From ebc233dc821fed0bcdfa55f869e5940eb4b5c5bb Mon Sep 17 00:00:00 2001 From: cdwensley Date: Mon, 20 Apr 2026 18:50:55 +0100 Subject: [PATCH 001/123] starting a PR of matrix examples --- doc/ref/matobj.xml | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 2818815902..834d44c3d3 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -21,6 +21,53 @@ cf. Chapters and . + +
+Some Elementary Examples +Just to give a flavour of these new objects, we construct here a vector +and a matrix in these new forms. +The elements should all belong to a semiring R +(the BaseDomain). +It is also necessary to specify their type, or filter. +The simplest of these use plain lists, namely +and . +Other available types are listed in Sections + and +. +

+To construct these objects we use the operations + and , although operations +Vector and Matrix are also available and are more flexible. +NewMatrix requires the number of columns as third input. +

+Basic arithmetic operations for vectors and matrices are available: +see Sections and +. +

+ dom := Integers;; +gap> filt1 := IsPlistVectorRep;; +gap> filt2 := IsPlistMatrixRep;; +gap> v1 := NewVector( filt1, dom, [3,4,7,8] ); + +gap> Print( v1 ); +NewVector(IsPlistVectorRep,Integers,[ 3, 4, 7, 8 ]) +gap> M := NewMatrix( filt2, dom, 4, [ [1,2,3,4], [6,7,8,9] ] );; +gap> Display( M ); +<2x4-matrix over Integers: +[[ 1, 2, 3, 4 ] + [ 6, 7, 8, 9 ] +]> +gap> v2 := NewVector( filt1, dom, [-7..-4] );; +gap> Print( v1 + v2 ); +NewVector(IsPlistVectorRep,Integers,[ -4, -2, 2, 4 ]) +gap> Print( (v1+v2) * TransposedMat(M) ); +NewVector(IsPlistVectorRep,Integers,[ 14, 14 ]) +]]> + +

+ +
Categories of Vector and Matrix Objects From a9fc8bc24b629f9c6e9c19f22663ec84f852e236 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 22 Apr 2026 12:37:35 +0100 Subject: [PATCH 002/123] Update doc/ref/matobj.xml Co-authored-by: Thomas Breuer --- doc/ref/matobj.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 834d44c3d3..219068cb5e 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -29,7 +29,7 @@ and a matrix in these new forms. The elements should all belong to a semiring R (the BaseDomain). It is also necessary to specify their type, or filter. -The simplest of these use plain lists, namely +The simplest of these use plain lists, namely and . Other available types are listed in Sections and From 8f97abc295ea943c19a4414bcee5451070d1c83e Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 22 Apr 2026 12:37:50 +0100 Subject: [PATCH 003/123] Update doc/ref/matobj.xml Co-authored-by: Thomas Breuer --- doc/ref/matobj.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 219068cb5e..cd418da620 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -30,7 +30,7 @@ The elements should all belong to a semiring R (the BaseDomain). It is also necessary to specify their type, or filter. The simplest of these use plain lists, namely -and . +and . Other available types are listed in Sections and . From dc94e93cb54e9181d5431e5f77f4b643035e3fe5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 09:16:30 +0200 Subject: [PATCH 004/123] build(deps): bump actions/upload-pages-artifact from 4 to 5 (#6336) Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-pages-artifact/releases) - [Commits](https://github.com/actions/upload-pages-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-pages-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/update-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index 0029894b91..e1ebb2c57b 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -67,7 +67,7 @@ jobs: mv doc/dev/bigpic.* public/doc/dev/ cp dev/index.html public/ - name: Upload artifact - uses: actions/upload-pages-artifact@v4 + uses: actions/upload-pages-artifact@v5 with: path: ./public From 7dff94aaeac42d5e005391e81c3b7a037f954545 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:42:07 +0000 Subject: [PATCH 005/123] build(deps): bump julia-actions/setup-julia from 2 to 3 (#6335) Bumps [julia-actions/setup-julia](https://github.com/julia-actions/setup-julia) from 2 to 3. - [Release notes](https://github.com/julia-actions/setup-julia/releases) - [Commits](https://github.com/julia-actions/setup-julia/compare/v2...v3) --- updated-dependencies: - dependency-name: julia-actions/setup-julia dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gapjl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gapjl.yml b/.github/workflows/gapjl.yml index f7ff5e2675..5e3a5ae291 100644 --- a/.github/workflows/gapjl.yml +++ b/.github/workflows/gapjl.yml @@ -48,7 +48,7 @@ jobs: with: path: 'GAPROOT' - name: "Set up Julia" - uses: julia-actions/setup-julia@v2 + uses: julia-actions/setup-julia@v3 with: version: ${{ matrix.julia-version }} - name: Install GAP.jl From e2485f9b0e2a6be5cff135f326384da3e9cbe42f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 20 Apr 2026 16:06:39 +0200 Subject: [PATCH 006/123] Improve CosetLeadersMatFFE documentation (#6338) Codex wrote most of this and I edited it. Co-authored-by: Codex --- lib/listcoef.gd | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/listcoef.gd b/lib/listcoef.gd index a97e54b8f6..c682bfd9f4 100644 --- a/lib/listcoef.gd +++ b/lib/listcoef.gd @@ -684,13 +684,30 @@ DeclareOperation("AClosestVectorCombinationsMatFFEVecFFECoords", ## ## ## -## returns a list of representatives of minimal weight for the cosets of a -## code. -## mat must be a check matrix for the code, -## the code is defined over the finite field f. -## All rows of mat must have the same length, and all elements must -## lie in the field f. -## The rows of mat must be linearly independent. +## Let C be the linear code over f with check matrix +## mat, that is, C is the right null space of mat: +## +## C = \{ v \mid mat \cdot v = 0 \}. +## +## For each syndrome s, the solutions of the non-homogeneous system +## mat * v = s form one coset of C. Equivalently, two vectors +## lie in the same coset if their difference lies in C, just as in +## group theory. +##

+## returns, for each coset of C, a +## vector of smallest Hamming weight in that coset. Such a vector is called +## a coset leader. +##

+## If L := CosetLeadersMatFFE( mat, f ) and +## q := Size( f ), then L[i] is the coset leader whose +## syndrome is the vector with number i-1; in other words, +## NumberFFVector( mat * L[i], q ) = i - 1 +## for all valid indices i. +##

+## Thus the list is indexed by syndromes, not by codewords. +##

+## All rows of mat must have the same length, all entries must lie in +## f, and the rows of mat must be linearly independent. ## ## ## <#/GAPDoc> From f7518bf69ccea48989ed92867d37298b5bf8820b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 20 Apr 2026 22:29:56 +0200 Subject: [PATCH 007/123] Allow 'shifting' ranges (#6334) So far adding an integer to a range produced a plain list. Add a kernel method to ensure this again produces a range, if possible. If not, fall back to the current behavior. AI-assisted with Codex for the kernel change and tests. Co-authored-by: Codex --- src/range.c | 51 ++++++++++++++++++++++++++++++++ tst/testinstall/kernel/range.tst | 48 ++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/range.c b/src/range.c index 3c80522a0b..7ae0c93305 100644 --- a/src/range.c +++ b/src/range.c @@ -56,6 +56,8 @@ #include "error.h" #include "gaputils.h" #include "io.h" +#include "integer.h" +#include "listoper.h" #include "lists.h" #include "modules.h" #include "opers.h" @@ -818,6 +820,45 @@ Obj Range3Check ( } +/**************************************************************************** +** +*F ShiftRange( , ) +** +** 'ShiftRange' preserves the range representation when shifting +** by the integer keeps both endpoints in the small integer range. +** Otherwise it falls back to the generic scalar/list implementation. +*/ +static Obj ShiftRange(Obj offset, Obj range) +{ + Obj low; + Obj high; + Obj shifted; + + low = SUM(offset, INTOBJ_INT(GET_LOW_RANGE(range))); + high = SUM(offset, GET_ELM_RANGE(range, GET_LEN_RANGE(range))); + if (!IS_INTOBJ(low) || !IS_INTOBJ(high)) { + return SumSclList(offset, range); + } + + shifted = NEW_RANGE(GET_LEN_RANGE(range), INT_INTOBJ(low), + GET_INC_RANGE(range)); + if (!IS_MUTABLE_OBJ(range)) { + MakeImmutableNoRecurse(shifted); + } + return shifted; +} + +static Obj SumIntRange(Obj opL, Obj opR) +{ + return ShiftRange(opL, opR); +} + +static Obj SumRangeInt(Obj opL, Obj opR) +{ + return ShiftRange(opR, opL); +} + + /**************************************************************************** ** *F * * * * * * * * * * * * * * GAP level functions * * * * * * * * * * * * * @@ -1178,6 +1219,16 @@ static Int InitKernel ( LtFuncs[ T_RANGE_SSORT ][ T_RANGE_NSORT ] = LtRange; LtFuncs[ T_RANGE_SSORT ][ T_RANGE_SSORT ] = LtRange; + SumFuncs[ T_INT ][ T_RANGE_NSORT ] = SumIntRange; + SumFuncs[ T_INT ][ T_RANGE_NSORT + IMMUTABLE ] = SumIntRange; + SumFuncs[ T_INT ][ T_RANGE_SSORT ] = SumIntRange; + SumFuncs[ T_INT ][ T_RANGE_SSORT + IMMUTABLE ] = SumIntRange; + + SumFuncs[ T_RANGE_NSORT ][ T_INT ] = SumRangeInt; + SumFuncs[ T_RANGE_NSORT + IMMUTABLE ][ T_INT ] = SumRangeInt; + SumFuncs[ T_RANGE_SSORT ][ T_INT ] = SumRangeInt; + SumFuncs[ T_RANGE_SSORT + IMMUTABLE ][ T_INT ] = SumRangeInt; + // install the list functions in the tables LenListFuncs [ T_RANGE_NSORT ] = LenRange; LenListFuncs [ T_RANGE_NSORT +IMMUTABLE ] = LenRange; diff --git a/tst/testinstall/kernel/range.tst b/tst/testinstall/kernel/range.tst index ce1b1b3a50..b713bfc4ed 100644 --- a/tst/testinstall/kernel/range.tst +++ b/tst/testinstall/kernel/range.tst @@ -12,6 +12,54 @@ gap> START_TEST("kernel/range.tst"); gap> TNAM_OBJ([1..10]{[]}); "empty plain list" +# +# SumRangeInt / SumIntRange +# +gap> r := 5 + [1..5]; +[ 6 .. 10 ] +gap> IsRangeRep(r); +true +gap> r := [1..5] + 5; +[ 6 .. 10 ] +gap> IsRangeRep(r); +true +gap> r := 5 + [1,3..9]; +[ 6, 8 .. 14 ] +gap> IsRangeRep(r); +true +gap> r := [1,3..9] + 5; +[ 6, 8 .. 14 ] +gap> IsRangeRep(r); +true +gap> r := 5 + [9,7..1]; +[ 14, 12 .. 6 ] +gap> IsRangeRep(r); +true +gap> r := [9,7..1] + 5; +[ 14, 12 .. 6 ] +gap> IsRangeRep(r); +true +gap> r := 1 + [INTOBJ_MAX-1..INTOBJ_MAX];; +gap> r = [INTOBJ_MAX, INTOBJ_MAX+1]; +true +gap> IsRangeRep(r); +false +gap> r := [INTOBJ_MAX-1..INTOBJ_MAX] + 1;; +gap> r = [INTOBJ_MAX, INTOBJ_MAX+1]; +true +gap> IsRangeRep(r); +false +gap> r := -1 + [-INTOBJ_MAX-1..-INTOBJ_MAX];; +gap> r = [-INTOBJ_MAX-2, -INTOBJ_MAX-1]; +true +gap> IsRangeRep(r); +false +gap> r := [-INTOBJ_MAX-1..-INTOBJ_MAX] + -1;; +gap> r = [-INTOBJ_MAX-2, -INTOBJ_MAX-1]; +true +gap> IsRangeRep(r); +false + # # UnbRange # From 0b3d102fa44c7598c8587fd8da780da4b0705b20 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 21 Apr 2026 00:41:23 +0200 Subject: [PATCH 008/123] Re-enable Codecov comments but delay PR notifications (#6332) Switch Codecov to manual notifications and send them once after the coverage-uploading test matrix finishes. This avoids noisy intermediate PR comments and temporary dropped-coverage reports while uploads are still in flight. Co-authored-by: Codex --- .codecov.yml | 6 ++++-- .github/workflows/CI.yml | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index a302704acc..32dc8a6220 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,3 +1,7 @@ +codecov: + notify: + manual_trigger: true # needed for codecov-notify CI step + coverage: precision: 2 round: down @@ -14,8 +18,6 @@ coverage: default: informational: true -comment: false - ignore: - "extern" - "hpcgap/extern" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 9a7626a9c1..ca0f05b997 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -280,6 +280,18 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} + codecov-notify: + name: Finalize Codecov notifications + runs-on: ubuntu-slim + needs: test + if: ${{ always() }} + + steps: + - name: "Send Codecov notifications" + uses: codecov/codecov-action@v6 + with: + token: ${{ secrets.CODECOV_TOKEN }} + run_command: send-notifications cross_compile: # The host should always be linux From f2e48061d1efbdde31e2820c0e802b5a87516619 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 22 Apr 2026 00:12:07 +0200 Subject: [PATCH 009/123] PlainListCopy for list not knowing they are small (#6333) --- src/lists.c | 3 ++- tst/testbugfix/2026-04-19-PlainListCopy.tst | 6 ++++++ tst/testinstall/list.tst | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 tst/testbugfix/2026-04-19-PlainListCopy.tst diff --git a/src/lists.c b/src/lists.c index bc1b4a7589..dc329b0966 100644 --- a/src/lists.c +++ b/src/lists.c @@ -1649,7 +1649,8 @@ Obj PLAIN_LIST_COPY(Obj list) Obj FuncPlainListCopy(Obj self, Obj list) { - RequireSmallList(SELF_NAME, list); + if (!IS_LIST(list)) + RequireArgument(SELF_NAME, list, "must be a list"); return PLAIN_LIST_COPY(list); } diff --git a/tst/testbugfix/2026-04-19-PlainListCopy.tst b/tst/testbugfix/2026-04-19-PlainListCopy.tst new file mode 100644 index 0000000000..9acb71775e --- /dev/null +++ b/tst/testbugfix/2026-04-19-PlainListCopy.tst @@ -0,0 +1,6 @@ +# Fix PlainListCopy for lists which are small but do not know it yet know they +# are in filter `IsSmallList`; this is e.g. needed for the semigroups test +# suite +gap> l:=RightTransversal(Group([ (1,2) ]),Group([ () ]));; +gap> PlainListCopy(l); +[ (), (1,2) ] diff --git a/tst/testinstall/list.tst b/tst/testinstall/list.tst index 65a8e0fcd7..f4742a9834 100644 --- a/tst/testinstall/list.tst +++ b/tst/testinstall/list.tst @@ -336,15 +336,15 @@ true gap> checkPlainListCopy(NewZeroVector(Is8BitVectorRep, GF(3), 10)); true gap> PlainListCopy(6); -Error, PlainListCopy: must be a small list (not the integer 6) +Error, PlainListCopy: must be a list (not the integer 6) gap> PlainListCopy((1,2,3)); -Error, PlainListCopy: must be a small list (not a permutation (small)) +Error, PlainListCopy: must be a list (not a permutation (small)) #@if IsHPCGAP gap> PlainListCopy(Group((1,2))); -Error, PlainListCopy: must be a small list (not an atomic component object) +Error, PlainListCopy: must be a list (not an atomic component object) #@else gap> PlainListCopy(Group((1,2))); -Error, PlainListCopy: must be a small list (not a component object) +Error, PlainListCopy: must be a list (not a component object) #@fi # Check TNUM behaviours From 155efe1f194a754894eb4ff604fc2aefc97c7800 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 22 Apr 2026 02:25:33 +0200 Subject: [PATCH 010/123] Faster {Copy,Extract}Sub{Matrix,Vector} for plist matrices/vectors (#6329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... by avoiding some method dispatch, providing optimized methods using `{...}` syntax, and turning ExtractSubVector, CopySubVector, ExtractSubMatrix, and CopySubMatrix into kernel ops. Then run some benchmarks via `benchmark/matobj/bench-submat.g` and the new `benchmark/matobj/bench-subvec.g`. Before: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 129 µs per iteration; 7749 iterations per second; (200 iterations) Testing ExtractSubMatrix: 720 µs per iteration; 1388 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 342 µs per iteration; 2921 iterations per second; (200 iterations) Testing CopySubMatrix: 1032 µs per iteration; 969 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 167 µs per iteration; 5999 iterations per second; (200 iterations) Testing ExtractSubMatrix: 3288 µs per iteration; 304 iterations per second; (92 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1992 µs per iteration; 502 iterations per second; (151 iterations) Testing CopySubMatrix: 2606 µs per iteration; 384 iterations per second; (116 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 393 µs per iteration; 2542 iterations per second; (200 iterations) Testing CopySubVector: 2324 µs per iteration; 430 iterations per second; (130 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 441 µs per iteration; 2266 iterations per second; (200 iterations) Testing CopySubVector: 2458 µs per iteration; 407 iterations per second; (123 iterations) After: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 136 µs per iteration; 7355 iterations per second; (200 iterations) Testing ExtractSubMatrix: 140 µs per iteration; 7135 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 301 µs per iteration; 3319 iterations per second; (200 iterations) Testing CopySubMatrix: 299 µs per iteration; 3347 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 154 µs per iteration; 6490 iterations per second; (200 iterations) Testing ExtractSubMatrix: 146 µs per iteration; 6854 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1895 µs per iteration; 528 iterations per second; (159 iterations) Testing CopySubMatrix: 1935 µs per iteration; 517 iterations per second; (156 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 428 µs per iteration; 2336 iterations per second; (200 iterations) Testing CopySubVector: 453 µs per iteration; 2209 iterations per second; (200 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 427 µs per iteration; 2344 iterations per second; (200 iterations) Testing CopySubVector: 460 µs per iteration; 2172 iterations per second; (200 iterations) So overall the Copy/Extract methods are now more or less on par with the code using `{...}` syntax. But actually this `ExtractSubMatrix` for a GF(2) rowlist is now *faster* than the optimized one for a compressed GF(2) matrix: +----------------------------------------------------------+ | Testing submatrix extraction for GF(2) compressed matrix | +----------------------------------------------------------+ Testing m{}{}: 1057 µs per iteration; 946 iterations per second; (200 iterations) Testing ExtractSubMatrix: 1618 µs per iteration; 618 iterations per second; (186 iterations) A substantial part of that is due to the the `ExtractSubMatrix` method for `IsGF2MatrixRep` calling `ConvertToMatrixRepNC(mm,2)`; after removing that, it went down from 1618 to 392 µs (which is still worse). --- AI assistance: Codex implemented the kernel plumbing, method cleanup, and test updates. It also created `benchmark/matobj/bench-subvec.g`. Co-authored-by: Codex --- benchmark/matobj/bench-submat.g | 41 ++++--- benchmark/matobj/bench-subvec.g | 81 ++++++++++++++ lib/matobj.gi | 31 +++--- lib/matobj2.gd | 17 +-- src/lists.c | 100 ++++++++++++++++++ tst/testinstall/MatrixObj/CopySubVector.tst | 3 +- .../MatrixObj/ExtractSubMatrix.tst | 13 +++ .../MatrixObj/ExtractSubvector.tst | 2 + 8 files changed, 247 insertions(+), 41 deletions(-) create mode 100644 benchmark/matobj/bench-subvec.g create mode 100644 tst/testinstall/MatrixObj/ExtractSubMatrix.tst diff --git a/benchmark/matobj/bench-submat.g b/benchmark/matobj/bench-submat.g index 0b10bf85b2..b5ee2697de 100644 --- a/benchmark/matobj/bench-submat.g +++ b/benchmark/matobj/bench-submat.g @@ -7,13 +7,15 @@ TestExtractingSubmatrix := function(m) rows := [2..NrRows(m)-2]; cols := [3..NrCols(m)-1]; - PrintHeadline("m{}{}"); - MyBench(function() - local u, x; - for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do - x:=m{rows}{cols}; - od; - end); + if not IsPlistMatrixRep(m) then + PrintHeadline("m{}{}"); + MyBench(function() + local u, x; + for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do + x:=m{rows}{cols}; + od; + end); + fi; PrintHeadline("ExtractSubMatrix"); MyBench(function() @@ -32,13 +34,15 @@ TestCopyingSubmatrix := function(m) rows := [2..NrRows(m)-2]; cols := [3..NrCols(m)-1]; - PrintHeadline("m{}{}:=n{}{}"); - MyBench(function() - local u; - for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do - x{rows}{cols}:=m{rows}{cols}; - od; - end); + if not IsPlistMatrixRep(m) then + PrintHeadline("m{}{}:=n{}{}"); + MyBench(function() + local u; + for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do + x{rows}{cols}:=m{rows}{cols}; + od; + end); + fi; PrintHeadline("CopySubMatrix"); MyBench(function() @@ -62,18 +66,21 @@ for dim in [10, 100] do PrintBoxed(Concatenation("Now testing in dimension ", String(dim))); m:=IdentityMat(dim);; - RunMatTest("integer matrix", m); + RunMatTest("integer matrix: list of lists", m); + + m:=IdentityMatrix(Integers, dim);; + RunMatTest("integer matrix: IsPlistMatrixRep", m); m:=IdentityMat(dim,GF(2));; RunMatTest("GF(2) rowlist", m); - m:=IdentityMat(dim,GF(2));; ConvertToMatrixRep(m);; + m:=IdentityMatrix(GF(2), dim);; RunMatTest("GF(2) compressed matrix", m); m:=IdentityMat(dim,GF(7));; RunMatTest("GF(7) rowlist", m); - m:=IdentityMat(dim,GF(7));; ConvertToMatrixRep(m);; + m:=IdentityMatrix(GF(8), dim);; RunMatTest("GF(7) compressed matrix", m); # TODO: also add cvec matrices diff --git a/benchmark/matobj/bench-subvec.g b/benchmark/matobj/bench-subvec.g new file mode 100644 index 0000000000..8e2ede2ea9 --- /dev/null +++ b/benchmark/matobj/bench-subvec.g @@ -0,0 +1,81 @@ +ReadGapRoot("benchmark/matobj/bench.g"); + + +TestExtractingSubvector := function(v) + local cols; + + cols := [3..Length(v)-1]; + + if not IsPlistVectorRep(v) then + PrintHeadline("v{}"); + MyBench(function() + local u, x; + for u in [1..QuoInt(100000, Length(v))] do + x := v{cols}; + od; + end); + fi; + + PrintHeadline("ExtractSubVector"); + MyBench(function() + local u, x; + for u in [1..QuoInt(100000, Length(v))] do + x := ExtractSubVector(v, cols); + od; + end); +end; + +TestCopyingSubvector := function(v) + local x, cols; + + x := ShallowCopy(v); + cols := [3..Length(v)-1]; + + if not IsPlistVectorRep(v) then + PrintHeadline("x{}:=v{}"); + MyBench(function() + local u; + for u in [1..QuoInt(100000, Length(v))] do + x{cols} := v{cols}; + od; + end); + fi; + + PrintHeadline("CopySubVector"); + MyBench(function() + local u; + for u in [1..QuoInt(100000, Length(v))] do + CopySubVector(v, x, cols, cols); + od; + end); +end; + +RunVecTest := function(desc, v) + Print("\n"); + PrintBoxed(Concatenation("Testing subvector extraction for ", desc)); + TestExtractingSubvector(v); + Print(TextAttr.2, "...now testing subvector copying...\n", TextAttr.reset); + TestCopyingSubvector(v); +end; + +for dim in [10, 100] do + PrintBoxed(Concatenation("Now testing in dimension ", String(dim))); + + v := [1..dim] * 0;; + RunVecTest("integer vector: plain list", v); + + v := Vector(IsPlistVectorRep, Integers, [1..dim]);; + RunVecTest("integer vector: IsPlistVectorRep", v); + + v := [1..dim] * One(GF(2));; + RunVecTest("GF(2) row vector", v); + + v := NewVector(IsGF2VectorRep, GF(2), [1..dim] * One(GF(2)));; + RunVecTest("GF(2) compressed vector", v); + + v := [1..dim] * One(GF(7));; + RunVecTest("GF(7) row vector", v); + + v := NewVector(Is8BitVectorRep, GF(7), [1..dim] * One(GF(7)));; + RunVecTest("GF(7) 8-bit vector", v); +od; diff --git a/lib/matobj.gi b/lib/matobj.gi index 652dddccad..35ae1ccbe0 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -749,9 +749,9 @@ InstallMethod( \{\}, return Vector( Unpack( v ){ poss }, v ); end ); -InstallMethod( ExtractSubVector, - "generic method for a vector object and a list", - [ IsVectorObj, IsList ], +InstallOtherMethod( ExtractSubVector, + "generic method for a row vector or vector object and a list", + [ IsRowVectorOrVectorObj, IsList ], { v, l } -> v{ l } ); InstallMethod( ExtractSubMatrix, @@ -759,20 +759,10 @@ InstallMethod( ExtractSubMatrix, [ IsMatrixObj, IsList, IsList ], { M, rowpos, colpos } -> Matrix( Unpack( M ){ rowpos }{ colpos }, M ) ); -# Hack from recog package -InstallOtherMethod( ExtractSubMatrix, "hack: for lists of compressed vectors", -[ IsList, IsList, IsList ], -function( m, poss1, poss2 ) - local i,n; - n := []; - for i in poss1 do - Add(n,ShallowCopy(m[i]{poss2})); - od; - if IsFFE(m[1,1]) then - ConvertToMatrixRep(n); - fi; - return n; -end ); +InstallOtherMethod( ExtractSubMatrix, + "generic method for a matrix and two lists", + [ IsMatrix, IsList, IsList ], + { M, rowpos, colpos } -> M{ rowpos }{ colpos } ); InstallMethod( CopySubVector, "generic method for row vectors and vector objects", @@ -788,6 +778,13 @@ InstallMethod( CopySubVector, od; end ); +InstallMethod( CopySubVector, + "generic method for row vectors", + [ IsRowVector, IsRowVector and IsMutable, IsList, IsList ], + function(src, dst, scols, dcols) + dst{dcols} := src{scols}; +end ); + ############################################################################# ## diff --git a/lib/matobj2.gd b/lib/matobj2.gd index c7cd9f0c4a..21f4af9a32 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -434,7 +434,8 @@ DeclareGlobalFunction( "ConcatenationOfVectors" ); ## ## <#/GAPDoc> ## -DeclareOperation( "ExtractSubVector", [ IsVectorObj, IsList ] ); +DeclareOperationKernel( "ExtractSubVector", + [ IsRowVectorOrVectorObj, IsList ], EXTRACT_SUB_VECTOR ); ############################################################################# @@ -896,9 +897,9 @@ DeclareOperation( "Randomize", [ IsRandomSource, IsMatrixOrMatrixObj and IsMutab ## ## <#/GAPDoc> ## -DeclareOperation( "CopySubVector", +DeclareOperationKernel( "CopySubVector", [ IsRowVectorOrVectorObj, IsRowVectorOrVectorObj and IsMutable, - IsList, IsList ] ); + IsList, IsList ], COPY_SUB_VECTOR ); ############################################################################# @@ -956,7 +957,8 @@ DeclareOperation( "DistanceOfVectors", [ IsVectorObj, IsVectorObj ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "ExtractSubMatrix", [ IsMatrixOrMatrixObj, IsList, IsList ] ); +DeclareOperationKernel( "ExtractSubMatrix", + [ IsMatrixOrMatrixObj, IsList, IsList ], EXTRACT_SUB_MATRIX ); ############################################################################# @@ -1005,8 +1007,11 @@ DeclareOperation( "MutableCopyMatrix", [ IsMatrixOrMatrixObj ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "CopySubMatrix", - [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj, IsList, IsList, IsList, IsList ] ); +DeclareOperationKernel( "CopySubMatrix", + [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj, IsList, IsList, IsList, IsList ], + COPY_SUB_MATRIX ); +#T We intentionally keep the second argument declaration broad, mirroring +#T the pre-existing operation declaration for compatibility with packages. ############################################################################# diff --git a/src/lists.c b/src/lists.c index dc329b0966..feb5c1584c 100644 --- a/src/lists.c +++ b/src/lists.c @@ -1611,6 +1611,99 @@ void AsssListLevel ( } +/**************************************************************************** +** +*F FuncEXTRACT_SUB_VECTOR( , , ) . . `EXTRACT_SUB_VECTOR' +*/ +static Obj ExtractSubVectorOper; + +static Obj FuncEXTRACT_SUB_VECTOR(Obj self, Obj vec, Obj poss) +{ + if (IS_PLIST(vec)) { + CheckIsPossList("List Elements", poss); + return ELMS_LIST(vec, poss); + } + + return DoOperation2Args(ExtractSubVectorOper, vec, poss); +} + + +/**************************************************************************** +** +*F FuncCOPY_SUB_VECTOR( , , , , ) +*/ +static Obj CopySubVectorOper; + +static Obj FuncCOPY_SUB_VECTOR( + Obj self, Obj src, Obj dst, Obj scols, Obj dcols) +{ + if (IS_PLIST(src) && IS_PLIST(dst)) { + Obj rhss; + + CheckIsPossList("List Assignments", scols); + CheckIsPossList("List Assignments", dcols); + rhss = ELMS_LIST(src, scols); + AsssListCheck(dst, dcols, rhss); + return 0; + } + + return DoOperation4Args(CopySubVectorOper, src, dst, scols, dcols); +} + + +/**************************************************************************** +** +*F FuncEXTRACT_SUB_MATRIX( , , , ) +*/ +static Obj ExtractSubMatrixOper; + +static Obj FuncEXTRACT_SUB_MATRIX(Obj self, Obj mat, Obj rows, Obj cols) +{ + if (IS_PLIST(mat)) { + Obj submat; + + CheckIsPossList("List Elements", rows); + CheckIsPossList("List Elements", cols); + submat = ELMS_LIST(mat, rows); + ElmsListLevel(submat, cols, 1); + return submat; + } + + return DoOperation3Args(ExtractSubMatrixOper, mat, rows, cols); +} + + +/**************************************************************************** +** +*F FuncCOPY_SUB_MATRIX( , , , , , , +*F ) +*/ +static Obj CopySubMatrixOper; + +static Obj FuncCOPY_SUB_MATRIX( + Obj self, Obj src, Obj dst, Obj srows, Obj drows, Obj scols, Obj dcols) +{ + if (IS_PLIST(src) && IS_PLIST(dst)) { + Obj srcsub; + Obj dstsub; + + CheckIsPossList("List Assignments", srows); + CheckIsPossList("List Assignments", drows); + CheckIsPossList("List Assignments", scols); + CheckIsPossList("List Assignments", dcols); + + srcsub = ELMS_LIST(src, srows); + ElmsListLevel(srcsub, scols, 1); + dstsub = ELMS_LIST(dst, drows); + AsssListLevel(dstsub, dcols, srcsub, 1); + return 0; + } + + return DoOperation6Args(CopySubMatrixOper, src, dst, srows, drows, scols, + dcols); +} + + /**************************************************************************** ** *F PLAIN_LIST() . . . . . . . . . . . convert a list to a plain list @@ -1953,6 +2046,13 @@ static StructGVarOper GVarOpers[] = { GVAR_OPER_4ARGS(ASS_MAT, mat, row, col, obj, &AssMatOper), GVAR_OPER_3ARGS(ELM_MAT, mat, row, col, &ElmMatOper), + GVAR_OPER_2ARGS(EXTRACT_SUB_VECTOR, vec, poss, &ExtractSubVectorOper), + GVAR_OPER_4ARGS(COPY_SUB_VECTOR, src, dst, scols, dcols, + &CopySubVectorOper), + GVAR_OPER_3ARGS(EXTRACT_SUB_MATRIX, mat, rows, cols, + &ExtractSubMatrixOper), + GVAR_OPER_6ARGS(COPY_SUB_MATRIX, src, dst, srows, drows, scols, dcols, + &CopySubMatrixOper), GVAR_OPER_3ARGS(SWAP_MAT_ROWS, mat, row1, row2, &SwapMatRows), GVAR_OPER_3ARGS(SWAP_MAT_COLS, mat, col1, col2, &SwapMatCols), diff --git a/tst/testinstall/MatrixObj/CopySubVector.tst b/tst/testinstall/MatrixObj/CopySubVector.tst index 5c702e6089..33cea42c90 100644 --- a/tst/testinstall/MatrixObj/CopySubVector.tst +++ b/tst/testinstall/MatrixObj/CopySubVector.tst @@ -79,7 +79,8 @@ gap> l4; # gap> CopySubVector( l1, l3, [1,2], [1] ); -Error, source and destination index lists must be of equal length +Error, List Assignments: must have the same length as (lengths a\ +re 2 and 1) # gap> STOP_TEST("CopySubVector.tst"); diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst new file mode 100644 index 0000000000..35517c5f25 --- /dev/null +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -0,0 +1,13 @@ +gap> START_TEST("ExtractSubMatrix.tst"); +gap> IsBoundGlobal("EXTRACT_SUB_MATRIX"); +true +gap> EXTRACT_SUB_MATRIX = ExtractSubMatrix; +true +gap> m1 := [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]; +[ [ 1, 2, 3 ], [ 4, 5, 6 ] ] +gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); +[ [ 6, 4 ], [ 3, 1 ] ] +gap> m2 := IdentityMatrix( Integers, 4 );; +gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); +[ [ 0, 1 ], [ 1, 0 ] ] +gap> STOP_TEST("ExtractSubMatrix.tst"); diff --git a/tst/testinstall/MatrixObj/ExtractSubvector.tst b/tst/testinstall/MatrixObj/ExtractSubvector.tst index 42af85ac22..81224516ab 100644 --- a/tst/testinstall/MatrixObj/ExtractSubvector.tst +++ b/tst/testinstall/MatrixObj/ExtractSubvector.tst @@ -1,6 +1,8 @@ gap> START_TEST("ExtractSubVector.tst"); gap> l1 := [1,2,3,4,5,6]; [ 1, 2, 3, 4, 5, 6 ] +gap> ExtractSubVector( l1, [1,2,4] ); +[ 1, 2, 4 ] gap> v3 := Vector(GF(5), l1*One(GF(5))); [ Z(5)^0, Z(5), Z(5)^3, Z(5)^2, 0*Z(5), Z(5)^0 ] gap> ExtractSubVector( v3, [1,2,4] ); From 5e7673dbc26597b1797eb7a2ed2ac1228076aab7 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 22 Apr 2026 16:33:35 +0100 Subject: [PATCH 011/123] not using New variants --- doc/ref/matobj.xml | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index cd418da620..c7d6857083 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -24,21 +24,13 @@ cf. Chapters and .

Some Elementary Examples -Just to give a flavour of these new objects, we construct here a vector +Just to give a flavour of these new objects, we construct here two vectors and a matrix in these new forms. The elements should all belong to a semiring R (the BaseDomain). -It is also necessary to specify their type, or filter. -The simplest of these use plain lists, namely -and . -Other available types are listed in Sections - and -. -

To construct these objects we use the operations - and , although operations -Vector and Matrix are also available and are more flexible. -NewMatrix requires the number of columns as third input. +Vector and Matrix which are described in Section +.

Basic arithmetic operations for vectors and matrices are available: see Sections and @@ -46,25 +38,34 @@ see Sections and

dom := Integers;; -gap> filt1 := IsPlistVectorRep;; -gap> filt2 := IsPlistMatrixRep;; -gap> v1 := NewVector( filt1, dom, [3,4,7,8] ); - +gap> v1 := Vector( dom, [3,4,7,8] );; gap> Print( v1 ); NewVector(IsPlistVectorRep,Integers,[ 3, 4, 7, 8 ]) -gap> M := NewMatrix( filt2, dom, 4, [ [1,2,3,4], [6,7,8,9] ] );; +gap> M := Matrix( dom, [ [1,2,3,4], [6,7,8,9] ] );; gap> Display( M ); <2x4-matrix over Integers: [[ 1, 2, 3, 4 ] [ 6, 7, 8, 9 ] ]> -gap> v2 := NewVector( filt1, dom, [-7..-4] );; +gap> v2 := Vector( [-7..-4], v1 ); + gap> Print( v1 + v2 ); NewVector(IsPlistVectorRep,Integers,[ -4, -2, 2, 4 ]) -gap> Print( (v1+v2) * TransposedMat(M) ); -NewVector(IsPlistVectorRep,Integers,[ 14, 14 ]) +gap> Display( (v1+v2) * TransposedMat(M) ); + ]]> +These objects need to know their type, or filter. +The simplest of these use plain lists, namely +and , +which &GAP; chooses automatically for v1 and M. +Note that v2 acquires its type by being defined relative to v1. +Other available types are listed in Sections + and +. +

From 91d94672208a5be0a5f7b19498a8be074f593f1a Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Thu, 23 Apr 2026 15:28:18 -0700 Subject: [PATCH 012/123] doc: fix IrreducibleModules description to say 'at most' dim (#6337) The GAPDoc description for IrreducibleModules claimed the second entry was 'a list of all irreducible modules of G over the field F in dimension dim'. The actual behaviour is to return all irreducible constituents of dimension at most dim, matching: Updated the description to match this, and also added a one-line note that passing 0 imposes no bound (already the implementation behavior, previously only discoverable by reading the code). Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Claude (Anthropic AI) --- lib/grpreps.gd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/grpreps.gd b/lib/grpreps.gd index 125cbbaf99..78433fcbf3 100644 --- a/lib/grpreps.gd +++ b/lib/grpreps.gd @@ -49,8 +49,10 @@ DeclareSynonym( "AbsolutelyIrreducibleModules", AbsolutIrreducibleModules ); ## ## returns a list of length 2. The first entry is a generating system of ## G. The second entry is a list of all irreducible modules of -## G over the field F in dimension dim, given as MeatAxe modules +## G over the field F of dimension at most dim, +## given as MeatAxe modules ## (see ). +## Pass 0 for dim to impose no dimension bound. ##
## ## <#/GAPDoc> From 89631b23bb45e270139f73e5531b4605ba37fe08 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 24 Apr 2026 16:36:36 +0200 Subject: [PATCH 013/123] Fix PartitionsGreatestLE for zero, improve docs (#6341) Return the empty partition from PartitionsGreatestLE(0, m) for every nonnegative m. Also clarify the documentation. Co-authored-by: Codex --- lib/combinat.gd | 22 ++++++++++++++++++++-- lib/combinat.gi | 12 ++++-------- tst/testinstall/combinat.tst | 22 ++++++++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/combinat.gd b/lib/combinat.gd index fb3ced6991..f89bbc550a 100644 --- a/lib/combinat.gd +++ b/lib/combinat.gd @@ -970,7 +970,7 @@ DeclareGlobalFunction("NrPartitions"); ############################################################################# ## -#F PartitionsGreatestLE( , ) . . . set of partitions of n parts <= n +#F PartitionsGreatestLE( , ) . . . partitions of n with parts <= m ## ## <#GAPDoc Label="PartitionsGreatestLE"> ## @@ -979,6 +979,16 @@ DeclareGlobalFunction("NrPartitions"); ## ## returns the set of all (unordered) partitions of the integer n ## having parts less or equal to the integer m. +## For n = 0 and m \geq 0, this returns the empty partition +## [[]]. +## Negative arguments yield the empty list. +## PartitionsGreatestLE( 6, 3 ); +## [ [ 1, 1, 1, 1, 1, 1 ], [ 2, 1, 1, 1, 1 ], [ 2, 2, 1, 1 ], [ 2, 2, 2 ], +## [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +## gap> List( [ 0 .. 3 ], m -> PartitionsGreatestLE( 0, m ) ); +## [ [ [ ] ], [ [ ] ], [ [ ] ], [ [ ] ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -988,7 +998,7 @@ DeclareGlobalFunction("PartitionsGreatestLE"); ############################################################################# ## -#F PartitionsGreatestEQ( , ) . . . . set of partitions of n parts = n +#F PartitionsGreatestEQ( , ) . . . . partitions of n with max part m ## ## <#GAPDoc Label="PartitionsGreatestEQ"> ## @@ -997,6 +1007,14 @@ DeclareGlobalFunction("PartitionsGreatestLE"); ## ## returns the set of all (unordered) partitions of the integer n ## having greatest part equal to the integer m. +## Since partitions use positive parts, this returns the empty list if +## n \leq 0 or m \leq 0. +## PartitionsGreatestEQ( 6, 3 ); +## [ [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +## gap> PartitionsGreatestEQ( 0, 1 ); +## [ ] +## ]]> ## ## ## <#/GAPDoc> diff --git a/lib/combinat.gi b/lib/combinat.gi index 4973b1a09d..672992d0d5 100644 --- a/lib/combinat.gi +++ b/lib/combinat.gi @@ -1887,7 +1887,7 @@ end); ############################################################################# ## -#F PartitionsGreatestLE( , ) . . . set of partitions of n parts <= m +#F PartitionsGreatestLE( , ) . . . partitions of n with parts <= m ## ## returns the set of all (unordered) partitions of the integer having ## parts less or equal to the integer . @@ -1984,11 +1984,8 @@ function(n,m) parts := []; else if n = 0 then - if m = 0 then - parts := [ [ ] ]; - else - parts := [ ]; - fi; + # The empty partition satisfies every nonnegative upper bound. + parts := [ [ ] ]; else if m = 0 then parts := [ ]; @@ -2003,7 +2000,7 @@ end); ############################################################################# ## -#F PartitionsGreatestEQ( , ) . . . . set of partitions of n parts = n +#F PartitionsGreatestEQ( , ) . . . . partitions of n with max part m ## ## returns the set of all (unordered) partitions of the integer having ## greatest part equal to the integer . @@ -2041,7 +2038,6 @@ BindGlobal( "GPartitionsGreatestEQ", function(n,m) # This works exactly as `GPartitionsGreatestLE' for n-m and m and # adds a part m to all partitions. This is however done effectively # during the work. - # This is the same as `Partitions(n,m)' in the GAP library. # n and m must be a natural numbers >= 1. local B,j,k,l,p,res; if m > n then return []; fi; # a special case diff --git a/tst/testinstall/combinat.tst b/tst/testinstall/combinat.tst index b34d4bbe92..f1bf71034f 100644 --- a/tst/testinstall/combinat.tst +++ b/tst/testinstall/combinat.tst @@ -388,6 +388,28 @@ gap> NrPartitions( 100 ); gap> NrPartitions( 100, 10 ); 2977866 +#F PartitionsGreatestLE( , ) . . . partitions with largest part <= m +gap> List( [0..3], m -> PartitionsGreatestLE( 0, m ) ); +[ [ [ ] ], [ [ ] ], [ [ ] ], [ [ ] ] ] +gap> Print(PartitionsGreatestLE( 6, 3 ),"\n"); +[ [ 1, 1, 1, 1, 1, 1 ], [ 2, 1, 1, 1, 1 ], [ 2, 2, 1, 1 ], [ 2, 2, 2 ], + [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +gap> Partitions( 6 ) = PartitionsGreatestLE( 6, 6 ); +true +gap> List( [1..4], k -> +> Difference( PartitionsGreatestLE( 6, k ), +> PartitionsGreatestLE( 6, k-1 ) ) +> = PartitionsGreatestEQ( 6, k ) ); +[ true, true, true, true ] +gap> Difference( PartitionsGreatestLE( 0, 1 ), +> PartitionsGreatestLE( 0, 0 ) ) +> = PartitionsGreatestEQ( 0, 1 ); +true +gap> Print(PartitionsGreatestEQ( 6, 3 ),"\n"); +[ [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +gap> PartitionsGreatestEQ( 0, 1 ); +[ ] + #F OrderedPartitions( ) . . . . set of ordered partitions of an integer gap> OrderedPartitions( 0 ); [ [ ] ] From d75e271c0a3226ba8278840c6ac9a9cd8eefec4a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 28 Apr 2026 13:44:47 +0200 Subject: [PATCH 014/123] Avoid some uses of IdGroup (#6343) --- grp/clasmax.grp | 2 +- grp/simple.gi | 18 +++++++++--------- lib/grpnames.gi | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/grp/clasmax.grp b/grp/clasmax.grp index 4d9daf2c2b..29ba01297a 100644 --- a/grp/clasmax.grp +++ b/grp/clasmax.grp @@ -25895,7 +25895,7 @@ local l,a,gf,conj,r,gp; (r^2=q and IsPrime(r) and r mod 10 in [3,7]) then # are the SL(2,5) in class S included ? (Depends on package status) - if not ForAny(l,x->Size(x)=120 and IdGroup(x)=[120,5]) then + if not ForAny(l,x->Size(x)=120 and IsPerfectGroup(x)) then # An A5, and its GL-conjugate gf:=GF(q); a:=Filtered(IrreducibleModules(TransitiveGroup(24,201),gf)[2], diff --git a/grp/simple.gi b/grp/simple.gi index c27d3078f4..c9a595c680 100644 --- a/grp/simple.gi +++ b/grp/simple.gi @@ -968,15 +968,15 @@ local nam,e,efactors,par,expo,prime,result,aut,i,classical,classaut,shortname, local s; if IsCyclic(gp) then return String(Size(gp)); - elif IdGroup(gp)=[4,2] then + elif Size(gp)=4 then return "2^2"; - elif IdGroup(gp)=[6,1] then + elif Size(gp)=6 then return "3.2"; - elif IdGroup(gp)=[8,3] then + elif Size(gp)=8 and IsDihedralGroup(gp) then return "2^2.2"; - elif IdGroup(gp)=[9,2] then + elif Size(gp)=9 then return "3^2"; - elif IdGroup(gp)=[18,3] then + elif Size(gp)=18 and Size(DerivedSubgroup(gp))=3 then return "3^2.2"; elif Size(gp)<=31 or Size(gp) in [33..47] then s:=StructureDescription(gp); @@ -1163,18 +1163,18 @@ local nam,e,efactors,par,expo,prime,result,aut,i,classical,classaut,shortname, if efactors<>fail and Size(classaut)<>Product(efactors) then Error("outer automorphism efactor fail"); fi; - if IdGroup(classaut)=[4,2] then + if Size(classaut)=4 and not IsCyclic(classaut) then # subgroup classes V4 e:=[[2,"2_1"],[2,"2_2"],[2,"2_3"],[4,"2^2"]]; - elif IdGroup(classaut)=[6,1] then + elif Size(classaut)=6 and not IsCyclic(classaut) then # subgroup classes S_3 e:=[ [ 2, "2" ], [ 3, "3" ], [ 6, "3.2" ] ]; - elif IdGroup(classaut)=[12,4] then + elif Size(classaut)=12 and IsDihedralGroup(classaut) then # subgroup classes 2\times S_3 (since S3 cannot act on C2) e:=[ [ 2, "2_1" ], [ 2, "2_2" ], [ 2, "2_3" ], [ 3, "3" ], [ 4, "2^2" ], [ 6, "3.2_1" ], [ 6, "3.2_2" ], [ 6, "6" ], [ 12, "3.2^2" ] ]; - elif IdGroup(classaut)=[24,12] then + elif Size(classaut)=24 and Size(DerivedSubgroup(classaut))=12 then # subgroup classes S_4 e:=[ [ 2, "2_1" ],[ 2, "2_2" ], [ 3, "3" ], [ 4, "4" ], [ 4, "(2^2)_{111}" ], [4,"(2^2)_{122}"], diff --git a/lib/grpnames.gi b/lib/grpnames.gi index 33d793ac5c..af9fdb5b01 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1208,7 +1208,7 @@ InstallMethod( IsAlternatingGroup, SetAlternatingDegree(G,0); return true; elif Size(G) = 3 then SetAlternatingDegree(G,3); return true; - elif Size(G) = 12 and IdGroup(G) = [ 12, 3 ] then + elif Size(G) = 12 and Size(DerivedSubgroup(G)) = 4 then SetAlternatingDegree(G,4); return true; else return false; fi; fi; From 549080bf753ccf8f00b07e3539613272d45ac7fb Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 24 Apr 2026 09:16:59 +0100 Subject: [PATCH 015/123] adding a few examples --- doc/ref/matobj.xml | 6 +++--- lib/matobj1.gd | 38 ++++++++++++++++++++++++++++---------- lib/matobj2.gd | 12 ++++++++++++ 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index c7d6857083..5f6d2a5e28 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -26,7 +26,7 @@ cf. Chapters and . Some Elementary Examples Just to give a flavour of these new objects, we construct here two vectors and a matrix in these new forms. -The elements should all belong to a semiring R +The elements should all belong to a semiring R (the BaseDomain). To construct these objects we use the operations Vector and Matrix which are described in Section @@ -60,8 +60,8 @@ gap> Display( (v1+v2) * TransposedMat(M) ); These objects need to know their type, or filter. The simplest of these use plain lists, namely and , -which &GAP; chooses automatically for v1 and M. -Note that v2 acquires its type by being defined relative to v1. +which &GAP; chooses automatically for v1 and M. +Note that v2 acquires its type by being defined relative to v1. Other available types are listed in Sections and . diff --git a/lib/matobj1.gd b/lib/matobj1.gd index ff53201b9c..f93b224566 100644 --- a/lib/matobj1.gd +++ b/lib/matobj1.gd @@ -110,16 +110,12 @@ DeclareCategory( "IsVectorObj", IsVector and IsVecOrMatObj and IsRowVectorOrVect ## argument. ##

## m:= IdentityMat( 2, GF(2) );; -## gap> IsMatrix( m ); IsMatrixObj( m ); IsMatrixOrMatrixObj( m ); -## true -## false -## true -## gap> m:= NewIdentityMatrix( IsPlistMatrixRep, GF(2), 2 );; -## gap> IsMatrix( m ); IsMatrixObj( m ); IsMatrixOrMatrixObj( m ); -## false -## true -## true +## m := [ [1,2,3,4], [6,7,8,9] ];; +## gap> [ IsMatrix( m ), IsMatrixObj( m ), IsMatrixOrMatrixObj( m ) ]; +## [ true, false, true ] +## m := Matrix( Integers, [ [1,2,3,4], [6,7,8,9] ] );; +## gap> [ IsMatrix( m ), IsMatrixObj( m ), IsMatrixOrMatrixObj( m ) ]; +## [ false, true, true ] ## ]]> ## ## @@ -256,6 +252,14 @@ DeclareCategory( "IsMatrixObj", IsMatrixOrMatrixObj ); ## Matrix objects in are not ## necessarily in , ## and then they need not obey the general rules for lists. +##

+## IsRowListMatrix( m ); +## true +## gap> Print( m[2] ); +## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) +## ]]> ## ## ## <#/GAPDoc> @@ -283,6 +287,12 @@ DeclareCategory( "IsRowListMatrix", IsMatrixObj ); ## its base domain with respect to ## , see Section ## . +##

+## BaseDomain( v ); +## Rationals +## ]]> ## ## ## <#/GAPDoc> @@ -317,6 +327,14 @@ DeclareAttribute( "BaseDomain", IsVecOrMatObj ); ## are synonyms of ## and ## , respectively. +##

+## NumberRows( m ); +## 2 +## gap> NrCols( m ); +## 4 +## ]]> ## ## ## <#/GAPDoc> diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 21f4af9a32..cb6b40918a 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -198,6 +198,11 @@ DeclareAttribute( "Length", IsVectorObj ); ## value of v or M implies then ## mutable versions of v or M can be created, ## otherwise all vector or matrix objects with this filter are immutable. +##

+## ConstructingFilter( v ); +## ## ## ## <#/GAPDoc> @@ -222,6 +227,13 @@ DeclareAttribute( "ConstructingFilter", IsVecOrMatObj ); ## value ## f are compatible in the sense that M can be multiplied with ## these vector objects, of fail if no such filter is known. +##

+## ConstructingFilter( m ); +## +## gap> CompatibleVectorFilter( m ); +## ## ## ## <#/GAPDoc> From 7247dc759594c38d32a1162f44e84ecf287ca7bb Mon Sep 17 00:00:00 2001 From: cdwensley Date: Sun, 26 Apr 2026 21:22:16 +0100 Subject: [PATCH 016/123] a few more examples --- doc/ref/matobj.xml | 13 +++++- lib/matobj2.gd | 106 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 92 insertions(+), 27 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 5f6d2a5e28..81a02e9ff6 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -36,6 +36,9 @@ Basic arithmetic operations for vectors and matrices are available: see Sections and .

+Note that if M2, like M had been defined over the integers +then attempting to have displayed its inverse would have thrown an error. +

dom := Integers;; gap> v1 := Vector( dom, [3,4,7,8] );; @@ -55,6 +58,12 @@ gap> Display( (v1+v2) * TransposedMat(M) ); +gap> M2 := Matrix( Rationals, [ [8,5], [7,4] ] );; +gap> Display( M2^(-1) ); +<2x2-matrix over Rationals: +[[ -4/3, 5/3 ] + [ 7/3, -8/3 ] +]> ]]> These objects need to know their type, or filter. @@ -103,13 +112,13 @@ More can be added as soon as there is need for them.

Constructing Vector and Matrix Objects -<#Include Label="NewVector"> <#Include Label="Vector"> <#Include Label="VectorObj_ZeroVector"> -<#Include Label="NewMatrix"> +<#Include Label="NewVector"> <#Include Label="MatObj_Matrix"> <#Include Label="MatObj_ZeroMatrix"> <#Include Label="MatObj_IdentityMatrix"> +<#Include Label="NewMatrix">
diff --git a/lib/matobj2.gd b/lib/matobj2.gd index cb6b40918a..eb38616f28 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -203,6 +203,7 @@ DeclareAttribute( "Length", IsVectorObj ); ## v := Vector( Rationals, [3,4,7,8] );; ## gap> ConstructingFilter( v ); ## +## ]]> ## ## ## <#/GAPDoc> @@ -565,27 +566,25 @@ DeclareOperation( "ScalarProduct", [ IsVectorObj, IsVectorObj ] ); ############################################################################# ## -#O ZeroVector( , , ) #O ZeroVector( , ) #O ZeroVector( , ) #O ZeroVector( , ) +#O ZeroVector( , , ) ## ## <#GAPDoc Label="VectorObj_ZeroVector"> ## ## ZeroVector -## ## ## ## +## ## ## a vector object ## -## For a filter filt, a semiring R and a nonnegative integer len, -## this operation returns a new vector object of length len over R -## in the representation filt containing only zeros. -##

-## If only R and len are given, -## then &GAP; guesses a suitable representation. +## For a semiring R and a nonnegative integer len, +## this operation returns a new vector object of length len +## over R in the representation filt containing only zeros. +## &GAP; guesses a suitable representation. ##

## For a vector object v and a nonnegative integer len, ## this operation returns a new vector object of length len @@ -597,6 +596,11 @@ DeclareOperation( "ScalarProduct", [ IsVectorObj, IsVectorObj ] ); ## value ## of M, provided that such a representation exists. ##

+## For a filter filt, a semiring R and a nonnegative integer +## len, this operation returns a new vector object of length +## len over R in the representation filt +## containing only zeros. +##

## If the ## value of the result implies then the result is ## mutable. @@ -604,33 +608,40 @@ DeclareOperation( "ScalarProduct", [ IsVectorObj, IsVectorObj ] ); ## Default methods for ## ## delegate to . +##

+## z1 := ZeroVector( Rationals, 4 );; Print( z1 ); +## NewVector(IsPlistVectorRep,Rationals,[ 0, 0, 0, 0 ]) +## gap> v5 := Vector( GF(5), [3,4]*Z(5) );; z5 := ZeroVector(3,v5);; Print(z5); +## [ 0*Z(5), 0*Z(5), 0*Z(5) ] +## gap> M6:=Matrix(Integers,[[1,3],[5,7]]);; z6:=ZeroVector(6,M6);; Print(z6); +## NewVector(IsPlistVectorRep,Integers,[ 0, 0, 0, 0, 0, 0 ]) +## gap> z8 := ZeroVector( IsZmodnZVectorRep, ZmodnZ(8), 4 );; Print( z8 ); +## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 0, 0, 0, 0 ]) +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); DeclareOperation( "ZeroVector", [ IsSemiring, IsInt ] ); DeclareOperation( "ZeroVector", [ IsInt, IsVecOrMatObj ] ); +DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); #DeclareOperation( "ZeroVector", [ IsInt, IsVectorObj ] ); #DeclareOperation( "ZeroVector", [ IsInt, IsMatrixOrMatrixObj ] ); ############################################################################# ## -#O Vector( , , ) -#O Vector( , , ) #O Vector( , ) #O Vector( , ) #O Vector( , ) #O Vector( , ) +#O Vector( , , ) +#O Vector( , , ) ## ## <#GAPDoc Label="Vector"> ## ## Vector -## -## ## ## ## +## +## ## ## a vector object ## -## If a filter filt is given as the first argument then -## a vector object is returned that has -## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the vector object -## v, respectively. -##

## If a semiring R is given as the first argument then ## a vector object is returned whose ## -## value is guessed from R, again with base domain R +## value is guessed from R, with base domain R ## and entries given by the last argument. ##

## In the remaining cases with two arguments, @@ -676,6 +684,13 @@ DeclareOperation( "ZeroVector", [ IsInt, IsVecOrMatObj ] ); ## In this situation, the result is a row vector that is equal to ## v1 and whose internal representation fits to that of v2. ##

+## If a filter filt is given as the first argument then +## a vector object is returned that has +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the vector object +## v, respectively. +##

## If the global option check is set to false then ## ## need not perform consistency checks. @@ -691,17 +706,39 @@ DeclareOperation( "ZeroVector", [ IsInt, IsVecOrMatObj ] ); ## Default methods for ## ## delegate to . +##

+## v1 := Vector( Integers, [3,4,7,8] );; Print( v1 ); +## NewVector(IsPlistVectorRep,Integers,[ 3, 4, 7, 8 ]) +## gap> v2 := Vector( Rationals, v1 );; Print( v2 ); +## NewVector(IsPlistVectorRep,Rationals,[ 3, 4, 7, 8 ]) +## gap> v3 := Vector( [ 11..13], v1) ;; Print( v3 ); +## NewVector(IsPlistVectorRep,Integers,[ 11, 12, 13 ]) +## gap> v0 := [6..9];; IsVector( v0 ); +## true +## gap> Print( Vector( v0, v1 ) ); +## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) +## gap> v4 := Vector( IsZmodnZVectorRep, ZmodnZ(8), [ 1, 4, 7 ] );; +## Print( v4 ); +## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 1, 4, 7 ]) +## gap> BaseDomain( v4 ); +## (Integers mod 8) +## gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); +## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 3, 4, 7, 8 ]) +## gap> v5[4]; +## ZmodnZObj( 0, 8 ) +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsList ] ); -DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsVectorObj ] ); DeclareOperation( "Vector", [ IsSemiring, IsList ] ); DeclareOperation( "Vector", [ IsSemiring, IsVectorObj ] ); DeclareOperation( "Vector", [ IsList, IsVectorObj ] ); DeclareOperation( "Vector", [ IsVectorObj, IsVectorObj ] ); DeclareOperation( "Vector", [ IsList ] ); +DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsList ] ); +DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsVectorObj ] ); ############################################################################# @@ -716,6 +753,10 @@ DeclareOperation( "Vector", [ IsList ] ); ## ## ## +## These two operations are constructors, and should only be used +## when or +## do not give the desired result. +##

## For a filter filt, a semiring R, and a list list ## of elements that belong to R, ## returns a vector object which has @@ -736,6 +777,15 @@ DeclareOperation( "Vector", [ IsList ] ); ##

## The returned object is mutable if and only if filt implies ## . +##

+## v := NewVector( IsGF2VectorRep, GF(2), [1,0,1,0,1]*Z(2) ); +## +## gap> Print(v); +## [ Z(2)^0, 0*Z(2), Z(2)^0, 0*Z(2), Z(2)^0 ] +## gap> NewZeroVector( IsZmodnZVectorRep, ZmodnZ(7), 5 ); +## +## ]]> ## ## ## <#/GAPDoc> @@ -760,6 +810,10 @@ DeclareTagBasedOperation( "NewZeroVector", ## ## ## +## These three operations are constructors, and should only be used +## when , or +## do not give the desired result. +##

## For a filter filt, a semiring R, ## a positive integer ncols, and a list list, ## returns a matrix object which has @@ -2105,6 +2159,7 @@ DeclareOperationKernel( "SwapMatrixColumns", [ IsMatrixOrMatrixObj and IsMutable ## representation. ## If both of the matrices are lists-of-lists, then the operation is delegated ## row by row to . +##

## mat1 := [ [ 1, 2 ], [ 3, 4 ] ]; ## [ [ 1, 2 ], [ 3, 4 ] ] @@ -2144,6 +2199,7 @@ DeclareOperation( "AddMatrix", [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMa ## In all of these, if the matrix mat is a lists-of-lists, then the ## operation is delegated row by row to and ## . +##

## mat1 := [ [ 1, 2 ], [ 3, 4 ] ]; ## [ [ 1, 2 ], [ 3, 4 ] ] From 75b618b24d22b2f77a07b73b7248da675f16329a Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 28 Apr 2026 16:28:42 +0100 Subject: [PATCH 017/123] reordering Vector, ZeroVector, NewVector --- doc/ref/matobj.xml | 14 +++--- lib/matobj1.gd | 108 ++++++++++++++++++++++----------------------- lib/matobj2.gd | 30 +++++++------ 3 files changed, 78 insertions(+), 74 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 81a02e9ff6..e8f5bbcedc 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -25,7 +25,7 @@ cf. Chapters and .

Some Elementary Examples Just to give a flavour of these new objects, we construct here two vectors -and a matrix in these new forms. +and matrices in these new forms. The elements should all belong to a semiring R (the BaseDomain). To construct these objects we use the operations @@ -36,7 +36,7 @@ Basic arithmetic operations for vectors and matrices are available: see Sections and .

-Note that if M2, like M had been defined over the integers +Note that if m2, like m2, had been defined over the integers then attempting to have displayed its inverse would have thrown an error.

dom := Integers;; gap> v1 := Vector( dom, [3,4,7,8] );; gap> Print( v1 ); NewVector(IsPlistVectorRep,Integers,[ 3, 4, 7, 8 ]) -gap> M := Matrix( dom, [ [1,2,3,4], [6,7,8,9] ] );; -gap> Display( M ); +gap> m1 := Matrix( dom, [ [1,2,3,4], [6,7,8,9] ] );; +gap> Display( m1 ); <2x4-matrix over Integers: [[ 1, 2, 3, 4 ] [ 6, 7, 8, 9 ] @@ -54,12 +54,12 @@ gap> v2 := Vector( [-7..-4], v1 ); gap> Print( v1 + v2 ); NewVector(IsPlistVectorRep,Integers,[ -4, -2, 2, 4 ]) -gap> Display( (v1+v2) * TransposedMat(M) ); +gap> Display( (v1+v2) * TransposedMat( m1 ) ); -gap> M2 := Matrix( Rationals, [ [8,5], [7,4] ] );; -gap> Display( M2^(-1) ); +gap> m2 := Matrix( Rationals, [ [8,5], [7,4] ] );; +gap> Display( m2^(-1) ); <2x2-matrix over Rationals: [[ -4/3, 5/3 ] [ 7/3, -8/3 ] diff --git a/lib/matobj1.gd b/lib/matobj1.gd index f93b224566..c19130890f 100644 --- a/lib/matobj1.gd +++ b/lib/matobj1.gd @@ -110,11 +110,11 @@ DeclareCategory( "IsVectorObj", IsVector and IsVecOrMatObj and IsRowVectorOrVect ## argument. ##

## m := [ [1,2,3,4], [6,7,8,9] ];; ## gap> [ IsMatrix( m ), IsMatrixObj( m ), IsMatrixOrMatrixObj( m ) ]; ## [ true, false, true ] -## m := Matrix( Integers, [ [1,2,3,4], [6,7,8,9] ] );; -## gap> [ IsMatrix( m ), IsMatrixObj( m ), IsMatrixOrMatrixObj( m ) ]; +## gap> m1 := Matrix( Integers, [ [1,2,3,4], [6,7,8,9] ] );; +## gap> [ IsMatrix( m1 ), IsMatrixObj( m1 ), IsMatrixOrMatrixObj( m1 ) ]; ## [ false, true, true ] ## ]]> ## @@ -242,7 +242,7 @@ DeclareCategory( "IsMatrixObj", IsMatrixOrMatrixObj ); ## the i-th row of M, ## for 1 \leq i \leq NumberRows( M ). ##

-## All rows are objects in the same +## All rows are objects in the compatible ## representation. ## Several rows of a row list matrix object can be identical objects, ## and different row list matrices may share rows. @@ -254,10 +254,10 @@ DeclareCategory( "IsMatrixObj", IsMatrixOrMatrixObj ); ## and then they need not obey the general rules for lists. ##

## IsRowListMatrix( m ); +## gap> m1 := Matrix( Integers, [ [1,2,3,4], [6,7,8,9] ] );; +## gap> IsRowListMatrix( m1 ); ## true -## gap> Print( m[2] ); +## gap> Print( m1[2] ); ## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) ## ]]> ## @@ -289,7 +289,7 @@ DeclareCategory( "IsRowListMatrix", IsMatrixObj ); ## . ##

## v := Vector( Rationals, [ 3, 4, 7, 8 ] );; ## gap> BaseDomain( v ); ## Rationals ## ]]> @@ -302,52 +302,6 @@ DeclareAttribute( "BaseDomain", IsVecOrMatObj ); #DeclareAttribute( "BaseDomain", IsMatrixOrMatrixObj ); -############################################################################# -## -#A NumberRows( ) -#A NrRows( ) -#A NumberColumns( ) -#A NrCols( ) -## -## <#GAPDoc Label="NumberRowsNumberColumns"> -## -## NumberRows and NumberColumns -## -## -## -## -## -## -## For a matrix object M, -## and -## store the -## number of rows and columns of M, respectively. -##

-## and -## are synonyms of -## and -## , respectively. -##

-## NumberRows( m ); -## 2 -## gap> NrCols( m ); -## 4 -## ]]> -## -## -## <#/GAPDoc> -## -DeclareAttributeKernel( "NumberRows", IsMatrixOrMatrixObj, NUMBER_ROWS ); -DeclareSynonymAttr( "NrRows", NumberRows ); -InstallTrueMethod( HasNumberRows, IsMatrixOrMatrixObj and IsPlistRep); - -DeclareAttributeKernel( "NumberColumns", IsMatrixOrMatrixObj, NUMBER_COLUMNS ); -DeclareSynonymAttr( "NrCols", NumberColumns ); -InstallTrueMethod( HasNumberColumns, IsMatrixOrMatrixObj and IsPlistRep ); - - ############################################################################# ## #A OneOfBaseDomain( ) @@ -392,6 +346,52 @@ DeclareAttribute( "ZeroOfBaseDomain", IsVecOrMatObj ); #DeclareAttribute( "ZeroOfBaseDomain", IsMatrixOrMatrixObj ); +############################################################################# +## +#A NumberRows( ) +#A NrRows( ) +#A NumberColumns( ) +#A NrCols( ) +## +## <#GAPDoc Label="NumberRowsNumberColumns"> +## +## NumberRows and NumberColumns +## +## +## +## +## +## +## For a matrix object M, +## and +## store the +## number of rows and columns of M, respectively. +##

+## and +## are synonyms of +## and +## , respectively. +##

+## m1 := Matrix( Integers, [ [1,2,3,4], [6,7,8,9] ] );; +## gap> NumberRows( m1 ); +## 2 +## gap> NrCols( m1 ); +## 4 +## ]]> +## +## +## <#/GAPDoc> +## +DeclareAttributeKernel( "NumberRows", IsMatrixOrMatrixObj, NUMBER_ROWS ); +DeclareSynonymAttr( "NrRows", NumberRows ); +InstallTrueMethod( HasNumberRows, IsMatrixOrMatrixObj and IsPlistRep); + +DeclareAttributeKernel( "NumberColumns", IsMatrixOrMatrixObj, NUMBER_COLUMNS ); +DeclareSynonymAttr( "NrCols", NumberColumns ); +InstallTrueMethod( HasNumberColumns, IsMatrixOrMatrixObj and IsPlistRep ); + + ############################################################################# ## #V ConstructingFiltersForMatrixGroupElements diff --git a/lib/matobj2.gd b/lib/matobj2.gd index eb38616f28..4440bb4693 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -200,7 +200,7 @@ DeclareAttribute( "Length", IsVectorObj ); ## otherwise all vector or matrix objects with this filter are immutable. ##

## v := Vector( Rationals, [3,4,7,8] );; ## gap> ConstructingFilter( v ); ## ## ]]> @@ -230,11 +230,12 @@ DeclareAttribute( "ConstructingFilter", IsVecOrMatObj ); ## these vector objects, of fail if no such filter is known. ##

## ConstructingFilter( m ); +## gap> m1 := Matrix( Integers, [ [1,2,3,4], [6,7,8,9] ] );; +## gap> ConstructingFilter( m1 ); ## -## gap> CompatibleVectorFilter( m ); +## gap> CompatibleVectorFilter( m1 ); ## +## ]]> ## ## ## <#/GAPDoc> @@ -718,13 +719,13 @@ DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); ## true ## gap> Print( Vector( v0, v1 ) ); ## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) -## gap> v4 := Vector( IsZmodnZVectorRep, ZmodnZ(8), [ 1, 4, 7 ] );; -## Print( v4 ); -## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 1, 4, 7 ]) -## gap> BaseDomain( v4 ); -## (Integers mod 8) -## gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); +## gap> v4 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; +## gap> Print( v4 ); +## [ 0*Z(2), Z(2)^0, 0*Z(2) ] +##. gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); ## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 3, 4, 7, 8 ]) +## gap> BaseDomain( v5 ); +## (Integers mod 8) ## gap> v5[4]; ## ZmodnZObj( 0, 8 ) ## ]]> @@ -754,7 +755,8 @@ DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsVectorObj ] ); ## ## ## These two operations are constructors, and should only be used -## when or +## when or +## ## do not give the desired result. ##

## For a filter filt, a semiring R, and a list list @@ -811,8 +813,10 @@ DeclareTagBasedOperation( "NewZeroVector", ## ## ## These three operations are constructors, and should only be used -## when , or -## do not give the desired result. +## when , +## or +## +## do not give the desired result. ##

## For a filter filt, a semiring R, ## a positive integer ncols, and a list list, From 318b1a16401866511644eca20e5ec9f78e344e0c Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 28 Apr 2026 16:39:09 +0100 Subject: [PATCH 018/123] reordering Vector, ZeroVector, NewVector --- lib/matobj2.gd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 4440bb4693..51168efc77 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -717,12 +717,12 @@ DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); ## NewVector(IsPlistVectorRep,Integers,[ 11, 12, 13 ]) ## gap> v0 := [6..9];; IsVector( v0 ); ## true -## gap> Print( Vector( v0, v1 ) ); +## gap> Print( Vector( v0, v1 ) ); ## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) ## gap> v4 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; ## gap> Print( v4 ); ## [ 0*Z(2), Z(2)^0, 0*Z(2) ] -##. gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); +##. gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); ## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 3, 4, 7, 8 ]) ## gap> BaseDomain( v5 ); ## (Integers mod 8) @@ -757,7 +757,7 @@ DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsVectorObj ] ); ## These two operations are constructors, and should only be used ## when or ## -## do not give the desired result. +## do not give the desired result. ##

## For a filter filt, a semiring R, and a list list ## of elements that belong to R, @@ -814,9 +814,9 @@ DeclareTagBasedOperation( "NewZeroVector", ## ## These three operations are constructors, and should only be used ## when , -## or +## or ## -## do not give the desired result. +## do not give the desired result. ##

## For a filter filt, a semiring R, ## a positive integer ncols, and a list list, From 797154753e81971f9c7e9286e6eb1236a262e999 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 28 Apr 2026 19:01:25 +0100 Subject: [PATCH 019/123] reordering Vector, ZeroVector, NewVector --- lib/matobj2.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 51168efc77..234591062f 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -722,7 +722,7 @@ DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); ## gap> v4 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; ## gap> Print( v4 ); ## [ 0*Z(2), Z(2)^0, 0*Z(2) ] -##. gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); +## gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); ## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 3, 4, 7, 8 ]) ## gap> BaseDomain( v5 ); ## (Integers mod 8) From 4bec05ff4cc1418a5abcfa820bec73234dfc955e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 30 Apr 2026 23:13:19 +0200 Subject: [PATCH 020/123] Refine SetSize and remove some immediate methods (#6347) The removed methods mostly were already obsolete due to the custom SetSize. Only the "non emptiness" was not recorded right, which the new code in `SetSize` now handles. --- lib/coll.gi | 42 +++++++++++++++++++--------------------- lib/modfree.gi | 13 ------------- tst/testinstall/coll.tst | 13 ++++++------- 3 files changed, 26 insertions(+), 42 deletions(-) diff --git a/lib/coll.gi b/lib/coll.gi index 6736ccf5a8..7a53bdbb12 100644 --- a/lib/coll.gi +++ b/lib/coll.gi @@ -92,10 +92,6 @@ InstallMethod( PrintObj, ## #M IsEmpty() . . . . . . . . . . . . . . . test if a collection is empty ## -InstallImmediateMethod( IsEmpty, - IsCollection and HasSize, 0, - C -> Size( C ) = 0 ); - InstallMethod( IsEmpty, "for a collection", [ IsCollection ], @@ -111,10 +107,6 @@ InstallMethod( IsEmpty, ## #M IsTrivial() . . . . . . . . . . . . . test if a collection is trivial ## -InstallImmediateMethod( IsTrivial, - IsCollection and HasSize, 0, - C -> Size( C ) = 1 ); - InstallMethod( IsTrivial, "for a collection", [ IsCollection ], @@ -143,10 +135,6 @@ InstallMethod( IsNonTrivial, ## #M IsFinite() . . . . . . . . . . . . . . test if a collection is finite ## -InstallImmediateMethod( IsFinite, - IsCollection and HasSize, 0, - C -> not IsIdenticalObj( Size( C ), infinity ) ); - InstallMethod( IsFinite, "for a collection", [ IsCollection ], @@ -2879,17 +2867,27 @@ local filt; fi; # some sanity checks - Assert(0, not HasIsEmpty(obj) or (IsEmpty(obj) = (sz=0))); - Assert(0, not HasIsNonTrivial(obj) or (IsNonTrivial(obj) = (sz<>1))); - Assert(0, not HasIsTrivial(obj) or (IsTrivial(obj) = (sz=1))); - Assert(0, not HasIsFinite(obj) or (IsFinite(obj) = (sz<>infinity))); - - if sz=0 then filt:=IsEmpty; - elif sz=1 then filt:=IsTrivial; - elif sz=infinity then filt:=IsNonTrivial and HasIsFinite; - else filt:=IsNonTrivial and IsFinite; + Assert(1, not HasIsEmpty(obj) or (IsEmpty(obj) = (sz=0))); + Assert(1, not HasIsNonTrivial(obj) or (IsNonTrivial(obj) = (sz<>1))); + Assert(1, not HasIsTrivial(obj) or (IsTrivial(obj) = (sz=1))); + Assert(1, not HasIsFinite(obj) or (IsFinite(obj) = (sz<>infinity))); + + filt:=HasSize; + if sz=0 then + filt:=filt and IsEmpty; + else + filt:=filt and HasIsEmpty; + fi; + if sz=1 then + filt:=filt and IsTrivial; + else + filt:=filt and IsNonTrivial; + fi; + if sz=infinity then + filt:=filt and HasIsFinite; + else + filt:=filt and IsFinite; fi; - filt:=filt and HasSize; obj!.Size:=sz; SetFilterObj(obj,filt); end); diff --git a/lib/modfree.gi b/lib/modfree.gi index c88e380f42..86252154e8 100644 --- a/lib/modfree.gi +++ b/lib/modfree.gi @@ -104,16 +104,6 @@ InstallMethod( \in, ## ring is needed since all generator dependent questions are handled in the ## `IsTrivial' call.) ## -InstallImmediateMethod( IsFinite, - IsFreeLeftModule and HasIsFiniteDimensional, 0, - function( V ) - if not IsFiniteDimensional( V ) then - return false; - else - TryNextMethod(); - fi; - end ); - InstallMethod( IsFinite, "for a free left module", [ IsFreeLeftModule ], @@ -136,9 +126,6 @@ InstallMethod( IsFinite, ## #M IsTrivial( ) ## -InstallImmediateMethod( IsTrivial, IsFreeLeftModule and HasDimension, 0, - V -> Dimension( V ) = 0 ); - InstallMethod( IsTrivial, "for a free left module", [ IsFreeLeftModule ], diff --git a/tst/testinstall/coll.tst b/tst/testinstall/coll.tst index 88b68bdd7a..cc30a2ba9f 100644 --- a/tst/testinstall/coll.tst +++ b/tst/testinstall/coll.tst @@ -46,13 +46,12 @@ gap> List(props, p -> p(M0)); gap> N1:=Magma([[[1,0],[0,0]]]);; gap> ForAll(props, prop -> not Tester(prop)(N1)); true - -#gap> Size(N1); -#1 -#gap> ForAll(props, prop -> Tester(prop)(N1)); -#true -#gap> List(props, p -> p(N1)); -#[ false, true, false, true ] +gap> Size(N1); +1 +gap> ForAll(props, prop -> Tester(prop)(N1)); +true +gap> List(props, p -> p(N1)); +[ false, true, false, true ] # ... immediate methods for a collection which knows its size, # applied to collection with size greater than 1 From ae0135dbb12d4fa7a8aa34662350e87f9672f077 Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Mon, 4 May 2026 05:43:08 +0800 Subject: [PATCH 021/123] Fix HexSHA256 to always return 64 hex digits (#6358) When the SHA256 digest's leading byte(s) were zero, HexStringInt dropped those leading zero hex digits, so HexSHA256 returned a string shorter than 64 characters. Left-pad the result to 64 hex digits, since a SHA256 digest is always 256 bits. --- lib/files.gi | 8 +++++++- tst/testinstall/sha256.tst | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/files.gi b/lib/files.gi index f9c3dfd1f8..d710bc4d81 100644 --- a/lib/files.gi +++ b/lib/files.gi @@ -412,5 +412,11 @@ function(str) GAP_SHA256_UPDATE(s, str); res := GAP_SHA256_FINAL(s); res := Sum([0..7], i -> res[8-i]*2^(32*i));; - return LowercaseString(HexStringInt(res)); + res := LowercaseString(HexStringInt(res)); + # HexStringInt drops leading zero digits, but a SHA256 digest is always + # 256 bits = 64 hex digits, so left-pad with '0' if the top byte(s) were 0. + if Length(res) < 64 then + res := Concatenation(ListWithIdenticalEntries(64 - Length(res), '0'), res); + fi; + return res; end); diff --git a/tst/testinstall/sha256.tst b/tst/testinstall/sha256.tst index 3d0fcc1d0c..7f6988cb3a 100644 --- a/tst/testinstall/sha256.tst +++ b/tst/testinstall/sha256.tst @@ -32,6 +32,17 @@ gap> HexSHA256("abcd\r\n"); gap> HexSHA256(""); "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" +# Inputs whose SHA256 starts with one or more zero hex digits: the result +# must still be 64 hex characters (the digest is always 256 bits). +gap> HexSHA256("39"); +"0b918943df0962bc7a1824c0555a389347b4febdc7cf9d1254406d80ce44e3f9" +gap> HexSHA256("286"); +"00328ce57bbc14b33bd6695bc8eb32cdf2fb5f3a7d89ec14a42825e15d39df60" +gap> HexSHA256("886"); +"000f21ac06aceb9cdd0575e82d0d85fc39bed0a7a1d71970ba1641666a44f530" +gap> ForAll(["", "abcd", "39", "286", "886"], s -> Length(HexSHA256(s)) = 64); +true + # gap> HexSHA256(InputTextString("abcd")); "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589" From 361fc32fe0ef54c88e43db8e9c1e447232e10537 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 30 Apr 2026 15:04:45 +0100 Subject: [PATCH 022/123] examples for Matrix --- lib/matobj2.gd | 121 +++++++++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 44 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 234591062f..ea427ce20e 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -615,7 +615,7 @@ DeclareOperation( "ScalarProduct", [ IsVectorObj, IsVectorObj ] ); ## NewVector(IsPlistVectorRep,Rationals,[ 0, 0, 0, 0 ]) ## gap> v5 := Vector( GF(5), [3,4]*Z(5) );; z5 := ZeroVector(3,v5);; Print(z5); ## [ 0*Z(5), 0*Z(5), 0*Z(5) ] -## gap> M6:=Matrix(Integers,[[1,3],[5,7]]);; z6:=ZeroVector(6,M6);; Print(z6); +## gap> m6:=Matrix(Integers,[[1,3],[5,7]]);; z6:=ZeroVector(6,m6);; Print(z6); ## NewVector(IsPlistVectorRep,Integers,[ 0, 0, 0, 0, 0, 0 ]) ## gap> z8 := ZeroVector( IsZmodnZVectorRep, ZmodnZ(8), 4 );; Print( z8 ); ## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 0, 0, 0, 0 ]) @@ -674,17 +674,17 @@ DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); ## are taken for the ## result. ##

-## If only a list list is given then both the -## and the -## are guessed from -## this list. -##

## The variant Vector( v1, v2 ) ## is supported also for the case that v2 is a row vector but not ## a vector object. ## In this situation, the result is a row vector that is equal to ## v1 and whose internal representation fits to that of v2. ##

+## If only a list list is given then both the +## and the +## are guessed from +## this list. +##

## If a filter filt is given as the first argument then ## a vector object is returned that has ## @@ -719,15 +719,17 @@ DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); ## true ## gap> Print( Vector( v0, v1 ) ); ## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) -## gap> v4 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; -## gap> Print( v4 ); +## gap> v4 := Vector( [ 2, 5/2, 7/3, 3 ] );; Print( v4 ); +## NewVector(IsPlistVectorRep,Rationals,[ 2, 5/2, 7/3, 3 ]) +## gap> v5 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; +## gap> Print( v5 ); ## [ 0*Z(2), Z(2)^0, 0*Z(2) ] -## gap> v5 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 );; Print( v5 ); -## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 3, 4, 7, 8 ]) -## gap> BaseDomain( v5 ); +## gap> v6 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 ); +## +## gap> BaseDomain( v6 ); ## (Integers mod 8) -## gap> v5[4]; -## ZmodnZObj( 0, 8 ) +## gap> v7 := Vector( IsZmodnZVectorRep, ZmodnZ(12), v0 ); +## ## ]]> ## ## @@ -1317,63 +1319,56 @@ DeclareOperation( "CompanionMatrix", ############################################################################# ## -#O Matrix( , , , ) -#O Matrix( , , ) -#O Matrix( , , ) -#O Matrix( , , ) #O Matrix( , ) +#O Matrix( , , ) #O Matrix( , ) -#O Matrix( , , ) #O Matrix( , ) +#O Matrix( , , ) #O Matrix( , ) -#O Matrix( , ) #O Matrix( ) +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , , , ) +#O Matrix( , , ) ## ## <#GAPDoc Label="MatObj_Matrix"> ## ## Matrix -## -## -## -## ## +## ## -## ## +## ## -## ## +## +## +## +## ## ## a matrix object ## -## If a filter filt is given as the first argument then -## a matrix object is returned that has +## If a semiring R is given as the first argument then +## a matrix object is returned whose ## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the matrix object -## M, respectively. +## value is guessed from R, with base domain R +## and entries given by the argument list. ## Here list can be either a list of plain lists that describe the ## entries of the rows, or a flat list of the entries in row major order, ## where ncols defines the number of columns. ##

-## If a semiring R is given as the first argument then -## a matrix object is returned whose -## -## value is guessed from R, again with base domain R -## and entries given by the last argument. -##

-## In those remaining cases where the last argument is a matrix object, +## In those cases where the last argument is a matrix object, ## the first argument is a list or a matrix object ## that defines (together with ncols if applicable) the entries of ## the result, and the @@ -1381,12 +1376,19 @@ DeclareOperation( "CompanionMatrix", ## of the last argument ## are taken for the result. ##

-## Finally, if only a list list and perhaps ncols is given +## If only a list list and perhaps ncols is given ## then both the ## and the ## are guessed from ## the list. ##

+## In the remaining cases a filter filt is given as the +## first argument and a matrix object is returned that has +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the matrix object +## M, respectively. +##

## If the global option check is set to false then ## ## need not perform consistency checks. @@ -1404,6 +1406,37 @@ DeclareOperation( "CompanionMatrix", ## Default methods for ## ## delegate to . +## m1 := Matrix( Integers, [ [3,4,5], [6,7,8] ] );; Print( m1 ); +## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ 3, 4, 5 ], [ 6, 7, 8 ] ]) +## gap> m2 := Matrix( Rationals, [10..30], 7 );; Display( m2 ); +## <3x7-matrix over Rationals: +## [[ 10 .. 16 ] +## [ 17 .. 23 ] +## [ 24 .. 30 ] +## ]> +gap> Print( Matrix( Integers, m2 ) ); +NewMatrix(IsPlistMatrixRep,Integers,7, +[ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) +gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); +NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) +gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); +NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) +gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); +true +gap> Print( Matrix( m0, m1 ) ); +NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) +gap> Print( Matrix( [-9..-4], 3, m1 ) ); +NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) +gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); +NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) +gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +gap> Display( m6 ); + 1 . 1 + . 1 . +gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); + +## ]]> ## ## ## <#/GAPDoc> From ba798f833e132025332fe8c569e612cf676d7b4d Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 1 May 2026 08:54:58 +0100 Subject: [PATCH 023/123] examples for Matrix --- lib/matobj2.gd | 79 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index ea427ce20e..c7fb9ef3ac 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -857,6 +857,11 @@ DeclareTagBasedOperation( "NewZeroVector", ##

## The returned object is mutable if and only if filt implies ## . +##

+## Matrix( IsPlistMatrixRep, Integers, [ [4,5,6], [7,8,9] ] ); +## <2x3-matrix over Integers> +## ]]> ## ## ## <#/GAPDoc> @@ -1198,6 +1203,20 @@ DeclareSynonym( "SetMatElm", ASS_MAT ); ## Default methods for ## ## delegate to . +##

+## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; +## gap> z7 := ZeroMatrix( 2, 2, m7 );; Print( z7 ); +## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, +## [ [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ], +## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ] ]) +## gap> z23 := ZeroMatrix( Rationals, 2, 3 );; Print( z23 ); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 0, 0 ], [ 0, 0, 0 ] ]) +## gap> z5 := ZeroMatrix( IsGF2MatrixRep, GF(2), 2, 5 );; Display( z5 ); +## . . . . . +## . . . . . +## ]> +## ]]> ## ## ## <#/GAPDoc> @@ -1245,6 +1264,21 @@ DeclareOperation( "ZeroMatrix", [ IsOperation, IsSemiring, IsInt, IsInt ] ); ## Default methods for ## ## delegate to . +##

+## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; +## gap> id7 := IdentityMatrix( 2, m7 );; Print( id7 ); +## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, +## [ [ ZmodnZObj( 1, 8 ), ZmodnZObj( 0, 8 ) ], +## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 1, 8 ) ] ]) +## gap> id2 := IdentityMatrix( Rationals, 2 );; Print( id2 ); +## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 1, 0 ], [ 0, 1 ] ]) +## gap> id3 := IdentityMatrix( IsGF2MatrixRep, GF(2), 3 );; Display( id3 ); +## 1 . . +## . 1 . +## . . 1 +## ]> +## ]]> ## ## ## <#/GAPDoc> @@ -1406,6 +1440,7 @@ DeclareOperation( "CompanionMatrix", ## Default methods for ## ## delegate to . +##

## m1 := Matrix( Integers, [ [3,4,5], [6,7,8] ] );; Print( m1 ); ## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ 3, 4, 5 ], [ 6, 7, 8 ] ]) @@ -1415,27 +1450,29 @@ DeclareOperation( "CompanionMatrix", ## [ 17 .. 23 ] ## [ 24 .. 30 ] ## ]> -gap> Print( Matrix( Integers, m2 ) ); -NewMatrix(IsPlistMatrixRep,Integers,7, -[ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) -gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); -NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) -gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); -NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) -gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); -true -gap> Print( Matrix( m0, m1 ) ); -NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) -gap> Print( Matrix( [-9..-4], 3, m1 ) ); -NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) -gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); -NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) -gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; -gap> Display( m6 ); - 1 . 1 - . 1 . -gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); - +## gap> Print( Matrix( Integers, m2 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,7, +## [ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) +## gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); +## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) +## gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) +## gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); +## true +## gap> Print( Matrix( m0, m1 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) +## gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) +## gap> Print( Matrix( [-9..-4], 3, m1 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) +## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +## gap> Display( m6 ); +## 1 . 1 +## . 1 . +## gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); +## +## gap> m8 := Matrix( IsZmodnZMatrixRep, ZmodnZ(12), m0 ); +## ## ]]> ## ## From f3e317d3fd91318c74f120bbf0c57ea625afbc62 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Mon, 4 May 2026 12:33:47 +0100 Subject: [PATCH 024/123] added alternative versions of NewMatrix --- lib/matobj2.gd | 34 ++++++++++++++++++++++++++++++---- lib/matobjplist.gi | 11 +++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index c7fb9ef3ac..29210efb02 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -803,6 +803,8 @@ DeclareTagBasedOperation( "NewZeroVector", ############################################################################# ## #O NewMatrix( , , , ) +#O NewMatrix( , , , ) +#O NewMatrix( , , ) #O NewZeroMatrix( , , , ) #O NewIdentityMatrix( , , ) ## @@ -810,15 +812,21 @@ DeclareTagBasedOperation( "NewZeroVector", ## ## NewMatrix, NewZeroMatrix, NewIdentityMatrix ## +## +## ## ## ## ## ## These three operations are constructors, and should only be used -## when , +## by those implementing new material for matrix objects. +## Most users should find +## , ## or ## -## do not give the desired result. +## sufficient for their requirements. ##

## For a filter filt, a semiring R, ## a positive integer ncols, and a list list, @@ -838,6 +846,10 @@ DeclareTagBasedOperation( "NewZeroVector", ## The corresponding entries must be in or compatible with R. ## If list already contains vector objects, they are copied. ##

+## The second and third alternatives for NewMatrix have been added +## for consistency with the corresponding versions of Matrix. +## They just call the first version. +##

## If the global option check is set to false then ## need not perform consistency checks. ##

@@ -859,8 +871,16 @@ DeclareTagBasedOperation( "NewZeroVector", ## . ##

## Matrix( IsPlistMatrixRep, Integers, [ [4,5,6], [7,8,9] ] ); -## <2x3-matrix over Integers> +## gap> m1 := NewMatrix( IsPlistMatrixRep, Integers, 3, [ [4,5,6], [7,8,9] ] );; +## gap> Display( m1 ); +## <2x3-matrix over Integers: +## [[ 4, 5, 6 ] +## [ 7, 8, 9 ] +## ]> +## gap> NewZeroMatrix( IsPlistMatrixRep, Rationals, 5, 3 ); +## <5x3-matrix over Rationals> +## gap> NewIdentityMatrix( IsGF2MatrixRep, GF(2), 4 ); +## ## ]]> ## ## @@ -869,6 +889,12 @@ DeclareTagBasedOperation( "NewZeroVector", DeclareTagBasedOperation( "NewMatrix", [ IsOperation, IsSemiring, IsInt, IsList] ); +DeclareOperation( "NewMatrix", + [ IsOperation, IsSemiring, IsList, IsInt] ); + +DeclareOperation( "NewMatrix", + [ IsOperation, IsSemiring, IsList] ); + DeclareTagBasedOperation( "NewZeroMatrix", [ IsOperation, IsSemiring, IsInt, IsInt ] ); diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index cafe1dd7d6..c3277ff899 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -188,6 +188,17 @@ InstallTagBasedMethod( NewZeroVector, return MakeIsPlistVectorRep(basedomain, list, false); end ); +# these two methods align NewMatrix with Matrix +InstallMethod( NewMatrix, [ IsOperation, IsSemiring, IsList, IsInt ], + function( filter, basedomain, list, ncols ) + return NewMatrix( filter, basedomain, ncols, list ); + end); + +InstallMethod( NewMatrix, [ IsOperation, IsSemiring, IsList ], + function( filter, basedomain, list ) + return NewMatrix( filter, basedomain, Length( list[1] ), list ); + end); + InstallTagBasedMethod( NewMatrix, IsPlistMatrixRep, function( filter, basedomain, ncols, list ) From 375569abe5ad623922745190750924f8645eabad Mon Sep 17 00:00:00 2001 From: cdwensley Date: Mon, 4 May 2026 12:45:21 +0100 Subject: [PATCH 025/123] remove trailing spaces --- lib/matobj2.gd | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 29210efb02..006e976705 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -872,12 +872,12 @@ DeclareTagBasedOperation( "NewZeroVector", ##

## m1 := NewMatrix( IsPlistMatrixRep, Integers, 3, [ [4,5,6], [7,8,9] ] );; -## gap> Display( m1 ); +## gap> Display( m1 ); ## <2x3-matrix over Integers: ## [[ 4, 5, 6 ] ## [ 7, 8, 9 ] ## ]> -## gap> NewZeroMatrix( IsPlistMatrixRep, Rationals, 5, 3 ); +## gap> NewZeroMatrix( IsPlistMatrixRep, Rationals, 5, 3 ); ## <5x3-matrix over Rationals> ## gap> NewIdentityMatrix( IsGF2MatrixRep, GF(2), 4 ); ## @@ -1232,9 +1232,9 @@ DeclareSynonym( "SetMatElm", ASS_MAT ); ##

## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; -## gap> z7 := ZeroMatrix( 2, 2, m7 );; Print( z7 ); +## gap> z7 := ZeroMatrix( 2, 2, m7 );; Print( z7 ); ## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, -## [ [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ], +## [ [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ], ## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ] ]) ## gap> z23 := ZeroMatrix( Rationals, 2, 3 );; Print( z23 ); ## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 0, 0 ], [ 0, 0, 0 ] ]) @@ -1293,9 +1293,9 @@ DeclareOperation( "ZeroMatrix", [ IsOperation, IsSemiring, IsInt, IsInt ] ); ##

## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; -## gap> id7 := IdentityMatrix( 2, m7 );; Print( id7 ); +## gap> id7 := IdentityMatrix( 2, m7 );; Print( id7 ); ## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, -## [ [ ZmodnZObj( 1, 8 ), ZmodnZObj( 0, 8 ) ], +## [ [ ZmodnZObj( 1, 8 ), ZmodnZObj( 0, 8 ) ], ## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 1, 8 ) ] ]) ## gap> id2 := IdentityMatrix( Rationals, 2 );; Print( id2 ); ## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 1, 0 ], [ 0, 1 ] ]) @@ -1476,12 +1476,12 @@ DeclareOperation( "CompanionMatrix", ## [ 17 .. 23 ] ## [ 24 .. 30 ] ## ]> -## gap> Print( Matrix( Integers, m2 ) ); +## gap> Print( Matrix( Integers, m2 ) ); ## NewMatrix(IsPlistMatrixRep,Integers,7, ## [ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) ## gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); ## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) -## gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); +## gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); ## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) ## gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); ## true @@ -1492,12 +1492,12 @@ DeclareOperation( "CompanionMatrix", ## gap> Print( Matrix( [-9..-4], 3, m1 ) ); ## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) ## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; -## gap> Display( m6 ); +## gap> Display( m6 ); ## 1 . 1 ## . 1 . ## gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); ## -## gap> m8 := Matrix( IsZmodnZMatrixRep, ZmodnZ(12), m0 ); +## gap> m8 := Matrix( IsZmodnZMatrixRep, ZmodnZ(12), m0 ); ## ## ]]> ## From 4bf9641b46884a804e47a6f85baf454efc346d4a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 16:09:00 +0100 Subject: [PATCH 026/123] Fix garbled result produced by CosetLeadersMatFFE (#6325) When invoked on compressed matrices over small finite fields, CosetLeadersMatFFE sometimes would produce incorrect output with gaps in it (i.e., undefined entries) AI assistance: Codex investigated the 8-bit fast path, added a regression test, and prepared the fix. Co-authored-by: Codex --- src/vec8bit.c | 24 +++++++++++++---- tst/testbugfix/2026-04-15-issue-5923.tst | 33 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tst/testbugfix/2026-04-15-issue-5923.tst diff --git a/src/vec8bit.c b/src/vec8bit.c index 397649b2c3..60243625c4 100644 --- a/src/vec8bit.c +++ b/src/vec8bit.c @@ -2482,6 +2482,7 @@ static UInt CosetLeadersInner8Bits(Obj veclis, UInt elts; UInt1 * ptr, *ptrw; const UInt1 * gettab; + const Obj * gapseq; const UInt1 * feltffe; Obj x; Obj vp; @@ -2491,6 +2492,7 @@ static UInt CosetLeadersInner8Bits(Obj veclis, elts = ELS_BYTE_FIELDINFO_8BIT(info); settab = SETELT_FIELDINFO_8BIT(info); gettab = GETELT_FIELDINFO_8BIT(info); + gapseq = GAPSEQ_FELT_FIELDINFO_8BIT(info); ptrw = BYTES_VEC8BIT(w); if (weight == 1) { for (i = pos; i <= len; i++) { @@ -2498,13 +2500,21 @@ static UInt CosetLeadersInner8Bits(Obj veclis, u = ELM_PLIST(vp, 1); AddVec8BitVec8BitInner(w, w, u, 1, lenw); ptr = BYTES_VEC8BIT(v) + (i - 1) / elts; - *ptr = settab[*ptr + 256 * (elts + ((i - 1) % elts))]; + // Keep the coefficient vector in the same sorted field-element + // order that NumberFFVector uses for list indices. + feltffe = FELT_FFE_FIELDINFO_8BIT(info); + x = ELM_PLIST(felts, 2); + *ptr = settab[*ptr + 256 * (elts * feltffe[VAL_FFE(x)] + + ((i - 1) % elts))]; sy = 0; for (j = 0; j < lenw; j++) { UInt xxxx; sy *= q; xxxx = gettab[ptrw[j / elts] + 256 * (j % elts)]; - sy += xxxx; + // The packed 8-bit representation uses a different internal + // field ordering, so translate back to GAP's sequence before + // using the syndrome number as a plain-list position. + sy += INT_INTOBJ(gapseq[xxxx]); } if ((Obj)0 == ELM_PLIST(leaders, sy + 1)) { UInt k; @@ -2517,10 +2527,13 @@ static UInt CosetLeadersInner8Bits(Obj veclis, wc = ZeroVec8Bit(q, lenw, 1); settab = SETELT_FIELDINFO_8BIT(info); gettab = GETELT_FIELDINFO_8BIT(info); + gapseq = GAPSEQ_FELT_FIELDINFO_8BIT(info); ptr = BYTES_VEC8BIT(v) + (i - 1) / elts; ptrw = BYTES_VEC8BIT(w); - for (k = 2; k < q; k++) { - qk = FFE_FELT_FIELDINFO_8BIT(info, k); + for (k = 3; k <= q; k++) { + // Record scalar multiples in the same order as the GAP + // fallback, namely the sorted field elements in 'felts'. + qk = ELM_PLIST(felts, k); MultVec8BitFFEInner(wc, w, qk, 1, lenw); ptrw = BYTES_VEC8BIT(wc); sy = 0; @@ -2528,11 +2541,12 @@ static UInt CosetLeadersInner8Bits(Obj veclis, UInt xxxx; sy *= q; xxxx = gettab[ptrw[j / elts] + 256 * (j % elts)]; - sy += xxxx; + sy += INT_INTOBJ(gapseq[xxxx]); } vc = ZeroVec8Bit(q, len, 0); settab = SETELT_FIELDINFO_8BIT(info); gettab = GETELT_FIELDINFO_8BIT(info); + gapseq = GAPSEQ_FELT_FIELDINFO_8BIT(info); ptr = BYTES_VEC8BIT(v) + (i - 1) / elts; ptrw = BYTES_VEC8BIT(w); MultVec8BitFFEInner(vc, v, qk, 1, len); diff --git a/tst/testbugfix/2026-04-15-issue-5923.tst b/tst/testbugfix/2026-04-15-issue-5923.tst new file mode 100644 index 0000000000..781733cd55 --- /dev/null +++ b/tst/testbugfix/2026-04-15-issue-5923.tst @@ -0,0 +1,33 @@ +# Regression test for issue #5923: the 8-bit kernel path for +# CosetLeadersMatFFE must not leave holes in the result list. +gap> F := GF(4);; +gap> M := One(F)*[[1,0,Z(4)],[0,1,Z(4)^2]];; +gap> L := CosetLeadersMatFFE(M, F);; +gap> Length(L) = Size(F)^2; +true +gap> ForAll([1..Length(L)], i -> IsBound(L[i])); +true +gap> List(L, v -> NumberFFVector(M * v, Size(F))) = [0..Length(L)-1]; +true + +# some additional tests "because we can" for other cases +gap> F := GF(2);; +gap> M := One(F)*[[1,0,1,0,1,0],[1,1,1,0,0,0]];; +gap> L := CosetLeadersMatFFE(M, F);; +gap> Length(L) = Size(F)^2; +true +gap> ForAll([1..Length(L)], i -> IsBound(L[i])); +true +gap> List(L, v -> NumberFFVector(M * v, Size(F))) = [0..Length(L)-1]; +true + +# some additional tests "because we can" for other cases +gap> F := GF(257);; +gap> M := One(F)*[[1,0,1,0,1,0],[1,1,1,0,0,0]];; +gap> L := CosetLeadersMatFFE(M, F);; +gap> Length(L) = Size(F)^2; +true +gap> ForAll([1..Length(L)], i -> IsBound(L[i])); +true +gap> List(L, v -> NumberFFVector(M * v, Size(F))) = [0..Length(L)-1]; +true From 99d2b4d334ece172fff77f690e9f7c1a390789bd Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 16:09:32 +0100 Subject: [PATCH 027/123] Fix crash in `CosetLeadersMatFFE` (#6326) Reject matrices with dependent rows before building the internal search tables for CosetLeadersMatFFE. This avoids a crash in the 8-bit path and restores correct behaviour for square full-rank inputs. AI assistance: Codex reproduced the crash, traced it to the internal row-independence assumption, added a regression test, and prepared the fix. Co-authored-by: Codex --- lib/listcoef.gi | 9 ++++++--- src/vec8bit.c | 2 ++ src/vecgf2.c | 2 ++ tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst | 8 ++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst diff --git a/lib/listcoef.gi b/lib/listcoef.gi index 8519d78cf5..106ab14463 100644 --- a/lib/listcoef.gi +++ b/lib/listcoef.gi @@ -1516,10 +1516,14 @@ InstallMethod(CosetLeadersMatFFE,"generic",IsCollsElms, q := Size(f); n := Length(mat[1]); m := Length(mat); + # The search below assumes the rows form a basis for an m-dimensional + # syndrome space, so reject dependent input before building the column data. + if RankMat(mat) <> m then + Error("CosetLeadersMatFFE: must have linearly independent rows"); + fi; tofind := q^m; t := TransposedMat(mat); - vl := []; - vl[m+1] := false; + vl := EmptyPlist(m); felts := AsSSortedList(f); Assert(2, felts[1] = Zero(f)); nzfelts := felts{[2..q]}; @@ -1537,7 +1541,6 @@ InstallMethod(CosetLeadersMatFFE,"generic",IsCollsElms, Add(vl[i], v*fds[j]); fi; od; - Add(vl[i],false); od; v := ListWithIdenticalEntries(n, felts[1]); w := ZeroOp(t[1]); diff --git a/src/vec8bit.c b/src/vec8bit.c index 60243625c4..9137672f8c 100644 --- a/src/vec8bit.c +++ b/src/vec8bit.c @@ -2604,8 +2604,10 @@ static Obj FuncCOSET_LEADERS_INNER_8BITS( Obj v, w; UInt lenv, lenw, q; + RequirePlainList(SELF_NAME, veclis); RequireSmallInt(SELF_NAME, weight); RequireSmallInt(SELF_NAME, tofind); + RequirePlainList(SELF_NAME, leaders); lenv = LEN_PLIST(veclis); q = LEN_PLIST(felts); diff --git a/src/vecgf2.c b/src/vecgf2.c index 69f1c9e8a1..6c3e64a1c2 100644 --- a/src/vecgf2.c +++ b/src/vecgf2.c @@ -3262,8 +3262,10 @@ static Obj FuncCOSET_LEADERS_INNER_GF2( Obj v, w; UInt lenv, lenw; + RequirePlainList(SELF_NAME, veclis); RequireSmallInt(SELF_NAME, weight); RequireSmallInt(SELF_NAME, tofind); + RequirePlainList(SELF_NAME, leaders); lenv = LEN_PLIST(veclis); NEW_GF2VEC(v, TYPE_LIST_GF2VEC, lenv); diff --git a/tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst b/tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst new file mode 100644 index 0000000000..75303e5941 --- /dev/null +++ b/tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst @@ -0,0 +1,8 @@ +# Regression test for square matrices and invalid dependent input in +# CosetLeadersMatFFE. +gap> M := IdentityMat(2, GF(2));; +gap> L := CosetLeadersMatFFE(M, GF(2));; +gap> Length(L); +4 +gap> CosetLeadersMatFFE(L, GF(2)); +Error, CosetLeadersMatFFE: must have linearly independent rows From 509f33ff9f52b3c28c43cfe825e4782fa22cf37f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 19:28:42 +0100 Subject: [PATCH 028/123] Fix MinimalGeneratingSet for pc groups (#6340) It sometimes produced incorrect results, where at least one generator was simply redundant. Revisit the pc-group candidates when a layer contracts. This drops generators that were only needed earlier. Later layer adjustments can change the induced pcgs. AI-assisted by Codex for investigation, testing, and implementation. Co-authored-by: Codex --- lib/grppcatr.gi | 29 +++++++++++++++++++++++- tst/testbugfix/2026-04-20-issue-5771.tst | 29 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2026-04-20-issue-5771.tst diff --git a/lib/grppcatr.gi b/lib/grppcatr.gi index b0f171adf7..0f9a42d7bf 100644 --- a/lib/grppcatr.gi +++ b/lib/grppcatr.gi @@ -541,6 +541,27 @@ RedispatchOnCondition( MaximalNormalSubgroups, true, [ IsSolvableGroup ], 0); +############################################################################# +## +#F ReduceMinGens( , , ) +## +BindGlobal( "ReduceMinGens", function( pcgs, pcgsN, min ) + local i, new; + + # Later layer refinements can make a previously appended generator + # redundant. Re-test the current candidates against the bottom layer. + i := 1; + while i <= Length( min ) do + new := min{Filtered([1..Length( min )], j -> j <> i)}; + if Length( InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, new ) ) + = Length( pcgs ) then + Remove( min, i ); + else + i := i + 1; + fi; + od; +end ); + ############################################################################# ## #F ModifyMinGens( , , , ) @@ -551,7 +572,8 @@ BindGlobal( "ModifyMinGens", function( pcgs, pcgsS, pcgsL, min ) # set up pcgsF := pcgsS mod pcgsL; - # try to modify mingens + # Try to absorb a generator from the current factor into one of the + # existing candidates before growing the generating set. for g in pcgsF do for i in [1..Length( min )] do new := ShallowCopy( min ); @@ -598,8 +620,13 @@ BindGlobal( "MinimalGensLayer", function( pcgs, pcgsS, pcgsN, min ) pcgsV := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsL, min ); pcgsU := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min ); if Length( pcgs ) = Length( pcgsV ) then + # Once the current candidates span the whole layer, continue with + # the next smaller layer and revisit any earlier append decisions. pcgsS := pcgsL; Remove(series); + ReduceMinGens( pcgs, pcgsN, min ); + pcgsV := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsS, min ); + pcgsU := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min ); fi; od; return min; diff --git a/tst/testbugfix/2026-04-20-issue-5771.tst b/tst/testbugfix/2026-04-20-issue-5771.tst new file mode 100644 index 0000000000..ea28b64c29 --- /dev/null +++ b/tst/testbugfix/2026-04-20-issue-5771.tst @@ -0,0 +1,29 @@ +## Regression test for #5771. The MinimalGeneratingSet method for pc-groups +## greedily appended a fifth generator, even though later adjustments make +## that generator redundant. The minimal generating set for this group has +## size 4, but GAP gave one of size 5, with one redundant generator. + +gap> START_TEST("2026-04-20-issue-5771.tst"); +gap> G := function() +> local f, g, g1, g2, g3, g4, g5, g6, g7, g8, g9, rws, rels, x; +> f := FreeGroup(IsSyllableWordsFamily, 9); +> g := GeneratorsOfGroup(f); +> g1 := g[1]; g2 := g[2]; g3 := g[3]; g4 := g[4]; g5 := g[5]; +> g6 := g[6]; g7 := g[7]; g8 := g[8]; g9 := g[9]; +> rws := SingleCollector(f, [ 2, 2, 2, 2, 3, 3, 3, 3, 3 ]); +> rels := [ +> [5,1,g5], [9,1,g9], [5,2,g5], [6,2,g6], [7,2,g7], +> [8,2,g8], [9,2,g9], [6,3,g6], [7,3,g7], [8,3,g8], +> [5,4,g5], [6,4,g6], [7,4,g7], [8,4,g8], [9,4,g9] +> ]; +> for x in rels do +> SetCommutator(rws, x[1], x[2], x[3]); +> od; +> return GroupByRwsNC(rws); +> end();; +gap> m := MinimalGeneratingSet(G);; +gap> Length(m) = 4 and +> ForAll([1..Length(m)], +> i -> Index(G, SubgroupNC(G, m{Filtered([1..Length(m)], j -> j <> i)})) > 1); +true +gap> STOP_TEST("2026-04-20-issue-5771.tst"); From 99c4a09294d639a9eb2ecc084578a6cd461e8d50 Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Mon, 4 May 2026 20:48:24 +0100 Subject: [PATCH 029/123] Add `WhereDepth` user preference (#6261) ... to control depth of initial stack trace in break loops --- doc/ref/mloop.xml | 11 ++++++++++- lib/error.g | 7 +++++-- lib/init.g | 10 ++++++++++ tst/testspecial/run_gap.sh | 1 + tst/testspecial/stack-trace-depth.g | 5 ++++- tst/testspecial/stack-trace-depth.g.out | 18 ++++++++++++++++-- 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/doc/ref/mloop.xml b/doc/ref/mloop.xml index ca1a723482..b39f2f50e8 100644 --- a/doc/ref/mloop.xml +++ b/doc/ref/mloop.xml @@ -739,12 +739,21 @@ is an example in the &GAP; code where the idea is actually used. Backtrace Stack trace shows the last nr commands on the execution stack during whose execution -the error occurred. If not given, nr defaults to 5. (Assume, for the +the error occurred. If not given, nr defaults to the value of the +WhereDepth user preference (initially 5). +If nr or the WhereDepth preference is not a non-negative integer, +it is treated as 5. +(Assume, for the following example, that after the last example has been set back to its default value.). acts the same as while also showing the arguments and local variables of each function.

+ acts the same as while also +showing the arguments and local variables of each function. +

+The following example assumes that is set to its default +value. StabChain(SymmetricGroup(1000)); # After this we typed ^C Error, user interrupt diff --git a/lib/error.g b/lib/error.g index fe1040a6ac..f43ab34778 100644 --- a/lib/error.g +++ b/lib/error.g @@ -180,6 +180,9 @@ end); BIND_GLOBAL("WHERE_INTERNAL", function(depth, showlocals) local activecontext; + if not IsInt(depth) or depth < 0 then + depth := 5; + fi; if ErrorLVars = fail or ErrorLVars = GetBottomLVars() then PrintTo(ERROR_OUTPUT, "not in any function "); else @@ -192,7 +195,7 @@ end); BIND_GLOBAL("WhereWithVars", function(arg) local depth; if LEN_LIST(arg) = 0 then - depth := 5; + depth := UserPreference("WhereDepth"); else depth := arg[1]; fi; @@ -203,7 +206,7 @@ end); BIND_GLOBAL("Where", function(arg) local depth; if LEN_LIST(arg) = 0 then - depth := 5; + depth := UserPreference("WhereDepth"); else depth := arg[1]; fi; diff --git a/lib/init.g b/lib/init.g index 810305951f..03601c810a 100644 --- a/lib/init.g +++ b/lib/init.g @@ -582,6 +582,16 @@ DeclareUserPreference( rec( default:= 3, check:= val -> IsInt( val ) and 0 <= val, ) ); +DeclareUserPreference( rec( + name:= "WhereDepth", + description:= [ + "The number of stack frames shown by Where and WhereWithVars \ +when called without an explicit depth argument, e.g. in the default OnBreak \ +handler." + ], + default:= 5, + check:= val -> IsInt( val ) and 0 <= val, + ) ); DeclareUserPreference( rec( name:= "ReproducibleBehaviour", description:= [ diff --git a/tst/testspecial/run_gap.sh b/tst/testspecial/run_gap.sh index 9ba7c29a65..aa7f088494 100755 --- a/tst/testspecial/run_gap.sh +++ b/tst/testspecial/run_gap.sh @@ -18,6 +18,7 @@ GAPROOT=$("$gap" --print-gaproot) ( echo "LogTo(\"${outfile}.tmp\");" ; cat "$gfile" ; echo "QUIT;" ) | "$gap" -r -A -b -m 256m -o 512m -x 800 \ -c 'SetUserPreference("UseColorsInTerminal",false);' \ + -c 'SetUserPreference("WhereDepth", 5);' \ 2>/dev/null >/dev/null sed -E -e "s:${GAPROOT//:/\\:}:GAPROOT/:g" -e "s;(GAPROOT(/[^/]+)+):[0-9]+;\1:LINE;g" < "${outfile}.tmp" > "${outfile}" rm "${outfile}.tmp" diff --git a/tst/testspecial/stack-trace-depth.g b/tst/testspecial/stack-trace-depth.g index dde6f2571b..28e525dbf2 100644 --- a/tst/testspecial/stack-trace-depth.g +++ b/tst/testspecial/stack-trace-depth.g @@ -32,5 +32,8 @@ f1 := function() return f2(); end;; f1(); -Where(12); +SetUserPreference("WhereDepth", 12); +Where(); +SetUserPreference("WhereDepth", 5); +Where(); quit; diff --git a/tst/testspecial/stack-trace-depth.g.out b/tst/testspecial/stack-trace-depth.g.out index 0005d8c5c7..7a30baca80 100644 --- a/tst/testspecial/stack-trace-depth.g.out +++ b/tst/testspecial/stack-trace-depth.g.out @@ -47,7 +47,8 @@ Stack trace: ... at *stdin*:35 you can 'quit;' to quit to outer loop, or you can 'return;' to continue -brk> Where(12); +brk> SetUserPreference("WhereDepth", 12); +brk> Where(); * [1] Error( "foo" ); @ *stdin*:3 [2] f11( ) @@ -71,6 +72,19 @@ brk> Where(12); [11] f2( ) @ *stdin*:33 ( ) - called from read-eval loop at *errin*:1 + called from read-eval loop at *errin*:2 +brk> SetUserPreference("WhereDepth", 5); +brk> Where(); +*[1] Error( "foo" ); + @ *stdin*:3 + [2] f11( ) + @ *stdin*:6 + [3] f10( ) + @ *stdin*:9 + [4] f9( ) + @ *stdin*:12 + [5] f8( ) + @ *stdin*:15 +... at *errin*:4 brk> quit; gap> QUIT; From 7e2e2da418513f75628bb2c40fffc21da78f9f9d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 22:02:55 +0100 Subject: [PATCH 030/123] doc: streamline Matrix argument variants (#6361) --- doc/ref/matobj.xml | 2 +- lib/matobj2.gd | 34 +++++++++------------------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index e8f5bbcedc..27fdfc1310 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -486,7 +486,7 @@ and then set the entries in this matrix. Functions like , , -and +and admit different kinds of inputs. ZeroMatrix( R, m, n ) can be used, for example, if we want to leave the decision about the representation of the result diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 006e976705..1405092d67 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1394,36 +1394,20 @@ DeclareOperation( "CompanionMatrix", ## <#GAPDoc Label="MatObj_Matrix"> ## ## Matrix -## -## -## -## -## -## -## -## -## -## -## +## +## +## +## +## ## ## a matrix object ## ## If a semiring R is given as the first argument then ## a matrix object is returned whose ## -## value is guessed from R, with base domain R -## and entries given by the argument list. +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the matrix object +## matobj, respectively. ## Here list can be either a list of plain lists that describe the ## entries of the rows, or a flat list of the entries in row major order, ## where ncols defines the number of columns. @@ -1456,7 +1440,7 @@ DeclareOperation( "CompanionMatrix", ## If the ## value of the result implies then the result is ## mutable if and only if the argument that determines the entries of the -## result (list, M, M1) is mutable. +## result (list or matobj) is mutable. ##

## In the case of a mutable result, it is guaranteed that the given list ## list is copied in the sense of , From db03c9979ea957b6018be6b65dc7e72227a48e24 Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Tue, 5 May 2026 16:16:11 +0100 Subject: [PATCH 031/123] Document DirectProductElement (#6260) --- doc/ref/mapping.xml | 1 + lib/tuples.gd | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/doc/ref/mapping.xml b/doc/ref/mapping.xml index 5a69256cc6..e23f858f8c 100644 --- a/doc/ref/mapping.xml +++ b/doc/ref/mapping.xml @@ -40,6 +40,7 @@ section . Direct Products and their Elements <#Include Label="IsDirectProductElement"> +<#Include Label="DirectProductElement"> <#Include Label="DirectProductFamily">

diff --git a/lib/tuples.gd b/lib/tuples.gd index bf644d6751..743a031bcc 100644 --- a/lib/tuples.gd +++ b/lib/tuples.gd @@ -147,13 +147,66 @@ BindGlobal( "EmptyDirectProductElementsFamily", #O DirectProductElementNC( , ) . . . . omits check on object #O families and objlist length ## +## <#GAPDoc Label="DirectProductElement"> ## ## ## ## ## +## returns a direct product element +## whose components are the entries of the list objlist. +## If the optional argument fam is given, it must be the family of +## direct product elements with the appropriate component families; +## otherwise the family is determined from objlist. +##

+## does the same but omits the checks +## that fam is consistent with objlist. +##

+## Direct product elements behave like lists: they can be indexed with +## elm[i] to access the i-th component, and +## returns the number of components. +## Arithmetic operations (multiplication, powering, one, inverse, +## addition, zero, additive inverse) are performed componentwise. +## a := (1,2,3);; b := (1,2);; +## gap> elm := DirectProductElement([a, b]); +## DirectProductElement( [ (1,2,3), (1,2) ] ) +## gap> elm[1]; +## (1,2,3) +## gap> elm[2]; +## (1,2) +## gap> Length(elm); +## 2 +## gap> elm2 := DirectProductElement([b, a]);; +## gap> elm * elm2; +## DirectProductElement( [ (2,3), (1,3) ] ) +## gap> One(elm); +## DirectProductElement( [ (), () ] ) +## gap> Inverse(elm); +## DirectProductElement( [ (1,3,2), (1,2) ] ) +## ]]> +##

+## The following example shows in the +## context of a direct product K = G \times H built with +## , where G is a permutation group and +## H is a pc group. The projections of K are +## used to move between the direct product and its component groups. +## G := DihedralGroup(IsPermGroup, 8);; +## gap> H := CyclicGroup(IsPcGroup, 4);; +## gap> K := DirectProduct(G, H);; +## gap> proj1 := Projection(K, 1);; proj2 := Projection(K, 2);; +## gap> g := (1,2,3,4);; h := GeneratorsOfGroup(H)[1];; +## gap> elm := DirectProductElement([g, h]); +## DirectProductElement( [ (1,2,3,4), f1 ] ) +## gap> Image(proj1, elm) = g; +## true +## gap> Image(proj2, elm) = h; +## true +## ]]> ## ## +## <#/GAPDoc> ## DeclareOperation( "DirectProductElement", [ IsList ]); DeclareOperation( "DirectProductElementNC", From c818f506da7f39c06ae914c4ef0bf6c96bddfce7 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 6 May 2026 01:47:49 +0200 Subject: [PATCH 032/123] Reset the options stack after an error also when the break loop is disabled (`-T` command line option) (#6355) --- lib/error.g | 12 ++++++++---- lib/package.gi | 5 +++-- tst/testinstall/error.tst | 10 ++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/error.g b/lib/error.g index f43ab34778..de03ee813f 100644 --- a/lib/error.g +++ b/lib/error.g @@ -32,13 +32,14 @@ ERROR_OUTPUT := MakeImmutable("*errout*"); Unbind(OnQuit); BIND_GLOBAL( "OnQuit", function() if not IsEmpty(OptionsStack) then + if IsBound(ResetMethodReordering) and IsFunction(ResetMethodReordering) + and ValueOption( "ReadingPackageFiles" ) = true then + ResetMethodReordering(); + fi; repeat PopOptions(); until IsEmpty(OptionsStack); - Info(InfoWarning,1,"Options stack has been reset"); - fi; - if IsBound(ResetMethodReordering) and IsFunction(ResetMethodReordering) then - ResetMethodReordering(); + Info(InfoWarning,2,"Options stack has been reset"); fi; if REREADING = true then MakeReadWriteGlobal("REREADING"); @@ -373,6 +374,9 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) ErrorLVars := errorLVars; ErrorTracebackLVars := errorTracebackLVars; SET_ERROR_LVARS(kernelErrorLVars); + if IsBound(OnQuit) and IsFunction(OnQuit) then + OnQuit(); + fi; if ErrorLevel = 0 then LEAVE_ALL_NAMESPACES(); fi; JUMP_TO_CATCH(0); fi; diff --git a/lib/package.gi b/lib/package.gi index fbd23eda01..1930c9d6fd 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -1750,7 +1750,7 @@ InstallGlobalFunction( LoadPackage, function( arg ) "start reading file 'init.g'", info.PackageName ); GAPInfo.PackageCurrent:= info; - ReadPackage( pkgname, "init.g" ); + ReadPackage( pkgname, "init.g" : ReadingPackageFiles:= true ); Unbind( GAPInfo.PackageCurrent ); LogPackageLoadingMessage( PACKAGE_DEBUG, "finish reading file 'init.g'", @@ -1766,7 +1766,8 @@ InstallGlobalFunction( LoadPackage, function( arg ) # (We have delayed this until now because it uses functionality # from the package GAPDoc.) # Note that no banners are printed during autoloading. - LoadPackage_ReadImplementationParts( secondrun, banner ); + LoadPackage_ReadImplementationParts( secondrun, banner + : ReadingPackageFiles:= true ); secondrun:= []; od; diff --git a/tst/testinstall/error.tst b/tst/testinstall/error.tst index 9cb0d353f7..cf590212f9 100644 --- a/tst/testinstall/error.tst +++ b/tst/testinstall/error.tst @@ -34,3 +34,13 @@ gap> if false then Stabilizer; fi; Syntax error: found an expression when a statement was expected in stream:1 if false then Stabilizer; fi; ^ + +# +gap> oldBreakOnError:= BreakOnError;; +gap> BreakOnError:= false;; +gap> PushOptions( rec( test:= true ) ); +gap> Error( "!" ); +Error, ! +gap> Length( OptionsStack ) = 0; +true +gap> BreakOnError:= oldBreakOnError;; From 7a617cc1464061e59308889fcd1d1ab81dbba2bd Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 6 May 2026 01:25:32 +0100 Subject: [PATCH 033/123] Guard some `IdGroup` calls by `ID_AVAILABLE` (#6353) ... instead of hardcoding assumptions about the availability of IdGroup. --- lib/grplatt.gi | 13 ++++++------- lib/grpnames.gi | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 610b9826e5..5563219bf7 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2759,15 +2759,14 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, fi; fgi:=function(gp,nor) - local idx,hom,l,f; - idx:=Index(gp,nor); + local hom,l,f; hom:=NaturalHomomorphismByNormalSubgroup(gp,nor); - if idx>1000 or idx=512 or not uselib then - l:=[idx,fail]; + f:=Image(hom); + if uselib and Size(f) < 1000 and ID_AVAILABLE(Size(f)) <> fail then + l:=ShallowCopy(IdGroup(f)); else - l:=ShallowCopy(IdGroup(gp/nor)); + l:=[Size(f),fail]; fi; - f:=Image(hom,gp); Add(l,hom); Add(l,f); Add(l,AutomorphismGroup(f)); @@ -2835,7 +2834,7 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, for k in no do hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); f:=Image(hom); - if Size(f)<1000 and Size(f)<>512 and uselib then + if uselib and Size(f) < 1000 and ID_AVAILABLE(Size(f)) <> fail then myid:=ShallowCopy(IdGroup(f)); else myid:=[Size(f),fail]; diff --git a/lib/grpnames.gi b/lib/grpnames.gi index af9fdb5b01..32aa8f6368 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1861,7 +1861,7 @@ BindGlobal( "StructureDescriptionForFiniteGroups", # for finite groups # fetch name from precomputed list, if available if ValueOption("recompute") <> true and Size(G) <= 2000 then - if IsBound(NAMES_OF_SMALL_GROUPS[Size(G)]) then + if IsBound(NAMES_OF_SMALL_GROUPS[Size(G)]) and ID_AVAILABLE(Size(G)) <> fail then i := IdGroup(G)[2]; if IsBound(NAMES_OF_SMALL_GROUPS[Size(G)][i]) then name := ShallowCopy(NAMES_OF_SMALL_GROUPS[Size(G)][i]); From 9fcabc2f922c730e0e251782c221cc619aaebf65 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 6 May 2026 02:43:15 +0200 Subject: [PATCH 034/123] Add `RandomMatrix`, `RandomInvertibleMatrix`; and fix a problem with a new feature for matrix groups (#6232) - add a description of the cache `FULLGLNICOCACHE` in the code; it is used only by `NicomorphismFFMatGroupOnFullSpace` - change the keys of `FULLGLNICOCACHE`: take the field of the matrix entries into account (not only its size), take the `ConstructingFilter` of the matrices into account - in `NicomorphismFFMatGroupOnFullSpace`, deal with special cases of matrices in `IsBlockMatrixRep` (which have no `ConstructingFilter`) and in `Is8BitMatrixRep` in the situation that the group itself lives over `GF(2)` - in order to admit the action of `IsMatrixObj` matrices on vectors supported by GAP's `Enumerator`s of vector spaces, add a `\^` method that `Unpack`s the matrix object (Eventually we want to avoid this overhead, but then we need `Enumerator`s consisting of vector objects corresponding to the matrix objects.) - add `Matrix` calls in the function that computes preimages under an action homomorphism with `Source` a matrix group, in order to support matrix group elements of prescribed kinds of `IsMatrixObj`. - add tests for the new supported situations (most of the changes were actually forced by already available tests) * add `\in` methods for matrix object and (`GL` or `SL`) * avoid some `Unpack` hacks - introduce `NormedRowVectors_internal( F, base )`, and `AsListOfFreeLeftModule_internal( F, base, zero )`, in order to admit `IsVectorObj`s in `base` without supporting the whole vector space machinery for these objects - introduce `ExternalSet( G )` for matrix groups `G`, meaning the natural `G`-set (an undocumented method for permutation groups `G` was already available) - change `NicomorphismFFMatGroupOnFullSpace` such that we can act with the `IsMatrixObj` matrices on their `IsVectorObj` vectors, without unpacking the matrices - support `IsMatrixObj` matrices in the `Random` methods for GL and SL * adjust also `IsProjectiveActionHomomorphism` methods * add `RandomMatrix`, `RandomInvertibleMatrix` and fix the `RankMat` method for `IsPlistMatrixRep` --- doc/ref/matrix.xml | 2 + grp/classic.gd | 2 +- lib/grpffmat.gi | 158 +++++++++++++--- lib/matobjplist.gi | 8 +- lib/matrix.gd | 174 +++++++++++++++++- lib/matrix.gi | 111 +++++++++++ lib/methsel.g | 24 +++ lib/modfree.gi | 24 ++- lib/oprt.gi | 96 +++++++--- lib/vspcrow.gi | 60 +++--- tst/testbugfix/2007-07-02-t00180.tst | 2 +- .../MatrixObj/DeterminantMatrix.tst | 29 +++ .../MatrixObj/RandomInvertibleMatrix.tst | 52 ++++++ tst/testinstall/MatrixObj/RandomMatrix.tst | 72 ++++++++ tst/testinstall/MatrixObj/RankMatrix.tst | 23 +++ tst/testinstall/MatrixObj/acthom.tst | 80 ++++++++ tst/testinstall/grpmat.tst | 18 +- 17 files changed, 823 insertions(+), 112 deletions(-) create mode 100644 tst/testinstall/MatrixObj/DeterminantMatrix.tst create mode 100644 tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst create mode 100644 tst/testinstall/MatrixObj/RandomMatrix.tst create mode 100644 tst/testinstall/MatrixObj/RankMatrix.tst create mode 100644 tst/testinstall/MatrixObj/acthom.tst diff --git a/doc/ref/matrix.xml b/doc/ref/matrix.xml index 59f006dbfd..e80f6b2419 100644 --- a/doc/ref/matrix.xml +++ b/doc/ref/matrix.xml @@ -341,7 +341,9 @@ see . Random Matrices <#Include Label="RandomMat"> +<#Include Label="RandomMatrix"> <#Include Label="RandomInvertibleMat"> +<#Include Label="RandomInvertibleMatrix"> <#Include Label="RandomUnimodularMat">

diff --git a/grp/classic.gd b/grp/classic.gd index 0bfd9b3b4b..ae891da7be 100644 --- a/grp/classic.gd +++ b/grp/classic.gd @@ -836,7 +836,7 @@ BindGlobal( "SymplecticGroup", function ( arg ) rep:= filt; filt:= IsMatrixGroup; else - rep:= fail; + rep:= ValueOption( "ConstructingFilter" ); fi; if DescribesInvariantBilinearForm( Last( arg ) ) then form:= Remove( arg ); diff --git a/lib/grpffmat.gi b/lib/grpffmat.gi index 147563c60b..2f63b1c1d3 100644 --- a/lib/grpffmat.gi +++ b/lib/grpffmat.gi @@ -124,31 +124,80 @@ end ); ############################################################################# ## -#M NiceMonomorphism( ) +## the natural G-set of a matrix group consists of the vectors of the +## natural module +## +InstallOtherMethod( ExternalSet, + [ IsFFEMatrixGroup and IsFinite ], + function( G ) + local basis, zero; + + basis:= RowsOfMatrix( One( G ) ); + zero:= Zero( basis[1] ); + return ExternalSet( G, AsListOfFreeLeftModule_internal( + FieldOfMatrixGroup( G ), basis, zero ) ); +end ); + +############################################################################# +## +#V FULLGLNICOCACHE +## +## 'NicomorphismFFMatGroupOnFullSpace' uses a cache of length up to 5, +## as follows. +## +## - If the argument is a matrix group that fits to an entry of this +## cache, in the sense that dimension, field of definition, +## and 'ConstructingFilter' of the matrices in the group are the same as +## for the cached value, the stored mapping is returned. +## - If a new mapping has to be constructed, the first cached entry is +## dropped and the new mapping gets added to the cache. ## MakeThreadLocal("FULLGLNICOCACHE"); # avoid recreating same homom. repeatedly -FULLGLNICOCACHE:=[]; -InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) - local field, dim, V, xset, nice; +BindGlobal( "FULLGLNICOCACHE", [] ); - field := FieldOfMatrixGroup( grp ); - dim := DimensionOfMatrixGroup( grp ); + +############################################################################# +## +#M NiceMonomorphism( ) +## +InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) + local rep, filt, q, dim, field, xset, nice; + + rep:= Representative( grp ); + field:= FieldOfMatrixGroup( grp ); + q:= Size( field ); + if IsBlockMatrixRep( rep ) then + # There is no support for these matrices acting on vectors. + filt:= IsPlistRep; + elif q = 2 and Is8BitMatrixRep( rep ) then + # We cannot keep both 'field' and 'Is8BitMatrixRep', + # the latter does not admit matrices over GF(2). + filt:= IsGF2MatrixRep; +#TODO: How can we get rid of these hacks? + else + filt:= ConstructingFilter( rep ); + fi; + dim:= DimensionOfMatrixGroup( grp ); #check cache - V:=Size(field); - nice:=First(FULLGLNICOCACHE,x->x[1]=V and x[2]=dim); - if nice<>fail then return nice[3];fi; + nice:= First( FULLGLNICOCACHE, + x -> x[1] = field and x[2] = dim and x[3] = filt ); + + if nice<>fail then return nice[4];fi; if not (HasIsNaturalGL(grp) and IsNaturalGL(grp)) then - grp:=GL(dim,field); # enforce map on full GL + # enforce map on full GL + grp:= GL( dim, field : ConstructingFilter:= filt ); fi; - V := field ^ dim; - xset := ExternalSet( grp, V ); - + xset := ExternalSet( grp ); # STILL: reverse the base to get point sorting compatible with lexicographic # vector arrangement - SetBaseOfGroup( xset, One( grp )); + if IsList( One( grp ) ) then + SetBaseOfGroup( xset, One( grp )); + else + SetBaseOfGroup( xset, RowsOfMatrix( One( grp ) ) ); + fi; nice := ActionHomomorphism( xset,"surjective" ); SetIsInjective( nice, true ); if not HasNiceMonomorphism(grp) then @@ -156,14 +205,14 @@ InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) fi; # because we act on the full space we are canonical. SetIsCanonicalNiceMonomorphism(nice,true); - if Size(V)>10^5 then + if q^dim > 10^5 then # store only one big one and have it get thrown out quickly - FULLGLNICOCACHE[1]:=[Size(field),dim,nice]; + FULLGLNICOCACHE[1]:= [ field, dim, filt, nice ]; else if Length(FULLGLNICOCACHE)>4 then - FULLGLNICOCACHE:=FULLGLNICOCACHE{[2..5]}; + Remove( FULLGLNICOCACHE, 1 ); fi; - Add(FULLGLNICOCACHE,[Size(field),dim,nice]); + Add( FULLGLNICOCACHE, [ field, dim, filt, nice ] ); fi; return nice; @@ -190,8 +239,7 @@ local tt; # if the permutation image would be too large, compute the orbit. TryNextMethod(); fi; - return NicomorphismFFMatGroupOnFullSpace( GL( DimensionOfMatrixGroup( grp ), - Size( FieldOfMatrixGroup( Parent(grp) ) ) ) ); + return NicomorphismFFMatGroupOnFullSpace( grp ); end ); ############################################################################# @@ -256,6 +304,25 @@ InstallMethod( \in, "general linear group", IsElmsColls, and Length( mat ) = RankMat( mat ); end ); +InstallMethod( \in, "general linear group", IsElmsColls, + [ IsMatrixObj, IsFFEMatrixGroup and IsFinite and IsNaturalGL ], 0, + function( mat, G ) + local n, F; + n:= NumberRows( mat ); + F:= FieldOfMatrixGroup( G ); + return n = NumberColumns( mat ) + and n = DimensionOfMatrixGroup( G ) + and n = RankMat( mat ) +#TODO: +# Currently we cannot force the rule that all matrices in a matrix +# group consisting of matrix objects have the same 'BaseDomain', +# and that this common 'BaseDomain' is equal to the 'FieldOfMatrixGroup' +# of the group. +# Eventually we want 'true' only if 'F = BaseDomain( mat )' holds. + and ( IsSubset( F, BaseDomain( mat ) ) or + ForAll( Unpack( mat ), row -> IsSubset( F, row ) ) ); +end ); + InstallMethod( \in, "special linear group", IsElmsColls, [ IsMatrix, IsFFEMatrixGroup and IsFinite and IsNaturalSL ], 0, function( mat, G ) @@ -266,6 +333,19 @@ InstallMethod( \in, "special linear group", IsElmsColls, and DeterminantMat(mat)=One(FieldOfMatrixGroup( G )); end ); +InstallMethod( \in, "special linear group", IsElmsColls, + [ IsMatrixObj, IsFFEMatrixGroup and IsFinite and IsNaturalSL ], 0, + function( mat, G ) + local n, F; + n:= NumberRows( mat ); + F:= FieldOfMatrixGroup( G ); + return n = NumberColumns( mat ) + and n = DimensionOfMatrixGroup( G ) + and ( IsSubset( F, BaseDomain( mat ) ) or + ForAll( Unpack( mat ), row -> IsSubset( F, row ) ) ) + and DeterminantMat( mat ) = One( F ); +end ); + ############################################################################# ## @@ -508,10 +588,23 @@ InstallMethodWithRandomSource( Random, "for a random source and natural GL", [ IsRandomSource, IsFFEMatrixGroup and IsFinite and IsNaturalGL ], function(rs, G) - local m; - m := RandomInvertibleMat( rs, DimensionOfMatrixGroup( G ), - FieldOfMatrixGroup( G ) ); - return ImmutableMatrix(FieldOfMatrixGroup(G), m, true); + local d, F, m; + + d:= DimensionOfMatrixGroup( G ); + F:= FieldOfMatrixGroup( G ); + m:= Representative( G ); + if IsMatrix( m ) then + m:= RandomInvertibleMat( rs, d, F ); + m:= ImmutableMatrix(F, m, true); + else + m:= ZeroMatrix( d, d, m ); + repeat + Randomize( rs, m ); + until RankMat( m ) = d; + MakeImmutable( m ); + fi; + + return m; end); @@ -527,11 +620,18 @@ InstallMethodWithRandomSource( Random, "for a random source and natural SL", [ IsRandomSource, IsFFEMatrixGroup and IsFinite and IsNaturalSL ], function(rs, G) - local m; - m:= RandomInvertibleMat( rs, DimensionOfMatrixGroup( G ), - FieldOfMatrixGroup( G ) ); - MultVector(m[1], DeterminantMat(m)^-1); - return ImmutableMatrix(FieldOfMatrixGroup(G), m, true); + local d, m; + + # We assume that all elements in the group have the same + # 'BaseDomain' value, hence we may take any 'Representative'. + # see the section "Groups Consisting of Matrix Objects" + # in the Reference Manual. + d:= DimensionOfMatrixGroup( G ); + m:= RandomInvertibleMatrix( rs, d, Representative( G ) ); + MultMatrixRow( m, 1, DeterminantMatrix( m )^-1 ); + MakeImmutable( m ); + + return m; end); ############################################################################# diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index c3277ff899..c9af75c590 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -1229,7 +1229,13 @@ InstallMethod( InverseSameMutability, InstallMethod( RankMat, [ "IsPlistMatrixRep" ], - M -> RankMat( List( M![ROWSPOS], x -> x![ELSPOS] ) ) ); + function( M ) + M:= M![ROWSPOS]; + if Length( M ) = 0 then + return 0; + fi; + return RankMat( List( M, x -> x![ELSPOS] ) ); + end ); InstallMethodWithRandomSource( Randomize, "for a random source and a mutable plist matrix", diff --git a/lib/matrix.gd b/lib/matrix.gd index 8056c80165..4fe2262981 100644 --- a/lib/matrix.gd +++ b/lib/matrix.gd @@ -1887,6 +1887,82 @@ DeclareGlobalFunction( "DiagonalMat" ); DeclareGlobalFunction( "ReflectionMat" ); +############################################################################# +## +#O RandomInvertibleMatrix( [, ][, ], ) +#O RandomInvertibleMatrix( [, ], ) +## +## <#GAPDoc Label="RandomInvertibleMatrix"> +## +## +## +## +## +## a matrix or matrix object I with m columns, +## with base domain R or equal to BaseDomain( M ), +## such that I is invertible over its base domain. +## +## +## If a semiring R is given then it will be the base domain +## (see ) +## of the returned matrix. +## In this case, a filter filt can be specified that defines the +## internal representation of the result +## (see ). +## The default value for filt is determined from R. +##

+## If a matrix object M is given then the returned matrix will have +## the same internal representation and the same base domain as M. +##

+## If a random source rs is given (see ) +## then the entries of the result are computed using rs, +## the default random source is . +##

+## If the value +## of the result implies then the result is +## fully mutable. +##

+## m:= RandomInvertibleMatrix( GF(9), 2 );; +## gap> RankMatrix( m ); +## 2 +## gap> DimensionsMat( m ); +## [ 2, 2 ] +## gap> BaseDomain( m ); +## GF(3^2) +## gap> Is8BitMatrixRep( m ); +## true +## gap> m1:= RandomInvertibleMatrix( IsPlistMatrixRep, GF(9), 2 );; +## gap> IsPlistMatrixRep( m1 ); +## true +## gap> m2:= RandomInvertibleMatrix( 2, m1 );; +## gap> IsPlistMatrixRep( m2 ); +## true +## gap> m:= RandomInvertibleMatrix( Integers, 2 );; +## gap> IsUnit( Integers, DeterminantMatrix( m ) ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareTagBasedOperation( "RandomInvertibleMatrix", + [ IsOperation, IsRandomSource, IsSemiring, IsInt ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsRandomSource, IsSemiring, IsInt ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsOperation, IsSemiring, IsInt ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsSemiring, IsInt ] ); + +DeclareOperation( "RandomInvertibleMatrix", + [ IsRandomSource, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsInt, IsMatrixOrMatrixObj ] ); + + ############################################################################# ## #F RandomInvertibleMat( [rs ,] [, ] ) . . . random invertible matrix @@ -1900,13 +1976,19 @@ DeclareGlobalFunction( "ReflectionMat" ); ## matrix with m rows and columns with elements taken from the ring ## R, which defaults to . ## Optionally, a random source rs can be supplied. +##

+## Note that the result need not be invertible over +## the prescribed ring R. +## Use +## for creating random matrices with this stronger property. +##

## m := RandomInvertibleMat(4); -## [ [ -4, 1, 0, -1 ], [ -1, -1, 1, -1 ], [ 1, -2, -1, -2 ], -## [ 0, -1, 2, -2 ] ] +## gap> m := RandomInvertibleMat( 4, Integers ); +## [ [ 1, -4, 0, 1 ], [ 0, -2, 3, 1 ], [ 0, -2, -1, -1 ], +## [ 0, -2, 2, 4 ] ] ## gap> m^-1; -## [ [ -1/8, -11/24, 1/24, 1/4 ], [ 1/4, -13/12, -1/12, 1/2 ], -## [ -1/8, 5/24, -7/24, 1/4 ], [ -1/4, 3/4, -1/4, -1/2 ] ] +## [ [ 1, -1/14, -19/14, -4/7 ], [ 0, -1/14, -5/14, -1/14 ], +## [ 0, 5/14, -3/14, -1/7 ], [ 0, -3/14, -1/14, 2/7 ] ] ## ]]> ## ## @@ -1939,6 +2021,78 @@ DeclareGlobalFunction( "RandomInvertibleMat" ); DeclareGlobalFunction( "RandomMat" ); +############################################################################# +## +#O RandomMatrix( [, ][, ], , ) +#O RandomMatrix( [, ], , ) +## +## <#GAPDoc Label="RandomMatrix"> +## +## +## +## +## +## a matrix or matrix object with m rows and n columns, +## with base domain R or equal to BaseDomain( M ). +## +## +## If a semiring R is given then it will be the base domain +## (see ) +## of the returned matrix. +## In this case, a filter filt can be specified that defines the +## internal representation of the result +## (see ). +## The default value for filt is determined from R. +##

+## If a matrix object M is given then the returned matrix will have +## the same internal representation and the same base domain as M. +##

+## If a random source rs is given (see ) +## then the entries of the result are computed using rs, +## the default random source is . +##

+## If the value +## of the result implies then the result is +## fully mutable. +##

+## m:= RandomMatrix( GF(9), 2, 3 );; +## gap> DimensionsMat( m ); +## [ 2, 3 ] +## gap> BaseDomain( m ); +## GF(3^2) +## gap> Is8BitMatrixRep( m ); +## true +## gap> m1:= RandomMatrix( IsPlistMatrixRep, GF(9), 2, 3 );; +## gap> IsPlistMatrixRep( m1 ); +## true +## gap> m2:= RandomMatrix( 3, 4, m1 );; +## gap> DimensionsMat( m2 ); +## [ 3, 4 ] +## gap> IsPlistMatrixRep( m2 ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareTagBasedOperation( "RandomMatrix", + [ IsOperation, IsRandomSource, IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "RandomMatrix", + [ IsRandomSource, IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "RandomMatrix", + [ IsOperation, IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "RandomMatrix", + [ IsSemiring, IsInt, IsInt ] ); + +DeclareOperation( "RandomMatrix", + [ IsRandomSource, IsInt, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "RandomMatrix", + [ IsInt, IsInt, IsMatrixOrMatrixObj ] ); + + ############################################################################# ## #F RandomUnimodularMat( [rs ,] ) . . . . . . . . random unimodular matrix @@ -1955,13 +2109,13 @@ DeclareGlobalFunction( "RandomMat" ); ## from Integers ## m := RandomUnimodularMat(3); -## [ [ -5, 1, 0 ], [ 12, -2, -1 ], [ -14, 3, 0 ] ] +## [ [ 1, -5, 26 ], [ 0, 1, -6 ], [ 0, 0, 1 ] ] ## gap> m^-1; -## [ [ -3, 0, 1 ], [ -14, 0, 5 ], [ -8, -1, 2 ] ] +## [ [ 1, 5, 4 ], [ 0, 1, 6 ], [ 0, 0, 1 ] ] ## gap> RandomUnimodularMat(3:domain:=[-1000..1000]); -## [ [ 312330173, 15560030349, -125721926670 ], -## [ -307290, -15309014, 123693281 ], -## [ -684293792, -34090949551, 275448039848 ] ] +## [ [ 6001314, 239514853714734, -44705745791413 ], +## [ -1448123744, -57795200635226587, 10787546189680040 ], +## [ -671, -26780118200, 4998542420 ] ] ## ]]> ## ## diff --git a/lib/matrix.gi b/lib/matrix.gi index 956cd1b41b..b5780f80f4 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -3952,6 +3952,71 @@ InstallGlobalFunction( ReflectionMat, function( arg ) end ); +######################################################################### +## +#M RandomInvertibleMatrix( [, ][, ], ) +#M RandomInvertibleMatrix( [, ], ) +## +InstallTagBasedMethod( RandomInvertibleMatrix, + function( filt, rs, R, m ) + local mat, i, j; + + if IsIntegers( R ) then + # We have a dedicated method for this case. + mat:= RandomUnimodularMat( rs, m ); + if filt <> IsPlistRep then + mat:= Matrix( filt, R, mat ); + fi; + else + # The following works if 'R' is a field or a residue class ring. + # If other rings become important, + # we have to think about a better approach. + mat:= ZeroMatrix( filt, R, m, m ); + repeat + # 'Randomize' does not admit 'R' as an argument, + # and we want to cover also 'IsPlistRep'. + for i in [ 1 .. m ] do + for j in [ 1 .. m ] do + mat[i,j]:= Random( rs, R ); + od; + od; + until IsUnit( DeterminantMat( mat ) ); + fi; + + return mat; + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsRandomSource, IsSemiring, IsInt ], + function( rs, R, m ) + return RandomInvertibleMatrix( DefaultMatrixRepForBaseDomain( R ), rs, R, m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsOperation, IsSemiring, IsInt ], + function( filt, R, m ) + return RandomInvertibleMatrix( filt, GlobalMersenneTwister, R, m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsSemiring, IsInt ], + function( R, m ) + return RandomInvertibleMatrix( DefaultMatrixRepForBaseDomain( R ), GlobalMersenneTwister, R, m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsRandomSource, IsInt, IsMatrixOrMatrixObj ], + function( rs, m, M ) + return RandomInvertibleMatrix( ConstructingFilter( M ), rs, BaseDomain( M ), m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsInt, IsMatrixOrMatrixObj ], + function( m, M ) + return RandomInvertibleMatrix( ConstructingFilter( M ), GlobalMersenneTwister, BaseDomain( M ), m ); + end ); + + ######################################################################### ## #F RandomInvertibleMat( [rs ,] [, ] ) . . . make a random invertible matrix @@ -4001,6 +4066,52 @@ InstallGlobalFunction( RandomInvertibleMat, function ( arg ) end ); +######################################################################### +## +#M RandomMatrix( [, ][, ], , ) +#M RandomMatrix( [, ], , ) +## +InstallTagBasedMethod( RandomMatrix, + function( filt, rs, R, m, n ) + local mat; + + mat:= ZeroMatrix( filt, R, m, n ); + Randomize( rs, mat ); + + return mat; + end ); + +InstallMethod( RandomMatrix, + [ IsRandomSource, IsSemiring, IsInt, IsInt ], + function( rs, R, m, n ) + return RandomMatrix( DefaultMatrixRepForBaseDomain( R ), rs, R, m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsOperation, IsSemiring, IsInt, IsInt ], + function( filt, R, m, n ) + return RandomMatrix( filt, GlobalMersenneTwister, R, m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsSemiring, IsInt, IsInt ], + function( R, m, n ) + return RandomMatrix( DefaultMatrixRepForBaseDomain( R ), GlobalMersenneTwister, R, m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsRandomSource, IsInt, IsInt, IsMatrixOrMatrixObj ], + function( rs, m, n, M ) + return RandomMatrix( ConstructingFilter( M ), rs, BaseDomain( M ), m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsInt, IsInt, IsMatrixOrMatrixObj ], + function( m, n, M ) + return RandomMatrix( ConstructingFilter( M ), GlobalMersenneTwister, BaseDomain( M ), m, n ); + end ); + + ############################################################################# ## #F RandomMat( [rs ,] , [, ] ) . . . . . . . . make a random matrix diff --git a/lib/methsel.g b/lib/methsel.g index 54e1e02fd9..1f8634f7c9 100644 --- a/lib/methsel.g +++ b/lib/methsel.g @@ -253,6 +253,30 @@ BIND_GLOBAL( "NewTagBasedOperation", return method( req1, req2, req3, req4 ); end ); + elif LENGTH( requirements ) = 5 then + InstallEarlyMethod( oper, + function( req1, req2, req3, req4, req5 ) + local method; + + if not ( requirements[1]( req1 ) and + requirements[2]( req2 ) and + requirements[3]( req3 ) and + requirements[4]( req4 ) and + requirements[5]( req5 ) ) then + TryNextMethod(); + fi; + + method:= FIND_OBJ_MAP( methods, req1, fail ); + if method = fail then + # Take the default method if there is one. + method:= FIND_OBJ_MAP( methods, IS_OBJECT, fail ); + fi; + if method = fail then + Error( "no default installed for tag based operation " ); + fi; + + return method( req1, req2, req3, req4, req5 ); + end ); else Error( "tag based operations for ", LENGTH( requirements ), " arguments are currently not supported" ); diff --git a/lib/modfree.gi b/lib/modfree.gi index 86252154e8..85928ad44e 100644 --- a/lib/modfree.gi +++ b/lib/modfree.gi @@ -162,23 +162,25 @@ InstallMethod( Size, ## Either this basis has been entered when the space was constructed, or a ## basis is computed together with the elements list. ## -BindGlobal( "AsListOfFreeLeftModule", function( V ) + +## The vectors in 'base' are assumed to be linearly independent. +BindGlobal( "AsListOfFreeLeftModule_internal", function( F, base, zero ) local elms, # elements list, result - B, # $F$-basis of $V$ new, # intermediate elements list v, # one generator of $V$ i; # loop variable - if not IsFinite( V ) then - Error( "cannot compute elements list of infinite domain " ); + elms:= [ zero ]; + + if IsEmpty( base ) then + return elms; + elif not IsFinite( F ) then + Error( "cannot compute elements list over infinite domain " ); fi; - B := Basis( V ); - elms := [ Zero( V ) ]; -#T check whether we have the elements now ? - for v in BasisVectors( B ) do + for v in base do new:= []; - for i in AsList( LeftActingDomain( V ) ) do + for i in AsList( F ) do Append( new, List( elms, x -> x + i * v ) ); od; elms:= new; @@ -189,6 +191,10 @@ BindGlobal( "AsListOfFreeLeftModule", function( V ) return elms; end ); +BindGlobal( "AsListOfFreeLeftModule", + V -> AsListOfFreeLeftModule_internal( LeftActingDomain( V ), + BasisVectors( Basis( V ) ), Zero( V ) ) ); + InstallMethod( AsList, "for a free left module", [ IsFreeLeftModule ], diff --git a/lib/oprt.gi b/lib/oprt.gi index fe1acea79d..d9d6b34a81 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -655,7 +655,7 @@ local xset,surj,G, D, act, fam, filter, hom, i,blockacttest; elif IsExternalSetByActorsRep( xset ) then filter := filter and IsActionHomomorphismByActors; elif IsMatrixGroup( G ) - and IsScalarList( D[ 1 ] ) then + and ( IsScalarList( D[ 1 ] ) or IsVectorObj( D[ 1 ] ) ) then if act in [ OnPoints, OnRight ] then # we act linearly. This might be used to compute preimages by linear # algebra @@ -3380,7 +3380,7 @@ end ); InstallMethod( PreImagesRepresentative,"IsLinearActionHomomorphism", FamRangeEqFamElm, [ IsLinearActionHomomorphism, IsPerm ], 0, function( hom, elm ) - local V, xset,lab,f; + local V, G, Grep, xset,lab,f; # is this method applicable? Test whether the domain contains a vector # space basis (respectively just get this basis). @@ -3393,20 +3393,21 @@ function( hom, elm ) #if not elm in Image( hom ) then return fail; fi; xset:=UnderlyingExternalSet(hom); V := HomeEnumerator(xset); - f:=DefaultFieldOfMatrixGroup(Source(hom)); + G:= Source( hom ); + Grep:= Representative( G ); + f:=DefaultFieldOfMatrixGroup(G); if not IsBound(hom!.linActBasisPositions) then hom!.linActBasisPositions:=List(lab,i->PositionCanonical(V,i)); fi; if not IsBound(hom!.linActInverse) then - lab:=ImmutableMatrix(f,lab); + lab:=ImmutableMatrix(f, Matrix( lab, Grep )); hom!.linActInverse:=Inverse(lab); fi; elm:=OnTuples(hom!.linActBasisPositions,elm); # image points elm:=V{elm}; # the corresponding vectors - f:=DefaultFieldOfMatrixGroup(Source(hom)); - elm:=ImmutableMatrix(f,elm); + elm:=ImmutableMatrix(f, Matrix( elm, Grep )); return hom!.linActInverse*elm; end ); @@ -3415,10 +3416,29 @@ end ); ## #M PreImagesRepresentative( , ) . . . . . . . . . . build matrix ## +## The idea is as follows. +## We have an $F$-basis $(v_1, \ldots, v_n)$. +## The matrix $M \in GL(n, F)$ acts first by right multiplication, +## let $w_i = v_i M$. +## Due to the projective action, we know only the normed vectors $c_i w_i$, +## where $c_i \in F \setminus \{ 0 \}$. +## The data computed by 'LinearActionBasis' (if its result is not 'fail') +## provide a vector $v = \sum_i a_i v_i$ such that all $a_i \not= 0$, +## and we know the normed vector $c w$ where $w = v M$ and $c \in F$. +## +## We can compute the decomposition $c w = \sum_i b_i (c_i w_i)$, +## and get $\sum_i b_i (c_i w_i) = c v M = c \sum_i a_i w_i$, +## which means $c_i = c a_i/b_i$ for all $i$. +## Thus we can reconstruct the matrix $M$ up to the scalar factor $c$. +## +## In the cases that are supported, either $c$ is irrelevant because the +## matrix group contains all scalar matrices, or we know that the preimage +## has determinant $1$ and taking the root in question is unique. +## InstallMethod( PreImagesRepresentative,"IsProjectiveActionHomomorphism", FamRangeEqFamElm, [ IsProjectiveActionHomomorphism, IsPerm ], 0, function( hom, elm ) - local V, mat, xset,lab,f,dim,sol,i; + local V, G, Grep, mat, xset,lab,dim,sol,i; # is this method applicable? Test whether field # finite, that the domain contains a vector @@ -3435,18 +3455,19 @@ function( hom, elm ) #if not elm in Image( hom ) then return fail; fi; xset:=UnderlyingExternalSet(hom); V := HomeEnumerator(xset); - f:=DefaultFieldOfMatrixGroup(Source(hom)); - dim:=DimensionOfMatrixGroup(Source(hom)); + G:= Source( hom ); + Grep:= Representative( G ); + dim:=DimensionOfMatrixGroup(G); elm:=OnTuples(hom!.projActBasisPositions,elm); # image points elm:=V{elm}; # the corresponding vectors - mat:=elm{[1..dim]}; + mat:= Matrix( List( elm{ [ 1 .. dim ] }, ShallowCopy ), Grep ); sol:=SolutionMat(mat,elm[dim+1]); for i in [1..dim] do - mat[i]:=sol[i]*mat[i]; + MultMatrixRow( mat, i, sol[i] ); od; - mat:=hom!.projActInverse*ImmutableMatrix(f,mat); + mat:= hom!.projActInverse * mat; # correct scalar using determinant if needed if hom!.correctionFactors[1]<>fail then @@ -3457,7 +3478,7 @@ function( hom, elm ) fi; fi; - return mat; + return MakeImmutable( mat ); end); ############################################################################# @@ -3467,18 +3488,24 @@ end); InstallMethod(LinearActionBasis,"find basis in domain",true, [IsLinearActionHomomorphism],0, function(hom) -local xset,D,b,t,i,r,pos; +local xset, base, M, D, b, t, i, r, pos, v; xset:=UnderlyingExternalSet(hom); if Size(xset)=0 then return fail; fi; - pos:=[]; # if there is a base, check whether it's full rank, if yes, take it - if HasBaseOfGroup(xset) - and RankMat(BaseOfGroup(xset))=Length(BaseOfGroup(xset)[1]) then - # this implies injectivity - SetIsInjective(hom,true); - return BaseOfGroup(xset); + if HasBaseOfGroup(xset) then + base:= BaseOfGroup(xset); + if IsMatrix( base ) then + M:= base; + elif ForAll( base, IsVectorObj ) then + M:= Matrix( BaseOfGroup( xset ), One( ActingDomain( xset ) ) ); + fi; + if RankMat( M ) = NrCols( M ) then + # this implies injectivity + SetIsInjective(hom,true); + return base; + fi; fi; # otherwise we've to find a basis from the domain. D:=HomeEnumerator(xset); @@ -3486,12 +3513,15 @@ local xset,D,b,t,i,r,pos; t:=[]; r:=Length(D[1]); i:=1; + pos:=[]; while Length(b)Length(t) then + v:= Unpack( D[i] ); +#TODO: try to get rid of 'Unpack' + if RankMat(Concatenation(t,[v]))>Length(t) then # new indep. vector Add(b,D[i]); Add(pos,i); - Add(t,ShallowCopy(D[i])); + Add(t, v); TriangulizeMat(t); # for faster rank tests fi; i:=i+1; @@ -3532,7 +3562,7 @@ end); InstallOtherMethod(LinearActionBasis,"projective with extra vector",true, [IsProjectiveActionHomomorphism],0, function(hom) -local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; +local xset,G,Grep,D,b,t,i,r,binv,pos,dets,roots,dim,f,v; xset:=UnderlyingExternalSet(hom); if Size(xset)=0 then return fail; @@ -3540,6 +3570,7 @@ local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; # will the determinants suffice to get suitable scalars? G:= Source(hom); + Grep:= Representative( G ); dim:=DimensionOfMatrixGroup(G); f:=DefaultFieldOfMatrixGroup(G); @@ -3575,11 +3606,13 @@ local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; i:=1; pos:=[]; while Length(b)Length(t) then + v:= Unpack( D[i] ); +#TODO: try to get rid of 'Unpack' + if RankMat(Concatenation(t,[v]))>Length(t) then # new indep. vector Add(b,D[i]); Add(pos,i); - Add(t,ShallowCopy(D[i])); + Add(t,v); TriangulizeMat(t); # for faster rank tests fi; i:=i+1; @@ -3589,15 +3622,20 @@ local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; fi; # try to find a vector that has nonzero coefficients for all b - binv:=Inverse(ImmutableMatrix(f,b)); + binv:= Inverse( ImmutableMatrix( f, Matrix( b, Grep ) ) ); while i<=Length(D) do - if ForAll(D[i]*binv,x->not IsZero(x)) then + if ForAll( Unpack( D[i] * binv ), x -> not IsZero(x) ) then +#TODO: get rid of 'Unpack'? Add(b,D[i]); Add(pos,i); hom!.projActBasisPositions:=pos; - hom!.projActInverse:=ImmutableMatrix(f,binv*Inverse(DiagonalMat(D[i]*binv))); + hom!.projActInverse:= ImmutableMatrix( f, + binv * Inverse( DiagonalMatrix( D[i] * binv, binv ) ) ); hom!.correctionFactors:=[dets,roots]; - return ImmutableMatrix(f,b); + if IsScalarList( D[1] ) then + b:= ImmutableMatrix(f,b); + fi; + return b; fi; i:=i+1; od; diff --git a/lib/vspcrow.gi b/lib/vspcrow.gi index 812c16179f..05df43d515 100644 --- a/lib/vspcrow.gi +++ b/lib/vspcrow.gi @@ -1033,44 +1033,26 @@ InstallMethod( Intersection2, ############################################################################# ## -#M NormedRowVectors( ) +#M NormedRowVectors_internal( , ) ## -InstallMethod( NormedRowVectors, - "for Gaussian row space", - [ IsGaussianRowSpace ], - function( V ) - local base, # basis vectors - elms, # element list, result - elms2, # intermediate element list - F, # `LeftActingDomain( V )' - q, # `Size( F )' - fieldelms, # elements of `F' (in other succession) - j, # loop over `base' - new, # intermediate element list - pos, # position in `new' to store the next element - len, # actual length of `elms2' - i, # loop over field elements - toadd, # vector to add to known vectors - k, # loop over `elms2' - v; # one normed row vector - - if not IsFinite( V ) then - Error( "sorry, cannot compute normed vectors of infinite domain " ); - fi; +## Assume that is a list of row vectors or vector objects over +## that is in echelon form. +## +BindGlobal( "NormedRowVectors_internal", function( F, base ) + local elms, elms2, fieldelms, j, new, pos, len, i, toadd, k; - base:= Reversed( BasisVectors( CanonicalBasis( V ) ) ); if Length( base ) = 0 then return []; + elif not IsFinite( F ) then + Error( "sorry, cannot compute normed vectors over infinite domain " ); fi; + base := Reversed( base ); elms := [ base[1] ]; elms2 := [ base[1] ]; - F := LeftActingDomain( V ); - q := Size( F ); fieldelms := List( AsSSortedList( F ), x -> x - 1 ); for j in [ 1 .. Length( base ) - 1 ] do - # Here `elms2' has the form # $b_i + M = b_i + \langle b_{i+1}, \ldots, b_n \rangle$. # Compute $b_{i-1} + \bigcup_{\lambda\in F} \lambda b_i + ( b_i + M )$. @@ -1080,9 +1062,7 @@ InstallMethod( NormedRowVectors, for i in fieldelms do toadd:= base[j+1] + i * base[j]; for k in [ 1 .. len ] do - v:= elms2[k] + toadd; - v:= ImmutableVector( q, v ); - new[ pos + k ]:= v; + new[ pos + k ]:= ImmutableVector( F, elms2[k] + toadd ); od; pos:= pos + len; od; @@ -1090,9 +1070,27 @@ InstallMethod( NormedRowVectors, # `elms2' is a set here. Append( elms, elms2 ); - od; + # Return the result. + return elms; + end ); + + +############################################################################# +## +#M NormedRowVectors( ) +## +InstallMethod( NormedRowVectors, + "for Gaussian row space", + [ IsGaussianRowSpace ], + function( V ) + local base, # basis vectors + elms; # element list, result + + base:= BasisVectors( CanonicalBasis( V ) ); + elms:= NormedRowVectors_internal( LeftActingDomain( V ), base ); + # The list is strictly sorted, so we store this. MakeImmutable( elms ); Assert( 1, IsSSortedList( elms ) ); diff --git a/tst/testbugfix/2007-07-02-t00180.tst b/tst/testbugfix/2007-07-02-t00180.tst index be77f789b5..a7f8e14c7c 100644 --- a/tst/testbugfix/2007-07-02-t00180.tst +++ b/tst/testbugfix/2007-07-02-t00180.tst @@ -1,6 +1,6 @@ # 2007/07/02 (SK) gap> GeneratorsOfRing(Rationals); -Error, cannot compute elements list of infinite domain +Error, cannot compute elements list over infinite domain gap> GeneratorsOfRingWithOne(Rationals); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 2nd choice method found for `GeneratorsOfRingWithOne' on 1 arguments diff --git a/tst/testinstall/MatrixObj/DeterminantMatrix.tst b/tst/testinstall/MatrixObj/DeterminantMatrix.tst new file mode 100644 index 0000000000..8d9f63eeca --- /dev/null +++ b/tst/testinstall/MatrixObj/DeterminantMatrix.tst @@ -0,0 +1,29 @@ +#@local M, mat +gap> START_TEST( "DeterminantMatrix.tst" ); + +# nonsquare matrix +gap> mat:= [[1,2,1,2],[1,0,1,0],[2,2,2,2]];; +gap> M:= NewMatrix( IsPlistMatrixRep, GF(5), 4, mat*Z(5)^0 );; +gap> DeterminantMatrix( M ); +Error, DeterminantMat: must be a nonempty square matrix + +# 0x0 matrix +gap> M:= ZeroMatrix( IsPlistRep, GF(9), 0, 0 ); +[ ] +gap> DeterminantMatrix( M ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `DeterminantMatrix' on 1 arguments +gap> M:= ZeroMatrix( IsPlistMatrixRep, GF(9), 0, 0 ); +<0x0-matrix over GF(3^2)> +gap> DeterminantMatrix( M ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `DeterminantMatrix' on 1 arguments + +# square nonempty matrix +gap> mat:= [[1,2,1],[1,0,1],[2,2,2]];; +gap> M:= NewMatrix( IsPlistMatrixRep, GF(5), 3, mat*Z(5)^0 );; +gap> DeterminantMatrix( M ); +0*Z(5) + +# +gap> STOP_TEST( "DeterminantMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst b/tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst new file mode 100644 index 0000000000..258d6c2934 --- /dev/null +++ b/tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst @@ -0,0 +1,52 @@ +#@local rs, M +gap> START_TEST( "RandomInvertibleMatrix.tst" ); + +# with base domain +gap> Is8BitMatrixRep( RandomInvertibleMatrix( GF(9), 10 ) ); +true +gap> IsPlistMatrixRep( RandomInvertibleMatrix( Integers, 10 ) ); +true + +# with constructing filter and base domain +gap> Is8BitMatrixRep( RandomInvertibleMatrix( Is8BitMatrixRep, GF(9), 10 ) ); +true +gap> IsPlistRep( RandomInvertibleMatrix( IsPlistRep, Integers, 10 ) ); +true + +# with random source and base domain +gap> rs:= RandomSource(IsMersenneTwister);; +gap> Is8BitMatrixRep( RandomInvertibleMatrix( Is8BitMatrixRep, GF(9), 10 ) ); +true +gap> IsPlistRep( RandomInvertibleMatrix( IsPlistRep, Integers, 10 ) ); +true + +# with constructing filter, random source, and base domain +gap> Is8BitMatrixRep( RandomInvertibleMatrix( Is8BitMatrixRep, rs, GF(9), 10 ) ); +true +gap> IsPlistRep( RandomInvertibleMatrix( IsPlistRep, rs, Integers, 10 ) ); +true + +# with example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomInvertibleMatrix( 2, M ); +<2x2-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> IsPlistRep( RandomInvertibleMatrix( 2, M ) ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomInvertibleMatrix( 2, M ); +<2x2-matrix over GF(3)> + +# with random source and example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomInvertibleMatrix( rs, 2, M ); +<2x2-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> IsPlistRep( RandomInvertibleMatrix( rs, 2, M ) ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomInvertibleMatrix( rs, 2, M ); +<2x2-matrix over GF(3)> + +# +gap> STOP_TEST( "RandomInvertibleMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/RandomMatrix.tst b/tst/testinstall/MatrixObj/RandomMatrix.tst new file mode 100644 index 0000000000..d4460cf9c0 --- /dev/null +++ b/tst/testinstall/MatrixObj/RandomMatrix.tst @@ -0,0 +1,72 @@ +#@local rs, M +gap> START_TEST( "RandomMatrix.tst" ); + +# with base domain +gap> Is8BitMatrixRep( RandomMatrix( GF(9), 10, 5 ) ); +true +gap> RandomMatrix( GF(9), 0, 1 ); +Error, Is8BitMatrixRep with zero rows not yet supported +gap> IsPlistMatrixRep( RandomMatrix( Integers, 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( Integers, 0, 0 ) ); +true + +# with constructing filter and base domain +gap> Is8BitMatrixRep( RandomMatrix( Is8BitMatrixRep, GF(9), 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( IsPlistMatrixRep, GF(9), 0, 0 ) ); +true +gap> IsPlistRep( RandomMatrix( IsPlistRep, Integers, 10, 5 ) ); +true + +# with random source and base domain +gap> rs:= RandomSource(IsMersenneTwister);; +gap> Is8BitMatrixRep( RandomMatrix( Is8BitMatrixRep, GF(9), 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( IsPlistMatrixRep, GF(9), 0, 0 ) ); +true +gap> IsPlistRep( RandomMatrix( IsPlistRep, Integers, 10, 5 ) ); +true + +# with constructing filter, random source, and base domain +gap> Is8BitMatrixRep( RandomMatrix( Is8BitMatrixRep, rs, GF(9), 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( IsPlistMatrixRep, rs, GF(9), 0, 0 ) ); +true +gap> IsPlistRep( RandomMatrix( IsPlistRep, rs, Integers, 10, 5 ) ); +true + +# with example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomMatrix( 2, 2, M ); +<2x2-matrix over Integers> +gap> RandomMatrix( 0, 0, M ); +<0x0-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> BaseDomain( M ); +Rationals +gap> IsPlistRep( RandomMatrix( 2, 2, M ) ); +true +gap> ForAll( Flat( RandomMatrix( 1, 2, M ) ), IsRat ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomMatrix( 2, 2, M ); +<2x2-matrix over GF(3)> + +# with random source and example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomMatrix( rs, 2, 2, M ); +<2x2-matrix over Integers> +gap> RandomMatrix( rs, 0, 0, M ); +<0x0-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> IsPlistRep( RandomMatrix( rs, 2, 2, M ) ); +true +gap> ForAll( Flat( RandomMatrix( rs, 1, 2, M ) ), IsRat ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomMatrix( rs, 2, 2, M ); +<2x2-matrix over GF(3)> + +# +gap> STOP_TEST( "RandomMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/RankMatrix.tst b/tst/testinstall/MatrixObj/RankMatrix.tst new file mode 100644 index 0000000000..d8561b2806 --- /dev/null +++ b/tst/testinstall/MatrixObj/RankMatrix.tst @@ -0,0 +1,23 @@ +#@local M, mat +gap> START_TEST( "RankMatrix.tst" ); + +# nonsquare matrix +gap> mat:= [[1,2,1,2],[1,0,1,0],[2,2,2,2]];; +gap> M:= NewMatrix( IsPlistMatrixRep, GF(5), 4, mat*Z(5)^0 ); +<3x4-matrix over GF(5)> +gap> RankMatrix( M ); +2 + +# 0x0 matrix +gap> M:= ZeroMatrix( IsPlistRep, GF(9), 0, 0 ); +[ ] +gap> RankMatrix( M ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `RankMatrix' on 1 arguments +gap> M:= ZeroMatrix( IsPlistMatrixRep, GF(9), 0, 0 ); +<0x0-matrix over GF(3^2)> +gap> RankMatrix( M ); +0 + +# +gap> STOP_TEST( "RankMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/acthom.tst b/tst/testinstall/MatrixObj/acthom.tst new file mode 100644 index 0000000000..6f7e73ed3e --- /dev/null +++ b/tst/testinstall/MatrixObj/acthom.tst @@ -0,0 +1,80 @@ +#@local right_representation, q, F, d, filt, groups, G, basis, xset, vectors +#@local orbs, len, D1, v, D2, D3, D4, actions, D, hom, i, g, img, pre +gap> START_TEST( "acthom.tst" ); + +# +gap> right_representation:= function( filt, g ) +> return ( filt = IsPlistRep and IsList( g ) ) or +> ( filt <> IsPlistRep and filt( g ) ); +> end;; +gap> for q in [ 2, 3, 4 ] do +> F:= GF(q); +> for d in [ 2 .. 4 ] do +> for filt in [ IsPlistRep, IsPlistMatrixRep ] do +> PushOptions( rec( ConstructingFilter:= filt ) ); +> # Test groups with special methods and a general group. +> groups:= [ GL( d, F ), SL( d, F ) ]; +> # Add( groups, SylowSubgroup( groups[1], 2 ) ); +> # Add( groups, Subgroup( groups[1], +> # [ GeneratorsOfGroup( groups[1] )[1] ] ) ); +> for G in groups do +> # Consider the G-action +> # - given by the nice monomorphism +> # - on an orbit (linear & projective) +> # - on the whole natural G-set (linear & projective) +> basis:= RowsOfMatrix( One( G ) ); +> xset:= ExternalSet( G ); +> vectors:= HomeEnumerator( xset ); +> orbs:= Orbits( G, vectors ); +> len:= Maximum( List( orbs, Length ) ); +> D1:= [ First( orbs, x -> Length( x ) = len ), OnRight ]; +> v:= OnLines( D1[1][1], One( G ) ); +> D2:= [ Orbit( G, v, OnLines ), OnLines ]; +> D3:= [ vectors, OnRight ]; +> D4:= [ NormedRowVectors_internal( F, basis ), OnLines ]; +> +> actions:= [ NiceMonomorphism( G ) ]; +> for D in [ D1, D2, D3, D4 ] do +> if not CompatibleVectorFilter( One( G ) )( D[1][1] ) then +> Error( "wrong repres. of vector for ", [ q, d, filt ] ); +> fi; +> hom:= ActionHomomorphism( G, D[1], D[2] ); +> if D[2] <> OnLines and +> not IsLinearActionHomomorphism( hom ) then +> Error( "unexpected type of action hom. for ", +> [ q, d, filt ] ); +> fi; +> Add( actions, hom ); +> od; +> +> for hom in actions do +> for i in [ 1 .. 5 ] do +> g:= Random( G ); +> if not right_representation( filt, g ) then +> Error( "wrong repres. of random matrix for ", +> [ q, d, filt ] ); +> fi; +> img:= g^hom; +> pre:= PreImagesRepresentative( hom, img ); +> if not right_representation( filt, pre ) then +> Error( "wrong repres. of preimage matrix for ", +> [ q, d, filt ] ); +> fi; +> if FunctionAction( UnderlyingExternalSet( hom ) ) = OnLines then +> if not ( pre / g in Centre( G ) ) then +> Error( "problem with projective action for ", +> [ q, d, filt ] ); +> fi; +> elif pre <> g then +> Error( "problem with linear action for ", +> [ q, d, filt ] ); +> fi; +> od; +> od; +> od; +> od; +> od; +> od; + +# +gap> STOP_TEST( "acthom.tst" ); diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index 31b192e7ba..4c23741723 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -1,4 +1,4 @@ -#@local cl,g,gd,gens,hom,i,img,iso,pcgs,u,G,F,o,a,m,nice,H +#@local cl,g,gd,gens,hom,i,img,iso,pcgs,u,G,F,o,a,m,nice,H,G2,nice2 gap> START_TEST("grpmat.tst"); gap> i := E(4);; G := Group([[i,0],[0,-i]],[[0,1],[-1,0]]);; gap> gens := GeneratorsOfGroup( G );; IsSSortedList( gens ); @@ -89,5 +89,21 @@ gap> TrivialSubgroup( GL(2, 2) ); gap> Length( LowIndexSubgroups( GL(2,5), 50 ) ) = 31; true +# 'NiceMonomorphism' behaves well w.r.t. 'ConstructingFilter' +gap> G:= SP( 4, 2 );; +gap> nice:= NiceMonomorphism( G );; +gap> G2:= SP( 4, 2 : ConstructingFilter:= IsPlistMatrixRep );; +gap> nice2:= NiceMonomorphism( G2 );; +gap> IsPlistMatrixRep( One( G ) ); +false +gap> IsPlistMatrixRep( One( G2 ) ); +true +gap> IsIdenticalObj( nice, nice2 ); +false +gap> IsSubset( Source( nice ), G ); +true +gap> IsSubset( Source( nice2 ), G2 ); +true + # gap> STOP_TEST( "grpmat.tst" ); From ce32e7883132cf1119db4bb7be44b2caacd4baea Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 22 Apr 2026 02:25:33 +0200 Subject: [PATCH 035/123] Faster {Copy,Extract}Sub{Matrix,Vector} for plist matrices/vectors (#6329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... by avoiding some method dispatch, providing optimized methods using `{...}` syntax, and turning ExtractSubVector, CopySubVector, ExtractSubMatrix, and CopySubMatrix into kernel ops. Then run some benchmarks via `benchmark/matobj/bench-submat.g` and the new `benchmark/matobj/bench-subvec.g`. Before: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 129 µs per iteration; 7749 iterations per second; (200 iterations) Testing ExtractSubMatrix: 720 µs per iteration; 1388 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 342 µs per iteration; 2921 iterations per second; (200 iterations) Testing CopySubMatrix: 1032 µs per iteration; 969 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 167 µs per iteration; 5999 iterations per second; (200 iterations) Testing ExtractSubMatrix: 3288 µs per iteration; 304 iterations per second; (92 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1992 µs per iteration; 502 iterations per second; (151 iterations) Testing CopySubMatrix: 2606 µs per iteration; 384 iterations per second; (116 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 393 µs per iteration; 2542 iterations per second; (200 iterations) Testing CopySubVector: 2324 µs per iteration; 430 iterations per second; (130 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 441 µs per iteration; 2266 iterations per second; (200 iterations) Testing CopySubVector: 2458 µs per iteration; 407 iterations per second; (123 iterations) After: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 136 µs per iteration; 7355 iterations per second; (200 iterations) Testing ExtractSubMatrix: 140 µs per iteration; 7135 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 301 µs per iteration; 3319 iterations per second; (200 iterations) Testing CopySubMatrix: 299 µs per iteration; 3347 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 154 µs per iteration; 6490 iterations per second; (200 iterations) Testing ExtractSubMatrix: 146 µs per iteration; 6854 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1895 µs per iteration; 528 iterations per second; (159 iterations) Testing CopySubMatrix: 1935 µs per iteration; 517 iterations per second; (156 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 428 µs per iteration; 2336 iterations per second; (200 iterations) Testing CopySubVector: 453 µs per iteration; 2209 iterations per second; (200 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 427 µs per iteration; 2344 iterations per second; (200 iterations) Testing CopySubVector: 460 µs per iteration; 2172 iterations per second; (200 iterations) So overall the Copy/Extract methods are now more or less on par with the code using `{...}` syntax. But actually this `ExtractSubMatrix` for a GF(2) rowlist is now *faster* than the optimized one for a compressed GF(2) matrix: +----------------------------------------------------------+ | Testing submatrix extraction for GF(2) compressed matrix | +----------------------------------------------------------+ Testing m{}{}: 1057 µs per iteration; 946 iterations per second; (200 iterations) Testing ExtractSubMatrix: 1618 µs per iteration; 618 iterations per second; (186 iterations) A substantial part of that is due to the the `ExtractSubMatrix` method for `IsGF2MatrixRep` calling `ConvertToMatrixRepNC(mm,2)`; after removing that, it went down from 1618 to 392 µs (which is still worse). --- AI assistance: Codex implemented the kernel plumbing, method cleanup, and test updates. It also created `benchmark/matobj/bench-subvec.g`. Co-authored-by: Codex --- .../MatrixObj/ExtractSubMatrix.tst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 35517c5f25..b73e17a196 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -1,8 +1,10 @@ gap> START_TEST("ExtractSubMatrix.tst"); + gap> IsBoundGlobal("EXTRACT_SUB_MATRIX"); true gap> EXTRACT_SUB_MATRIX = ExtractSubMatrix; true + gap> m1 := [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]; [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); @@ -10,4 +12,21 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] + +# IsGF2MatrixRep +gap> m1 := IdentityMatrix( GF(2), 100 ); + +gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); + +gap> IsOne(m2); +true + +# Is8BitMatrixRep +gap> m1 := IdentityMatrix( GF(3), 100 ); +< mutable compressed matrix 100x100 over GF(3) > +gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); +< mutable compressed matrix 20x20 over GF(3) > +gap> IsOne(m2); +true + gap> STOP_TEST("ExtractSubMatrix.tst"); From c23216d2ded18ab04eaaa8b05757ba9bb06d3040 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 5 May 2026 09:16:38 +0100 Subject: [PATCH 036/123] ChangeBaseDomain --- lib/matobj2.gd | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 1405092d67..9869c1186e 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -388,6 +388,12 @@ DeclareOperation( "ListOp", [ IsVectorObj, IsFunction ] ); ##

## Changing the result does not change v or M, respectively. ## The entries themselves are not copied. +##

+## m1 := Matrix( Integers, [ [1,2,3,4], [6,7,8,9] ] );; +## gap> Unpack( m1 ); +## [ [ 1, 2, 3, 4 ], [ 6, 7, 8, 9 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -927,6 +933,17 @@ DeclareTagBasedOperation( "NewIdentityMatrix", ##

## For example, one can create a vector defined over GF(4) ## from a vector defined over GF(2) with this operation. +##

+## v1 := Vector( Integers, [ 3, 5, 7, 9 ] );; +## gap> ChangedBaseDomain( v1, Rationals ); +## +## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +## gap> m64 := ChangedBaseDomain( m6, GF(4) ); +## [ [ Z(2)^0, 0*Z(2), Z(2)^0 ], [ 0*Z(2), Z(2)^0, 0*Z(2) ] ] +## gap> ConstructingFilter( m64 ); +## +## ]]> ## ## ## <#/GAPDoc> @@ -996,6 +1013,13 @@ DeclareOperation( "Randomize", [ IsRandomSource, IsMatrixOrMatrixObj and IsMutab ##

## If the global option check is set to false then ## need not perform consistency checks. +##

+## v1 := Vector( Integers, [ 2,3,5,6,8,9 ] );; +## gap> v2 := Vector( Integers, [ 9,8,6,5,3,2 ] );; +## gap> CopySubVector( v1, v2, [2..4], [3..5] ); Print( v2 ); +## NewVector(IsPlistVectorRep,Integers,[ 9, 8, 3, 5, 6, 2 ]) +## ]]> ## ## ## <#/GAPDoc> @@ -1303,7 +1327,6 @@ DeclareOperation( "ZeroMatrix", [ IsOperation, IsSemiring, IsInt, IsInt ] ); ## 1 . . ## . 1 . ## . . 1 -## ]> ## ]]> ## ## From e0a1dbc83ae94968028a6bfa252fb19e16a91c8e Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 7 May 2026 09:29:50 +0100 Subject: [PATCH 037/123] examples up to and including 26.10 --- lib/matobj.gi | 32 + lib/matobj2.gd | 1648 +++++++++++++++++++++++++----------------------- 2 files changed, 903 insertions(+), 777 deletions(-) diff --git a/lib/matobj.gi b/lib/matobj.gi index 35ae1ccbe0..ca1c152681 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -885,6 +885,23 @@ end ); ## otherwise it is not specified what happens. ## If the result is a vector object then it has the same representation and ## the same base domain as the given vector object(s). +##

+## v1 := Vector( Rationals, [-1,-1/2,0,1/2,1] );; Print( v1 ); +## NewVector(IsPlistVectorRep,Rationals,[ -1, -1/2, 0, 1/2, 1 ]) +## gap> v2 := Vector( [0,1,2,4,8], v1 );; Print( v2 ); +## NewVector(IsPlistVectorRep,Rationals,[ 0, 1, 2, 4, 8 ]) +## gap> Print( v1 + v2 ); +## NewVector(IsPlistVectorRep,Rationals,[ -1, 1/2, 2, 9/2, 9 ]) +## gap> Unpack( v2 - v1 ); +## [ 1, 3/2, 2, 7/2, 7 ] +## gap> Unpack( 2 * v1 ); Unpack( v1 * 4 ); Unpack( v2 / 4 ); +## [ -2, -1, 0, 1, 2 ] +## [ -4, -2, 0, 2, 4 ] +## [ 0, 1/4, 1/2, 1, 2 ] +## gap> v1 * v2; +## 19/2 +## ]]> ## ## ## <#/GAPDoc> @@ -1123,6 +1140,21 @@ InstallMethod( MultVectorRight, ## otherwise it is not specified what happens. ## If the result is a matrix object then it has the same representation and ## the same base domain as the given matrix object(s). +##

+## m1 := Matrix( Rationals, [ [3,4,5], [6,7,8] ] );; +## gap> m2 := Matrix( [ [1,0,1], [0,1,0] ], m1 );; +## gap> Print( m1 + m2, "\n", m1 - m2 ); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 4, 4, 6 ], [ 6, 8, 8 ] ]) +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 2, 4, 4 ], [ 6, 6, 8 ] ]) +## gap> Unpack( 3 * m2 ); Unpack( m2 * 5 ); Unpack( m2 / 2 ); +## [ [ 3, 0, 3 ], [ 0, 3, 0 ] ] +## [ [ 5, 0, 5 ], [ 0, 5, 0 ] ] +## [ [ 1/2, 0, 1/2 ], [ 0, 1/2, 0 ] ] +## gap> m3 := Matrix( [ [1,1], [0,1] ], m1 );; +## gap> Print( m3 * m1 ); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 9, 11, 13 ], [ 6, 7, 8 ] ]) +## ]]> ## ## ## <#/GAPDoc> diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 9869c1186e..cf2798a88c 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -155,24 +155,6 @@ ## -############################################################################# -## -#A Length( ) -## -## <#GAPDoc Label="Length_IsVectorObj"> -## -## -## -## -## returns the length of the vector object v, -## which is defined to be the number of entries of v. -## -## -## <#/GAPDoc> -## -DeclareAttribute( "Length", IsVectorObj ); - - ############################################################################# ## #A ConstructingFilter( ) @@ -245,126 +227,609 @@ DeclareAttribute( "CompatibleVectorFilter", IsMatrixOrMatrixObj ); ############################################################################# ## -## List Like Operations for Vector Objects +#A Length( ) +## +## <#GAPDoc Label="Length_IsVectorObj"> +## +## ## +## +## returns the length of the vector object v, +## which is defined to be the number of entries of v. +## +## +## <#/GAPDoc> +## +DeclareAttribute( "Length", IsVectorObj ); ############################################################################# ## -#O \[\]( , ) -#O \[\]\:\=( , , ) -#O \{\}( , ) +#O Vector( , , ) +#O Vector( , ) +#O Vector( , , ) +#O Vector( , ) +#O Vector( , ) +#O Vector( , ) ## -## <#GAPDoc Label="ElementAccessVectorObj"> +## <#GAPDoc Label="Vector"> ## -## Element Access and Assignment for Vector Objects -## -## -## -## +## Vector +## +## +## +## +## ## +## a vector object ## -## For a vector object v and a positive integer i that is -## not larger than the length of v -## (see ), -## v[i] is the entry at position i. +## If a filter filt is given as the first argument then +## a vector object is returned that has +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the vector object +## vecobj, respectively. ##

-## If v is mutable, i is as above, and obj is an object -## from the base domain of v then -## v[i]:= obj assigns obj to the -## i-th position of v. +## If a semiring R is given as the first argument then +## a vector object is returned whose +## +## value is guessed from R, again with base domain R +## and entries given by the last argument. ##

-## If list is a list of positive integers that are not larger than -## the length of v then -## v{list} returns a new mutable vector object -## in the same representation as v -## (see ) -## that contains the list[ k ]-th entry of v at -## position k. +## In the remaining cases with two arguments, +## the first argument is a list or a vector object +## that defines the entries of the result, +## and the second argument is a vector object whose +## and +## are taken for the +## result. +##

+## The variant +## Vector( vecobj, vecobj_example ) +## is supported also for the case that vecobj is a row vector +## but not a vector object. +## In this situation, the result is a row vector that is equal to +## vecobj and whose +## and +## +## are taken from the example. +##

+## If only a list list is given then both the +## and the +## are guessed from +## this list. ##

## If the global option check is set to false then -## +## ## need not perform consistency checks. ##

-## Note that the sublist assignment operation -## is left out here since it tempts the programmer to use constructions like -## v{ [ 1 .. 3 ] }:= w{ [ 4 .. 6 ] } -## which produces an unnecessary intermediate object; -## one should use instead. +## If the +## value of the result implies then the result is +## mutable if and only if the argument that determines the entries of the +## result (list, v, v1) is mutable. +##

+## In the case of a mutable result, it is not guaranteed that +## the given list of entries is copied. +##

+## Default methods for +## +## delegate to . +##

+## v1 := Vector( Integers, [3,4,7,8] );; Print( v1 ); +## NewVector(IsPlistVectorRep,Integers,[ 3, 4, 7, 8 ]) +## gap> v2 := Vector( Rationals, v1 );; Print( v2 ); +## NewVector(IsPlistVectorRep,Rationals,[ 3, 4, 7, 8 ]) +## gap> v3 := Vector( [ 11..13], v1) ;; Print( v3 ); +## NewVector(IsPlistVectorRep,Integers,[ 11, 12, 13 ]) +## gap> v0 := [6..9];; IsVector( v0 ); +## true +## gap> Print( Vector( v0, v1 ) ); +## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) +## gap> v4 := Vector( [ 2, 5/2, 7/3, 3 ] );; Print( v4 ); +## NewVector(IsPlistVectorRep,Rationals,[ 2, 5/2, 7/3, 3 ]) +## gap> v5 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; +## gap> Print( v5 ); +## [ 0*Z(2), Z(2)^0, 0*Z(2) ] +## gap> v6 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 ); +## +## gap> BaseDomain( v6 ); +## (Integers mod 8) +## gap> v7 := Vector( IsZmodnZVectorRep, ZmodnZ(12), v0 ); +## +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "[]", [ IsVectorObj, IsPosInt ] ); - -DeclareOperation( "[]:=", [ IsVectorObj, IsPosInt, IsObject ] ); - -DeclareOperation( "{}", [ IsVectorObj, IsList ] ); +DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsList ] ); +DeclareOperation( "Vector", [ IsSemiring, IsList ] ); +DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsVectorObj ] ); +DeclareOperation( "Vector", [ IsSemiring, IsVectorObj ] ); +DeclareOperation( "Vector", [ IsList, IsVectorObj ] ); +DeclareOperation( "Vector", [ IsVectorObj, IsVectorObj ] ); +DeclareOperation( "Vector", [ IsList ] ); ############################################################################# ## -## <#GAPDoc Label="MatObj_PositionNonZero"> -## -## -## -## An integer -## -## Returns the index of the first entry in the vector object v -## that is not zero. -## If all entries are zero, -## the function returns Length(v) + 1. -## -## -## <#/GAPDoc> -## -DeclareOperation( "PositionNonZero", [ IsVectorObj ] ); - - -############################################################################# +#O ZeroVector( , ) +#O ZeroVector( , ) +#O ZeroVector( , ) +#O ZeroVector( , , ) ## -## <#GAPDoc Label="MatObj_PositionLastNonZero"> +## <#GAPDoc Label="VectorObj_ZeroVector"> ## -## +## ZeroVector +## +## +## +## ## -## An integer +## a vector object ## -## Returns the index of the last entry in the vector object v -## that is not zero. -## If all entries are zero, the function returns 0. +## For a semiring R and a nonnegative integer len, +## this operation returns a new vector object of length len +## over R in the representation filt containing only zeros. +## &GAP; guesses a suitable representation. +##

+## For a vector object v and a nonnegative integer len, +## this operation returns a new vector object of length len +## in the same representation as v containing only zeros. +##

+## For a matrix object M and a nonnegative integer len, +## this operation returns a new zero vector object of length +## len in the representation given by the +## value +## of M, provided that such a representation exists. +##

+## For a filter filt, a semiring R and a nonnegative integer +## len, this operation returns a new vector object of length +## len over R in the representation filt +## containing only zeros. +##

+## If the +## value of the result implies then the result is +## mutable. +##

+## Default methods for +## +## delegate to . +##

+## z1 := ZeroVector( Rationals, 4 );; Print( z1 ); +## NewVector(IsPlistVectorRep,Rationals,[ 0, 0, 0, 0 ]) +## gap> v5 := Vector( GF(5), [3,4]*Z(5) );; z5 := ZeroVector(3,v5);; Print(z5); +## [ 0*Z(5), 0*Z(5), 0*Z(5) ] +## gap> m6:=Matrix(Integers,[[1,3],[5,7]]);; z6:=ZeroVector(6,m6);; Print(z6); +## NewVector(IsPlistVectorRep,Integers,[ 0, 0, 0, 0, 0, 0 ]) +## gap> z8 := ZeroVector( IsZmodnZVectorRep, ZmodnZ(8), 4 );; Print( z8 ); +## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 0, 0, 0, 0 ]) +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "PositionLastNonZero", [ IsVectorObj ] ); +DeclareOperation( "ZeroVector", [ IsSemiring, IsInt ] ); +DeclareOperation( "ZeroVector", [ IsInt, IsVecOrMatObj ] ); +DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); +#DeclareOperation( "ZeroVector", [ IsInt, IsVectorObj ] ); +#DeclareOperation( "ZeroVector", [ IsInt, IsMatrixOrMatrixObj ] ); ############################################################################# ## -#O ListOp( [, ] ) +#O NewVector( , , ) +#O NewZeroVector( , , ) ## -## <#GAPDoc Label="MatObj_ListOp"> +## <#GAPDoc Label="NewVector"> ## -## +## NewVector and NewZeroVector +## +## ## -## A plain list ## -## Applies the function func to each entry of the vector object -## v and returns the results as a mutable plain list. -## This allows for calling -## on vector objects. +## These two operations are constructors, and should only be used +## when or +## +## do not give the desired result. ##

-## If the argument func is not given, -## applies to all entries. -## -## -## <#/GAPDoc> -## -DeclareOperation( "ListOp", [ IsVectorObj ] ); -DeclareOperation( "ListOp", [ IsVectorObj, IsFunction ] ); +## For a filter filt, a semiring R, and a list list +## of elements that belong to R, +## returns a vector object which has +## the +## filt, +## the R, +## and the entries in list. +## The list list is guaranteed not to be changed by this operation. +##

+## If the global option check is set to false then +## need not perform consistency checks. +##

+## Similarly, returns a vector object +## of length n which has filt and R as +## and +## values, +## and contains the zero of R in each position. +##

+## The returned object is mutable if and only if filt implies +## . +##

+## v := NewVector( IsGF2VectorRep, GF(2), [1,0,1,0,1]*Z(2) ); +## +## gap> Print(v); +## [ Z(2)^0, 0*Z(2), Z(2)^0, 0*Z(2), Z(2)^0 ] +## gap> NewZeroVector( IsZmodnZVectorRep, ZmodnZ(7), 5 ); +## +## ]]> +## +## +## <#/GAPDoc> +## +DeclareTagBasedOperation( "NewVector", [ IsOperation, IsSemiring, IsList ] ); + +DeclareTagBasedOperation( "NewZeroVector", + [ IsOperation, IsSemiring, IsInt ] ); + + +############################################################################# +## +#O Matrix( , , , ) +#O Matrix( , , ) +#O Matrix( , , ) +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , ) +#O Matrix( , ) +#O Matrix( , ) +#O Matrix( ) +## +## <#GAPDoc Label="MatObj_Matrix"> +## +## Matrix +## +## +## +## +## +## +## a matrix object +## +## If a filter filt is given as the first argument +## then a matrix object is returned that has +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list +## or the matrix object matobj, respectively. +## Here list can be either a list of plain lists that describe the +## entries of the rows, or a flat list of the entries in row major order, +## where ncols defines the number of columns. +##

+## If a semiring R is given as the first argument then +## a matrix object is returned whose +## +## value filt is guessed from R, +## again with base domain R and entries given by the last argument. +##

+## In those cases where the last argument is a matrix object, +## the first argument is a list or a matrix object +## that defines the entries of the result, then the +## and +## +## of the last argument are taken for the result. +##

+## Finally, if only a list list and perhaps ncols is given +## then both the +## and the +## are guessed from +## the list. +##

+## If the global option check is set to false then +## +## need not perform consistency checks. +##

+## If the +## value of the result implies then the result is +## mutable if and only if the argument that determines the entries of the +## result (list or matobj) is mutable. +##

+## In the case of a mutable result, it is guaranteed that the given list +## list is copied in the sense of , +## and if list is a nested list then it is not guaranteed +## that also the entries of list are copied. +##

+## Default methods for +## +## delegate to . +##

+## m1 := Matrix( Integers, [ [3,4,5], [6,7,8] ] );; Print( m1 ); +## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ 3, 4, 5 ], [ 6, 7, 8 ] ]) +## gap> m2 := Matrix( Rationals, [10..30], 7 );; Display( m2 ); +## <3x7-matrix over Rationals: +## [[ 10 .. 16 ] +## [ 17 .. 23 ] +## [ 24 .. 30 ] +## ]> +## gap> Print( Matrix( Integers, m2 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,7, +## [ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) +## gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); +## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) +## gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) +## gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); +## true +## gap> Print( Matrix( m0, m1 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) +## gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) +## gap> Print( Matrix( [-9..-4], 3, m1 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) +## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +## gap> Display( m6 ); +## 1 . 1 +## . 1 . +## gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); +## +## gap> m8 := Matrix( IsZmodnZMatrixRep, ZmodnZ(12), m0 ); +## +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList ] ); +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsList ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsList ]); + + +############################################################################# +## +#O ZeroMatrix( , , ) +#O ZeroMatrix( , , ) +#O ZeroMatrix( , , , ) +## +## <#GAPDoc Label="MatObj_ZeroMatrix"> +## +## ZeroMatrix +## +## +## +## +## a matrix object +## +## For a matrix object M and two nonnegative integers m +## and n, this operation returns a new matrix object +## with m rows and n columns +## in the same representation and over the same base domain as M +## containing only zeros. +##

+## If a semiring R and two nonnegative integers m and +## n are given, +## the representation of the result is guessed from R. +##

+## If a filter filt and a semiring R are given as the first +## and second argument, they are taken as the values of +## and +## of the result. +##

+## If the +## value of the result implies then the result is +## fully mutable. +##

+## Default methods for +## +## delegate to . +##

+## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; +## gap> z7 := ZeroMatrix( 2, 2, m7 );; Print( z7 ); +## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, +## [ [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ], +## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ] ]) +## gap> z23 := ZeroMatrix( Rationals, 2, 3 );; Print( z23 ); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 0, 0 ], [ 0, 0, 0 ] ]) +## gap> z5 := ZeroMatrix( IsGF2MatrixRep, GF(2), 2, 5 );; Display( z5 ); +## . . . . . +## . . . . . +## ]> +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "ZeroMatrix", [ IsInt, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "ZeroMatrix", [ IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "ZeroMatrix", [ IsOperation, IsSemiring, IsInt, IsInt ] ); + + +############################################################################# +## +#O IdentityMatrix( , ) +#O IdentityMatrix( , ) +#O IdentityMatrix( , , ) +## +## <#GAPDoc Label="MatObj_IdentityMatrix"> +## +## IdentityMatrix +## +## +## +## +## a matrix object +## +## For a matrix object M and a nonnegative integer n, +## this operation returns a new identity matrix object +## with n rows and columns +## in the same representation and over the same base domain as M. +##

+## If a semiring R and a nonnegative integer n is given, +## the representation of the result is guessed from R. +##

+## If a filter filt and a semiring R are given as the first +## and second argument, they are taken as the values of +## and +## of the result. +##

+## If the +## value of the result implies then the result is +## fully mutable. +##

+## Default methods for +## +## delegate to . +##

+## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; +## gap> id7 := IdentityMatrix( 2, m7 );; Print( id7 ); +## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, +## [ [ ZmodnZObj( 1, 8 ), ZmodnZObj( 0, 8 ) ], +## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 1, 8 ) ] ]) +## gap> id2 := IdentityMatrix( Rationals, 2 );; Print( id2 ); +## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 1, 0 ], [ 0, 1 ] ]) +## gap> id3 := IdentityMatrix( IsGF2MatrixRep, GF(2), 3 );; Display( id3 ); +## 1 . . +## . 1 . +## . . 1 +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "IdentityMatrix", [ IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "IdentityMatrix", [ IsSemiring, IsInt ] ); +DeclareOperation( "IdentityMatrix", [ IsOperation, IsSemiring, IsInt ] ); + + +############################################################################# +## +#O NewMatrix( , , , ) +#O NewMatrix( , , , ) +#O NewMatrix( , , ) +#O NewZeroMatrix( , , , ) +#O NewIdentityMatrix( , , ) +## +## <#GAPDoc Label="NewMatrix"> +## +## NewMatrix, NewZeroMatrix, NewIdentityMatrix +## +## +## +## +## +## +## +## These three operations are constructors, and should only be used +## by those implementing new material for matrix objects. +## Most users should find +## , +## or +## +## sufficient for their requirements. +##

+## For a filter filt, a semiring R, +## a positive integer ncols, and a list list, +## returns a matrix object which has +## the +## filt, +## the R, +## n columns +## (see ), +## and the entries described by list, +## which can be either a plain list of vector objects of length ncols +## or a plain list of plain lists of length ncols +## or a plain list of length a multiple of ncols containing the +## entries in row major order. +## The list list is guaranteed not to be changed by this operation. +##

+## The corresponding entries must be in or compatible with R. +## If list already contains vector objects, they are copied. +##

+## The second and third alternatives for NewMatrix have been added +## for consistency with the corresponding versions of Matrix. +## They just call the first version. +##

+## If the global option check is set to false then +## need not perform consistency checks. +##

+## Similarly, returns a zero matrix +## object with m rows and n columns +## which has filt and R as +## and +## values. +##

+## Similarly, returns an identity +## matrix object with n rows and columns +## which has filt and R as +## and +## values, +## and contains the identity element of R in the diagonal +## and the zero of R in each off-diagonal position. +##

+## The returned object is mutable if and only if filt implies +## . +##

+## m1 := NewMatrix( IsPlistMatrixRep, Integers, 3, [ [4,5,6], [7,8,9] ] );; +## gap> Display( m1 ); +## <2x3-matrix over Integers: +## [[ 4, 5, 6 ] +## [ 7, 8, 9 ] +## ]> +## gap> NewZeroMatrix( IsPlistMatrixRep, Rationals, 5, 3 ); +## <5x3-matrix over Rationals> +## gap> NewIdentityMatrix( IsGF2MatrixRep, GF(2), 4 ); +## +## ]]> +## +## +## <#/GAPDoc> +## +DeclareTagBasedOperation( "NewMatrix", + [ IsOperation, IsSemiring, IsInt, IsList] ); + +DeclareOperation( "NewMatrix", + [ IsOperation, IsSemiring, IsList, IsInt] ); + +DeclareOperation( "NewMatrix", + [ IsOperation, IsSemiring, IsList] ); + +DeclareTagBasedOperation( "NewZeroMatrix", + [ IsOperation, IsSemiring, IsInt, IsInt ] ); + +DeclareTagBasedOperation( "NewIdentityMatrix", + [ IsOperation, IsSemiring, IsInt ] ); + + +############################################################################# +## +## Operations for Vector and Matrix Objects +## ############################################################################# @@ -408,581 +873,442 @@ DeclareOperation( "Unpack", [ IsVecOrMatObj ] ); ############################################################################# ## -## <#GAPDoc Label="MatObj_ConcatenationOfVectors"> -## -## ConcatenationOfVectors -## -## +#O ChangedBaseDomain( , ) +#O ChangedBaseDomain( , ) ## -## a vector object +## <#GAPDoc Label="ChangedBaseDomain"> +## +## ChangedBaseDomain +## +## ## ## -## Returns a new mutable vector object in the representation of v1 -## or the first entry of the nonempty list vlist of vector objects, -## respectively, -## such that the entries are the concatenation of the given vector objects. +## For a vector object v (a matrix object M) +## and a semiring R, +## returns +## a new vector object (matrix object) +## with value R, +## value +## equal to that of v (M), +## and the same entries as v (M). ##

-## (Note that -## is a function for which no methods can be installed.) +## The result is mutable if and only if v (M) is mutable. +##

+## For example, one can create a vector defined over GF(4) +## from a vector defined over GF(2) with this operation. +##

+## v1 := Vector( Integers, [ 3, 5, 7, 9 ] );; +## gap> ChangedBaseDomain( v1, Rationals ); +## +## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +## gap> m64 := ChangedBaseDomain( m6, GF(4) ); +## [ [ Z(2)^0, 0*Z(2), Z(2)^0 ], [ 0*Z(2), Z(2)^0, 0*Z(2) ] ] +## gap> ConstructingFilter( m64 ); +## +## ]]> ## ## ## <#/GAPDoc> ## -DeclareGlobalFunction( "ConcatenationOfVectors" ); +DeclareOperation( "ChangedBaseDomain", [ IsVecOrMatObj, IsSemiring ] ); +#DeclareOperation( "ChangedBaseDomain", [ IsVectorObj, IsSemiring ] ); +#DeclareOperation( "ChangedBaseDomain", [ IsMatrixOrMatrixObj, IsSemiring ] ); -############################################################################# -## -## <#GAPDoc Label="MatObj_ExtractSubVector"> -## -## +############################################################################ ## -## a vector object +#O Randomize( [Rs, ]v ) +#O Randomize( [Rs, ]M ) ## +## <#GAPDoc Label="Randomize"> +## +## Randomize +## +## ## -## Returns a new mutable vector object of the same vector representation -## as v, containing the entries of v at the positions in -## the list l. +## Replaces every entry in the mutable vector object v +## or matrix object M, respectively, with +## a random one from the base domain of v or M, +## respectively, and returns the argument. ##

-## This is the same as v{l}, -## the name was introduced in analogy to -## , for which no equivalent syntax using -## curly brackets is available. +## If given, the random source Rs is used to compute the +## random elements. +## Note that in this case, +## a +## method must be available that takes a random source as its first +## argument and the base domain as its second argument. +## m6 := ZeroMatrix( IsGF2MatrixRep, GF(2), 2, 10 );; +## gap> Randomize( m6 ); Display( m6 ); +## +## . 1 . . 1 . 1 . . . +## . . 1 . . . 1 1 . 1 +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperationKernel( "ExtractSubVector", - [ IsRowVectorOrVectorObj, IsList ], EXTRACT_SUB_VECTOR ); +DeclareOperation( "Randomize", [ IsVectorObj and IsMutable ] ); +DeclareOperation( "Randomize", [ IsRandomSource, IsVectorObj and IsMutable ] ); +DeclareOperation( "Randomize", [ IsMatrixOrMatrixObj and IsMutable ] ); +DeclareOperation( "Randomize", [ IsRandomSource, IsMatrixOrMatrixObj and IsMutable ] ); ############################################################################# ## -## Arithmetical operations for vector objects +## List Like Operations for Vector Objects ## ############################################################################# ## -#O AddVector( , [, [, , ]] ) -#O AddVector( , , [, , ] ) +#O \[\]( , ) +#O \[\]\:\=( , , ) +#O \{\}( , ) ## -## <#GAPDoc Label="MatObj_AddVector"> +## <#GAPDoc Label="ElementAccessVectorObj"> ## -## -## +## Element Access and Assignment for Vector Objects ## -## nothing +## +## +## ## ## -## Called with two vector objects dst and src, -## this function replaces the entries of dst in-place -## by the entries of the sum dst + src. +## For a vector object v and a positive integer i that is +## not larger than the length of v +## (see ), +## v[i] is the entry at position i. ##

-## If a scalar mul is given as the third or second argument, -## respectively, then the entries of dst get replaced by those of -## dst + src * mul or -## dst + mul * src, respectively. +## If v is mutable, i is as above, and obj is an object +## from the base domain of v then +## v[i]:= obj assigns obj to the +## i-th position of v. ##

-## If the optional parameters from and to are given then -## only the index range [from..to] is guaranteed to be -## affected. -## Other indices may be affected, if it is more convenient to do so. -## This can be helpful if entries of src are known to be zero. +## If list is a list of positive integers that are not larger than +## the length of v then +## v{list} returns a new mutable vector object +## in the same representation as v +## (see ) +## that contains the list[ k ]-th entry of v at +## position k. +##

+## If the global option check is set to false then +## +## need not perform consistency checks. ##

-## If from is bigger than to, the operation does nothing. +## Note that the sublist assignment operation +## is left out here since it tempts the programmer to use constructions like +## v{ [ 1 .. 3 ] }:= w{ [ 4 .. 6 ] } +## which produces an unnecessary intermediate object; +## one should use instead. +##

+## v1 := Vector( Integers, [3,4,7,8] );; +## gap> v1[4]; +## 8 +## gap> v1[2] := 6;; Print( v1 ); +## NewVector(IsPlistVectorRep,Integers,[ 3, 6, 7, 8 ]) +## gap> Print( v1{[2..3]} ); +## NewVector(IsPlistVectorRep,Integers,[ 6, 7 ]) +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "AddVector", - [ IsVectorObj and IsMutable, IsVectorObj ] ); -DeclareOperation( "AddVector", - [ IsVectorObj and IsMutable, IsVectorObj, IsObject ] ); -DeclareOperation( "AddVector", - [ IsVectorObj and IsMutable, IsObject, IsVectorObj ] ); -DeclareOperation( "AddVector", - [ IsVectorObj and IsMutable, IsVectorObj, IsObject, IsPosInt, IsPosInt ] ); -DeclareOperation( "AddVector", - [ IsVectorObj and IsMutable, IsObject, IsVectorObj, IsPosInt, IsPosInt ] ); +DeclareOperation( "[]", [ IsVectorObj, IsPosInt ] ); + +DeclareOperation( "[]:=", [ IsVectorObj, IsPosInt, IsObject ] ); + +DeclareOperation( "{}", [ IsVectorObj, IsList ] ); ############################################################################# ## -#O MultVector( , [, , ] ) -#O MultVectorLeft( , [, , ] ) -#O MultVectorRight( , [, , ] ) -## -## <#GAPDoc Label="MatObj_MultVectorLeft"> +## <#GAPDoc Label="MatObj_PositionNonZero"> ## -## -## -## -## -## nothing +## ## +## An integer ## -## These operations multiply v by mul in-place -## where -## multiplies with mul from the left -## and -## does so from the right. -##

-## Note that -## is just a synonym for -## . -## This was chosen because vectors in &GAP; are by default row vectors -## and scalar multiplication is usually written as -## a \cdot v = a \cdot [v_1, ..., v_n] = [a \cdot v_1, ..., a \cdot v_n] -## with scalars being applied from the left. -##

-## If the optional parameters from and to are given then -## only the index range [from..to] is guaranteed to be -## affected. Other indices may be affected, if it is more convenient -## to do so. -## This can be helpful if entries of v are known to be zero. -## If from is bigger than to, the operation does nothing. +## Returns the index of the first entry in the vector object v +## that is not zero. +## If all entries are zero, +## the function returns Length(v) + 1. ##

+## v := Vector( Integers, [0,0,1,1,2,2,0,0,0] );; Unpack( v ); +## [ 0, 0, 1, 1, 2, 2, 0, 0, 0 ] +## gap> PositionNonZero( v ); +## 3 +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "MultVectorLeft", - [ IsVectorObj and IsMutable, IsObject ] ); -DeclareOperation( "MultVectorLeft", - [ IsVectorObj and IsMutable, IsObject, IsInt, IsInt ] ); - -DeclareOperation( "MultVectorRight", - [ IsVectorObj and IsMutable, IsObject ] ); -DeclareOperation( "MultVectorRight", - [ IsVectorObj and IsMutable, IsObject, IsInt, IsInt ] ); - - -# This is defined for two vectors of equal length, -# it returns the standard scalar product. -# (The documentation is in the section about arithm. operations.) -DeclareOperation( "ScalarProduct", [ IsVectorObj, IsVectorObj ] ); +DeclareOperation( "PositionNonZero", [ IsVectorObj ] ); ############################################################################# ## -#O ZeroVector( , ) -#O ZeroVector( , ) -#O ZeroVector( , ) -#O ZeroVector( , , ) -## -## <#GAPDoc Label="VectorObj_ZeroVector"> +## <#GAPDoc Label="MatObj_PositionLastNonZero"> ## -## ZeroVector -## -## -## -## +## ## -## a vector object +## An integer ## -## For a semiring R and a nonnegative integer len, -## this operation returns a new vector object of length len -## over R in the representation filt containing only zeros. -## &GAP; guesses a suitable representation. -##

-## For a vector object v and a nonnegative integer len, -## this operation returns a new vector object of length len -## in the same representation as v containing only zeros. -##

-## For a matrix object M and a nonnegative integer len, -## this operation returns a new zero vector object of length -## len in the representation given by the -## value -## of M, provided that such a representation exists. -##

-## For a filter filt, a semiring R and a nonnegative integer -## len, this operation returns a new vector object of length -## len over R in the representation filt -## containing only zeros. -##

-## If the -## value of the result implies then the result is -## mutable. -##

-## Default methods for -## -## delegate to . +## Returns the index of the last entry in the vector object v +## that is not zero. +## If all entries are zero, the function returns 0. ##

## z1 := ZeroVector( Rationals, 4 );; Print( z1 ); -## NewVector(IsPlistVectorRep,Rationals,[ 0, 0, 0, 0 ]) -## gap> v5 := Vector( GF(5), [3,4]*Z(5) );; z5 := ZeroVector(3,v5);; Print(z5); -## [ 0*Z(5), 0*Z(5), 0*Z(5) ] -## gap> m6:=Matrix(Integers,[[1,3],[5,7]]);; z6:=ZeroVector(6,m6);; Print(z6); -## NewVector(IsPlistVectorRep,Integers,[ 0, 0, 0, 0, 0, 0 ]) -## gap> z8 := ZeroVector( IsZmodnZVectorRep, ZmodnZ(8), 4 );; Print( z8 ); -## NewVector(IsZmodnZVectorRep,Monoid( ... ),[ 0, 0, 0, 0 ]) +## gap> v := Vector( Integers, [0,0,1,1,2,2,0,0,0] );; Unpack( v ); +## [ 0, 0, 1, 1, 2, 2, 0, 0, 0 ] +## gap> PositionLastNonZero( v ); +## 6 ## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "ZeroVector", [ IsSemiring, IsInt ] ); -DeclareOperation( "ZeroVector", [ IsInt, IsVecOrMatObj ] ); -DeclareOperation( "ZeroVector", [ IsOperation, IsSemiring, IsInt ] ); -#DeclareOperation( "ZeroVector", [ IsInt, IsVectorObj ] ); -#DeclareOperation( "ZeroVector", [ IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "PositionLastNonZero", [ IsVectorObj ] ); ############################################################################# ## -#O Vector( , ) -#O Vector( , ) -#O Vector( , ) -#O Vector( , ) -#O Vector( , , ) -#O Vector( , , ) +#O ListOp( [, ] ) ## -## <#GAPDoc Label="Vector"> +## <#GAPDoc Label="MatObj_ListOp"> ## -## Vector -## -## -## -## -## -## -## +## ## -## a vector object +## A plain list ## -## If a semiring R is given as the first argument then -## a vector object is returned whose -## -## value is guessed from R, with base domain R -## and entries given by the last argument. -##

-## In the remaining cases with two arguments, -## the first argument is a list or a vector object -## that defines the entries of the result, -## and the second argument is a vector object whose -## and -## are taken for the -## result. -##

-## The variant Vector( v1, v2 ) -## is supported also for the case that v2 is a row vector but not -## a vector object. -## In this situation, the result is a row vector that is equal to -## v1 and whose internal representation fits to that of v2. -##

-## If only a list list is given then both the -## and the -## are guessed from -## this list. -##

-## If a filter filt is given as the first argument then -## a vector object is returned that has -## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the vector object -## v, respectively. -##

-## If the global option check is set to false then -## -## need not perform consistency checks. -##

-## If the -## value of the result implies then the result is -## mutable if and only if the argument that determines the entries of the -## result (list, v, v1) is mutable. -##

-## In the case of a mutable result, it is not guaranteed that -## the given list of entries is copied. +## Applies the function func to each entry of the vector object +## v and returns the results as a mutable plain list. +## This allows for calling +## on vector objects. ##

-## Default methods for -## -## delegate to . +## If the argument func is not given, +## applies to all entries. ##

## v1 := Vector( Integers, [3,4,7,8] );; Print( v1 ); -## NewVector(IsPlistVectorRep,Integers,[ 3, 4, 7, 8 ]) -## gap> v2 := Vector( Rationals, v1 );; Print( v2 ); -## NewVector(IsPlistVectorRep,Rationals,[ 3, 4, 7, 8 ]) -## gap> v3 := Vector( [ 11..13], v1) ;; Print( v3 ); -## NewVector(IsPlistVectorRep,Integers,[ 11, 12, 13 ]) -## gap> v0 := [6..9];; IsVector( v0 ); -## true -## gap> Print( Vector( v0, v1 ) ); -## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) -## gap> v4 := Vector( [ 2, 5/2, 7/3, 3 ] );; Print( v4 ); -## NewVector(IsPlistVectorRep,Rationals,[ 2, 5/2, 7/3, 3 ]) -## gap> v5 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; -## gap> Print( v5 ); -## [ 0*Z(2), Z(2)^0, 0*Z(2) ] -## gap> v6 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 ); -## -## gap> BaseDomain( v6 ); -## (Integers mod 8) -## gap> v7 := Vector( IsZmodnZVectorRep, ZmodnZ(12), v0 ); -## +## gap> v := Vector( Integers, [0,0,1,1,2,2,0,0,0] );; Unpack( v ); +## [ 0, 0, 1, 1, 2, 2, 0, 0, 0 ] +## gap> List( v, x -> x-1 ); +## [ -1, -1, 0, 0, 1, 1, -1, -1, -1 ] ## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "Vector", [ IsSemiring, IsList ] ); -DeclareOperation( "Vector", [ IsSemiring, IsVectorObj ] ); -DeclareOperation( "Vector", [ IsList, IsVectorObj ] ); -DeclareOperation( "Vector", [ IsVectorObj, IsVectorObj ] ); -DeclareOperation( "Vector", [ IsList ] ); -DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsList ] ); -DeclareOperation( "Vector", [ IsOperation, IsSemiring, IsVectorObj ] ); +DeclareOperation( "ListOp", [ IsVectorObj ] ); +DeclareOperation( "ListOp", [ IsVectorObj, IsFunction ] ); ############################################################################# ## -#O NewVector( , , ) -#O NewZeroVector( , , ) +## Arithmetical operations for vector objects ## -## <#GAPDoc Label="NewVector"> + +############################################################################# +## +#O AddVector( , [, [, , ]] ) +#O AddVector( , , [, , ] ) +## +## <#GAPDoc Label="MatObj_AddVector"> ## -## NewVector and NewZeroVector -## -## +## +## +## +## nothing ## ## -## These two operations are constructors, and should only be used -## when or -## -## do not give the desired result. -##

-## For a filter filt, a semiring R, and a list list -## of elements that belong to R, -## returns a vector object which has -## the -## filt, -## the R, -## and the entries in list. -## The list list is guaranteed not to be changed by this operation. +## Called with two vector objects dst and src, +## this function replaces the entries of dst in-place +## by the entries of the sum dst + src. ##

-## If the global option check is set to false then -## need not perform consistency checks. +## If a scalar mul is given as the third or second argument, +## respectively, then the entries of dst get replaced by those of +## dst + src * mul or +## dst + mul * src, respectively. ##

-## Similarly, returns a vector object -## of length n which has filt and R as -## and -## values, -## and contains the zero of R in each position. +## If the optional parameters from and to are given then +## only the index range [from..to] is guaranteed to be +## affected. +## Other indices may be affected, if it is more convenient to do so. +## This can be helpful if entries of src are known to be zero. ##

-## The returned object is mutable if and only if filt implies -## . +## If from is bigger than to, the operation does nothing. ##

## v := NewVector( IsGF2VectorRep, GF(2), [1,0,1,0,1]*Z(2) ); -## -## gap> Print(v); -## [ Z(2)^0, 0*Z(2), Z(2)^0, 0*Z(2), Z(2)^0 ] -## gap> NewZeroVector( IsZmodnZVectorRep, ZmodnZ(7), 5 ); -## +## gap> v1 := Vector( Integers, [0,1,2,4,8] );; Print( v1 ); +## NewVector(IsPlistVectorRep,Integers,[ 0, 1, 2, 4, 8 ]) +## gap> v2 := Vector( [1,0,1,0,1], v1 );; Print( v2 ); +## NewVector(IsPlistVectorRep,Integers,[ 1, 0, 1, 0, 1 ]) +## gap> AddVector( v1, v2 ); Unpack( v1 ); +## [ 1, 1, 3, 4, 9 ] +## gap> AddVector( v1, v2, -2 ); Unpack( v1 ); +## [ -1, 1, 1, 4, 7 ] ## ]]> ## ## ## <#/GAPDoc> ## -DeclareTagBasedOperation( "NewVector", [ IsOperation, IsSemiring, IsList ] ); - -DeclareTagBasedOperation( "NewZeroVector", - [ IsOperation, IsSemiring, IsInt ] ); +DeclareOperation( "AddVector", + [ IsVectorObj and IsMutable, IsVectorObj ] ); +DeclareOperation( "AddVector", + [ IsVectorObj and IsMutable, IsVectorObj, IsObject ] ); +DeclareOperation( "AddVector", + [ IsVectorObj and IsMutable, IsObject, IsVectorObj ] ); +DeclareOperation( "AddVector", + [ IsVectorObj and IsMutable, IsVectorObj, IsObject, IsPosInt, IsPosInt ] ); +DeclareOperation( "AddVector", + [ IsVectorObj and IsMutable, IsObject, IsVectorObj, IsPosInt, IsPosInt ] ); ############################################################################# ## -#O NewMatrix( , , , ) -#O NewMatrix( , , , ) -#O NewMatrix( , , ) -#O NewZeroMatrix( , , , ) -#O NewIdentityMatrix( , , ) +#O MultVector( , [, , ] ) +#O MultVectorLeft( , [, , ] ) +#O MultVectorRight( , [, , ] ) ## -## <#GAPDoc Label="NewMatrix"> +## <#GAPDoc Label="MatObj_MultVectorLeft"> ## -## NewMatrix, NewZeroMatrix, NewIdentityMatrix -## -## -## -## -## +## +## +## +## +## nothing ## ## -## These three operations are constructors, and should only be used -## by those implementing new material for matrix objects. -## Most users should find -## , -## or -## -## sufficient for their requirements. -##

-## For a filter filt, a semiring R, -## a positive integer ncols, and a list list, -## returns a matrix object which has -## the -## filt, -## the R, -## n columns -## (see ), -## and the entries described by list, -## which can be either a plain list of vector objects of length ncols -## or a plain list of plain lists of length ncols -## or a plain list of length a multiple of ncols containing the -## entries in row major order. -## The list list is guaranteed not to be changed by this operation. -##

-## The corresponding entries must be in or compatible with R. -## If list already contains vector objects, they are copied. -##

-## The second and third alternatives for NewMatrix have been added -## for consistency with the corresponding versions of Matrix. -## They just call the first version. -##

-## If the global option check is set to false then -## need not perform consistency checks. -##

-## Similarly, returns a zero matrix -## object with m rows and n columns -## which has filt and R as -## and -## values. +## These operations multiply v by mul in-place +## where +## multiplies with mul from the left +## and +## does so from the right. ##

-## Similarly, returns an identity -## matrix object with n rows and columns -## which has filt and R as -## and -## values, -## and contains the identity element of R in the diagonal -## and the zero of R in each off-diagonal position. +## Note that +## is just a synonym for +## . +## This was chosen because vectors in &GAP; are by default row vectors +## and scalar multiplication is usually written as +## a \cdot v = a \cdot [v_1, ..., v_n] = [a \cdot v_1, ..., a \cdot v_n] +## with scalars being applied from the left. ##

-## The returned object is mutable if and only if filt implies -## . +## If the optional parameters from and to are given then +## only the index range [from..to] is guaranteed to be +## affected. Other indices may be affected, if it is more convenient +## to do so. +## This can be helpful if entries of v are known to be zero. +## If from is bigger than to, the operation does nothing. ##

## m1 := NewMatrix( IsPlistMatrixRep, Integers, 3, [ [4,5,6], [7,8,9] ] );; -## gap> Display( m1 ); -## <2x3-matrix over Integers: -## [[ 4, 5, 6 ] -## [ 7, 8, 9 ] -## ]> -## gap> NewZeroMatrix( IsPlistMatrixRep, Rationals, 5, 3 ); -## <5x3-matrix over Rationals> -## gap> NewIdentityMatrix( IsGF2MatrixRep, GF(2), 4 ); -## +## gap> v1 := Vector( Integers, [0,1,2,4,8] );; +## gap> MultVector( v1, 2 ); Unpack( v1 ); +## [ 0, 2, 4, 8, 16 ] ## ]]> ## ## ## <#/GAPDoc> ## -DeclareTagBasedOperation( "NewMatrix", - [ IsOperation, IsSemiring, IsInt, IsList] ); - -DeclareOperation( "NewMatrix", - [ IsOperation, IsSemiring, IsList, IsInt] ); - -DeclareOperation( "NewMatrix", - [ IsOperation, IsSemiring, IsList] ); +DeclareOperation( "MultVectorLeft", + [ IsVectorObj and IsMutable, IsObject ] ); +DeclareOperation( "MultVectorLeft", + [ IsVectorObj and IsMutable, IsObject, IsInt, IsInt ] ); -DeclareTagBasedOperation( "NewZeroMatrix", - [ IsOperation, IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "MultVectorRight", + [ IsVectorObj and IsMutable, IsObject ] ); +DeclareOperation( "MultVectorRight", + [ IsVectorObj and IsMutable, IsObject, IsInt, IsInt ] ); -DeclareTagBasedOperation( "NewIdentityMatrix", - [ IsOperation, IsSemiring, IsInt ] ); +# This is defined for two vectors of equal length, +# it returns the standard scalar product. +# (The documentation is in the section about arithm. operations.) +DeclareOperation( "ScalarProduct", [ IsVectorObj, IsVectorObj ] ); ############################################################################# ## -#O ChangedBaseDomain( , ) -#O ChangedBaseDomain( , ) +## Operations for Vector Objects ## -## <#GAPDoc Label="ChangedBaseDomain"> + +############################################################################# +## +## <#GAPDoc Label="MatObj_ConcatenationOfVectors"> ## -## ChangedBaseDomain -## -## +## ConcatenationOfVectors +## +## +## +## a vector object ## ## -## For a vector object v (a matrix object M) -## and a semiring R, -## returns -## a new vector object (matrix object) -## with value R, -## value -## equal to that of v (M), -## and the same entries as v (M). -##

-## The result is mutable if and only if v (M) is mutable. +## Returns a new mutable vector object in the representation of v1 +## or the first entry of the nonempty list vlist of vector objects, +## respectively, +## such that the entries are the concatenation of the given vector objects. ##

-## For example, one can create a vector defined over GF(4) -## from a vector defined over GF(2) with this operation. +## (Note that +## is a function for which no methods can be installed.) ##

## v1 := Vector( Integers, [ 3, 5, 7, 9 ] );; -## gap> ChangedBaseDomain( v1, Rationals ); -## -## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; -## gap> m64 := ChangedBaseDomain( m6, GF(4) ); -## [ [ Z(2)^0, 0*Z(2), Z(2)^0 ], [ 0*Z(2), Z(2)^0, 0*Z(2) ] ] -## gap> ConstructingFilter( m64 ); -## +## gap> v1 := Vector( Integers, [1,2,3] );; +## gap> v2 := Vector( Integers, [6,7,8,9] );; +## gap> Print( ConcatenationOfVectors( v1, v2 ) ); +## NewVector(IsPlistVectorRep,Integers,[ 1, 2, 3, 6, 7, 8, 9 ]) +## gap> Print( ConcatenationOfVectors( v2, [0,1] ) ); +## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9, 0, 1 ]) +## gap> Print( ConcatenationOfVectors( [ v1, [0,0,0], v2 ] ) ); +## NewVector(IsPlistVectorRep,Integers,[ 1, 2, 3, 0, 0, 0, 6, 7, 8, 9 ]) ## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "ChangedBaseDomain", [ IsVecOrMatObj, IsSemiring ] ); -#DeclareOperation( "ChangedBaseDomain", [ IsVectorObj, IsSemiring ] ); -#DeclareOperation( "ChangedBaseDomain", [ IsMatrixOrMatrixObj, IsSemiring ] ); +DeclareGlobalFunction( "ConcatenationOfVectors" ); -############################################################################ -## -#O Randomize( [Rs, ]v ) -#O Randomize( [Rs, ]M ) +############################################################################# ## -## <#GAPDoc Label="Randomize"> +## <#GAPDoc Label="MatObj_ExtractSubVector"> ## -## Randomize -## -## +## +## +## a vector object +## ## -## Replaces every entry in the mutable vector object v -## or matrix object M, respectively, with -## a random one from the base domain of v or M, -## respectively, and returns the argument. +## Returns a new mutable vector object of the same vector representation +## as v, containing the entries of v at the positions in +## the list l. ##

-## If given, the random source Rs is used to compute the -## random elements. -## Note that in this case, -## a -## method must be available that takes a random source as its first -## argument and the base domain as its second argument. +## This is the same as v{l}, +## the name was introduced in analogy to +## , for which no equivalent syntax using +## curly brackets is available. +##

+## v1 := Vector( Rationals, [-5..5] );; +## gap> v2 := ExtractSubVector( v1, [1,3,5,7,9,11] );; Print( v2 ); +## NewVector(IsPlistVectorRep,Rationals,[ -5, -3, -1, 1, 3, 5 ]) +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperation( "Randomize", [ IsVectorObj and IsMutable ] ); -DeclareOperation( "Randomize", [ IsRandomSource, IsVectorObj and IsMutable ] ); -DeclareOperation( "Randomize", [ IsMatrixOrMatrixObj and IsMutable ] ); -DeclareOperation( "Randomize", [ IsRandomSource, IsMatrixOrMatrixObj and IsMutable ] ); +DeclareOperationKernel( "ExtractSubVector", + [ IsRowVectorOrVectorObj, IsList ], EXTRACT_SUB_VECTOR ); ############################################################################# @@ -1038,6 +1364,14 @@ DeclareOperationKernel( "CopySubVector", ## ## returns the Hamming weight of the vector object v, ## i.e., the number of nonzero entries in v. +##

+## v1 := Vector( Integers, [2,3,5,6,8,9] );; +## gap> v2 := Vector( Integers, [2,3,0,0,8,9] );; +## gap> v3 := ZeroVector( Integers, 6 );; +## gap> [ WeightOfVector(v1), WeightOfVector(v2), WeightOfVector(v3) ]; +## [ 6, 4, 0 ] +## ]]> ## ## ## <#/GAPDoc> @@ -1056,6 +1390,14 @@ DeclareOperation( "WeightOfVector", [ IsVectorObj ] ); ## returns the Hamming distance of the vector objects v1 and ## v2, i.e., the number of entries in which the vectors differ. ## The vectors must have equal length. +##

+## v1 := Vector( Integers, [2,3,5,6,8,9] );; +## gap> v2 := Vector( Integers, [2,3,0,0,8,9] );; +## gap> v3 := ZeroVector( Integers, 6 );; +## gap> [ DistanceOfVectors( v1, v2 ), DistanceOfVectors( v2, v3 ) ]; +## [ 2, 4 ] +## ]]> ## ## ## <#/GAPDoc> @@ -1213,130 +1555,6 @@ DeclareOperationKernel( "[,]:=", [ IsMatrixOrMatrixObj, IsInt, IsInt, IsObject ] DeclareSynonym( "SetMatElm", ASS_MAT ); -############################################################################# -## -#O ZeroMatrix( , , ) -#O ZeroMatrix( , , ) -#O ZeroMatrix( , , , ) -## -## <#GAPDoc Label="MatObj_ZeroMatrix"> -## -## ZeroMatrix -## -## -## -## -## a matrix object -## -## For a matrix object M and two nonnegative integers m -## and n, this operation returns a new matrix object -## with m rows and n columns -## in the same representation and over the same base domain as M -## containing only zeros. -##

-## If a semiring R and two nonnegative integers m and -## n are given, -## the representation of the result is guessed from R. -##

-## If a filter filt and a semiring R are given as the first -## and second argument, they are taken as the values of -## and -## of the result. -##

-## If the -## value of the result implies then the result is -## fully mutable. -##

-## Default methods for -## -## delegate to . -##

-## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; -## gap> z7 := ZeroMatrix( 2, 2, m7 );; Print( z7 ); -## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, -## [ [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ], -## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 0, 8 ) ] ]) -## gap> z23 := ZeroMatrix( Rationals, 2, 3 );; Print( z23 ); -## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 0, 0 ], [ 0, 0, 0 ] ]) -## gap> z5 := ZeroMatrix( IsGF2MatrixRep, GF(2), 2, 5 );; Display( z5 ); -## . . . . . -## . . . . . -## ]> -## ]]> -## -## -## <#/GAPDoc> -## -DeclareOperation( "ZeroMatrix", [ IsInt, IsInt, IsMatrixOrMatrixObj ] ); -DeclareOperation( "ZeroMatrix", [ IsSemiring, IsInt, IsInt ] ); -DeclareOperation( "ZeroMatrix", [ IsOperation, IsSemiring, IsInt, IsInt ] ); - - -############################################################################# -## -#O IdentityMatrix( , ) -#O IdentityMatrix( , ) -#O IdentityMatrix( , , ) -## -## <#GAPDoc Label="MatObj_IdentityMatrix"> -## -## IdentityMatrix -## -## -## -## -## a matrix object -## -## For a matrix object M and a nonnegative integer n, -## this operation returns a new identity matrix object -## with n rows and columns -## in the same representation and over the same base domain as M. -##

-## If a semiring R and a nonnegative integer n is given, -## the representation of the result is guessed from R. -##

-## If a filter filt and a semiring R are given as the first -## and second argument, they are taken as the values of -## and -## of the result. -##

-## If the -## value of the result implies then the result is -## fully mutable. -##

-## Default methods for -## -## delegate to . -##

-## m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 );; -## gap> id7 := IdentityMatrix( 2, m7 );; Print( id7 ); -## NewMatrix(IsZmodnZMatrixRep,Monoid( ... ),2, -## [ [ ZmodnZObj( 1, 8 ), ZmodnZObj( 0, 8 ) ], -## [ ZmodnZObj( 0, 8 ), ZmodnZObj( 1, 8 ) ] ]) -## gap> id2 := IdentityMatrix( Rationals, 2 );; Print( id2 ); -## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 1, 0 ], [ 0, 1 ] ]) -## gap> id3 := IdentityMatrix( IsGF2MatrixRep, GF(2), 3 );; Display( id3 ); -## 1 . . -## . 1 . -## . . 1 -## ]]> -## -## -## <#/GAPDoc> -## -DeclareOperation( "IdentityMatrix", [ IsInt, IsMatrixOrMatrixObj ] ); -DeclareOperation( "IdentityMatrix", [ IsSemiring, IsInt ] ); -DeclareOperation( "IdentityMatrix", [ IsOperation, IsSemiring, IsInt ] ); - - ############################################################################# ## #O CompanionMatrix( , ) @@ -1400,130 +1618,6 @@ DeclareOperation( "CompanionMatrix", [ IsUnivariatePolynomial, IsSemiring ] ); -############################################################################# -## -#O Matrix( , ) -#O Matrix( , , ) -#O Matrix( , ) -#O Matrix( , ) -#O Matrix( , , ) -#O Matrix( , ) -#O Matrix( ) -#O Matrix( , ) -#O Matrix( , , ) -#O Matrix( , , , ) -#O Matrix( , , ) -## -## <#GAPDoc Label="MatObj_Matrix"> -## -## Matrix -## -## -## -## -## -## -## a matrix object -## -## If a semiring R is given as the first argument then -## a matrix object is returned whose -## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the matrix object -## matobj, respectively. -## Here list can be either a list of plain lists that describe the -## entries of the rows, or a flat list of the entries in row major order, -## where ncols defines the number of columns. -##

-## In those cases where the last argument is a matrix object, -## the first argument is a list or a matrix object -## that defines (together with ncols if applicable) the entries of -## the result, and the -## and -## of the last argument -## are taken for the result. -##

-## If only a list list and perhaps ncols is given -## then both the -## and the -## are guessed from -## the list. -##

-## In the remaining cases a filter filt is given as the -## first argument and a matrix object is returned that has -## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the matrix object -## M, respectively. -##

-## If the global option check is set to false then -## -## need not perform consistency checks. -##

-## If the -## value of the result implies then the result is -## mutable if and only if the argument that determines the entries of the -## result (list or matobj) is mutable. -##

-## In the case of a mutable result, it is guaranteed that the given list -## list is copied in the sense of , -## and if list is a nested list then it is not guaranteed -## that also the entries of list are copied. -##

-## Default methods for -## -## delegate to . -##

-## m1 := Matrix( Integers, [ [3,4,5], [6,7,8] ] );; Print( m1 ); -## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ 3, 4, 5 ], [ 6, 7, 8 ] ]) -## gap> m2 := Matrix( Rationals, [10..30], 7 );; Display( m2 ); -## <3x7-matrix over Rationals: -## [[ 10 .. 16 ] -## [ 17 .. 23 ] -## [ 24 .. 30 ] -## ]> -## gap> Print( Matrix( Integers, m2 ) ); -## NewMatrix(IsPlistMatrixRep,Integers,7, -## [ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) -## gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); -## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) -## gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); -## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) -## gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); -## true -## gap> Print( Matrix( m0, m1 ) ); -## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) -## gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); -## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) -## gap> Print( Matrix( [-9..-4], 3, m1 ) ); -## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) -## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; -## gap> Display( m6 ); -## 1 . 1 -## . 1 . -## gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); -## -## gap> m8 := Matrix( IsZmodnZMatrixRep, ZmodnZ(12), m0 ); -## -## ]]> -## -## -## <#/GAPDoc> -## -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList ] ); -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsList ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsInt, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsList ]); - - ############################################################################ ## #A CompatibleVector( ) From 6059c94b03b45f9bde589c53f4e98c2e64932797 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 7 May 2026 09:53:15 +0100 Subject: [PATCH 038/123] resolving conflict --- lib/matobj2.gd | 89 -------------------------------------------------- 1 file changed, 89 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index c032d0e8da..cf2798a88c 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1618,95 +1618,6 @@ DeclareOperation( "CompanionMatrix", [ IsUnivariatePolynomial, IsSemiring ] ); -############################################################################# -## -#O Matrix( , , , ) -#O Matrix( , , ) -#O Matrix( , , ) -#O Matrix( , , ) -#O Matrix( , ) -#O Matrix( , ) -#O Matrix( , , ) -#O Matrix( , ) -#O Matrix( , ) -#O Matrix( , ) -#O Matrix( ) -## -## <#GAPDoc Label="MatObj_Matrix"> -## -## Matrix -## -## -## -## -## -## -## a matrix object -## -## If a filter filt is given as the first argument then -## a matrix object is returned that has -## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the matrix object -## matobj, respectively. -## Here list can be either a list of plain lists that describe the -## entries of the rows, or a flat list of the entries in row major order, -## where ncols defines the number of columns. -##

-## If a semiring R is given as the first argument then -## a matrix object is returned whose -## -## value is guessed from R, again with base domain R -## and entries given by the last argument. -##

-## In those remaining cases where the last argument is a matrix object, -## the first argument is a list or a matrix object -## that defines (together with ncols if applicable) the entries of -## the result, and the -## and -## of the last argument -## are taken for the result. -##

-## Finally, if only a list list and perhaps ncols is given -## then both the -## and the -## are guessed from -## the list. -##

-## If the global option check is set to false then -## -## need not perform consistency checks. -##

-## If the -## value of the result implies then the result is -## mutable if and only if the argument that determines the entries of the -## result (list or matobj) is mutable. -##

-## In the case of a mutable result, it is guaranteed that the given list -## list is copied in the sense of , -## and if list is a nested list then it is not guaranteed -## that also the entries of list are copied. -##

-## Default methods for -## -## delegate to . -## -## -## <#/GAPDoc> -## -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList ] ); -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsList ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsInt, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsList ]); - - ############################################################################ ## #A CompatibleVector( ) From fcf44fd633f47860a2f98f3f46051b5dedbc5376 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 7 May 2026 13:09:51 +0100 Subject: [PATCH 039/123] added examples for 26.13 and 26.14 --- lib/matobj.gi | 16 +- lib/matobj2.gd | 732 +++++++++++------- .../MatrixObj/ExtractSubMatrix.tst | 5 - 3 files changed, 463 insertions(+), 290 deletions(-) diff --git a/lib/matobj.gi b/lib/matobj.gi index ca1c152681..4b5c1f72a8 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1151,9 +1151,17 @@ InstallMethod( MultVectorRight, ## [ [ 3, 0, 3 ], [ 0, 3, 0 ] ] ## [ [ 5, 0, 5 ], [ 0, 5, 0 ] ] ## [ [ 1/2, 0, 1/2 ], [ 0, 1/2, 0 ] ] -## gap> m3 := Matrix( [ [1,1], [0,1] ], m1 );; -## gap> Print( m3 * m1 ); -## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 9, 11, 13 ], [ 6, 7, 8 ] ]) +## gap> m3 := Matrix( Integers, [ [1,1], [0,1] ] ); +## <2x2-matrix over Integers> +## gap> m3 := Matrix( Integers, [ [1,1], [0,1] ] );; +## gap> m4 := Matrix( Integers, [ [3,5], [4,7] ] );; +## gap> Print( m3 * m4 ); +## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ 7, 12 ], [ 4, 7 ] ]) +## gap> Unpack( m3 * m4 ); +## [ [ 7, 12 ], [ 4, 7 ] ] +## gap> Unpack( m3^6 ); Unpack( m4^-1 ); +## [ [ 1, 6 ], [ 0, 1 ] ] +## [ [ 7, -5 ], [ -4, 3 ] ] ## ]]> ## ## @@ -1436,7 +1444,7 @@ InstallMethod( Characteristic, ## ## a matrix object ## -## For a vector object M, +## For a matrix object M, ## the operations for computing the additive inverse with prescribed ## mutability return a matrix object with the same ## and diff --git a/lib/matobj2.gd b/lib/matobj2.gd index cf2798a88c..c4652e9152 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -899,7 +899,7 @@ DeclareOperation( "Unpack", [ IsVecOrMatObj ] ); ##

## v1 := Vector( Integers, [ 3, 5, 7, 9 ] );; -## gap> ChangedBaseDomain( v1, Rationals ); +## gap> ChangedBaseDomain( v1, Rationals ); ## ## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; ## gap> m64 := ChangedBaseDomain( m6, GF(4) ); @@ -1405,6 +1405,91 @@ DeclareOperation( "WeightOfVector", [ IsVectorObj ] ); DeclareOperation( "DistanceOfVectors", [ IsVectorObj, IsVectorObj ] ); +############################################################################# +## +#O MatElm( , , ) . . . . . . select an entry from a matrix +#O [ , ] . . . . . . . . . . select an entry from a matrix +## +## <#GAPDoc Label="MatObj_MatElm"> +## +## +## +## an entry of the matrix object +## +## +## For a matrix object M, this operation returns the entry in +## row row and column col. +##

+## Also the syntax M[ row, col ] +## is supported. +##

+## Note that this is not equivalent to +## M[ row ][ col ], +## which would first try to access M[ row ], +## and this is in general not possible. +##

+## m1 := Matrix( Rationals, [ [3,4,5], [6,7,8] ] );; +## gap> [ MatElm( m1, 2, 2 ), m1[2,3] ]; +## [ 7, 8 ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperationKernel( "[,]", [ IsMatrixOrMatrixObj, IS_INT, IS_INT ], ELM_MAT ); +DeclareSynonym( "MatElm", ELM_MAT ); + + +############################################################################# +## +#O SetMatElm( , , , ) . . . . set an entry in a matrix +#O [ , ]:= . . . . . . . . . set an entry in a matrix +## +## <#GAPDoc Label="MatObj_SetMatElm"> +## +## +## +## nothing +## +## +## For a mutable matrix object M, this operation assigns the object +## obj to the position in row row and column col, +## provided that obj is compatible with the +## value of M. +##

+## Also the syntax +## M[ row, col ]:= obj +## is supported. +##

+## Note that this is not equivalent to +## M[ row ][ col ]:= obj, +## which would first try to access M[ row ], +## and this is in general not possible. +##

+## If the global option check is set to false then +## need not perform consistency checks. +##

+## m1 := Matrix( Rationals, [ [3,4,5], [6,7,8] ] );; +## gap> SetMatElm( m1, 1, 3, 0 ); +## gap> m1[2,1] := 0;; Unpack( m1 ); +## [ [ 3, 4, 0 ], [ 0, 7, 8 ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperationKernel( "[,]:=", [ IsMatrixOrMatrixObj, IsInt, IsInt, IsObject ], + ASS_MAT ); +#T We want to require also 'IsMutable' for the first argument, +#T but some package may have installed methods without this requirement. +#T Note that if we declare the operation twice, once with requirement +#T 'IsMutable' and once without, each method installation will show +#T a complaint that it matches more than one declaration. +DeclareSynonym( "SetMatElm", ASS_MAT ); + + ############################################################################# ## #O ExtractSubMatrix( , , ) @@ -1422,6 +1507,15 @@ DeclareOperation( "DistanceOfVectors", [ IsVectorObj, IsVectorObj ] ); ## If the ## value of the result implies then the result is ## fully mutable. +##

+## m1 := Matrix( Integers, [1..20], 5 );; Unpack( m1 ); +## [ [ 1 .. 5 ], [ 6 .. 10 ], [ 11 .. 15 ], [ 16 .. 20 ] ] +## gap> m2 := ExtractSubMatrix( m1, [2,3], [2..4] );; Unpack( m2 ); +## [ [ 7 .. 9 ], [ 12 .. 14 ] ] +## gap> m3 := ExtractSubMatrix( m1, [4,1], [5,1] );; Unpack( m3 ); +## [ [ 20, 16 ], [ 5, 1 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -1472,6 +1566,16 @@ DeclareOperation( "MutableCopyMatrix", [ IsMatrixOrMatrixObj ] ); ##

## If the global option check is set to false then ## need not perform consistency checks. +##

+## m1 := Matrix( Integers, [1..20], 5 );; Unpack( m1 ); +## [ [ 1 .. 5 ], [ 6 .. 10 ], [ 11 .. 15 ], [ 16 .. 20 ] ] +## gap> m0 := ZeroMatrix( Integers, 2, 9 );; +## gap> CopySubMatrix( m1, m0, [2,3], [1,2], [2..4], [3..5] ); Unpack( m0 ); +## [ [ 0, 0, 7, 8, 9, 0, 0, 0, 0 ], [ 0, 0, 12, 13, 14, 0, 0, 0, 0 ] ] +## gap> CopySubMatrix( m1, m0, [4,1], [1,2], [5,1], [7,8] ); Unpack( m0 ); +## [ [ 0, 0, 7, 8, 9, 0, 20, 16, 0 ], [ 0, 0, 12, 13, 14, 0, 5, 1, 0 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -1483,76 +1587,79 @@ DeclareOperationKernel( "CopySubMatrix", #T the pre-existing operation declaration for compatibility with packages. -############################################################################# +############################################################################ ## -#O MatElm( , , ) . . . . . . select an entry from a matrix -#O [ , ] . . . . . . . . . . select an entry from a matrix +#A CompatibleVector( ) ## -## <#GAPDoc Label="MatObj_MatElm"> +## <#GAPDoc Label="CompatibleVector"> ## -## +## ## -## an entry of the matrix object +## a vector object ## ## -## For a matrix object M, this operation returns the entry in -## row row and column col. +## Called with a matrix object M with m rows, +## this operation returns a mutable zero vector object v of length +## m and in the representation given by the +## value +## of M (provided that such a representation exists). ##

-## Also the syntax M[ row, col ] -## is supported. +## The idea is that there should be an efficient way to +## form the product vM. ##

-## Note that this is not equivalent to -## M[ row ][ col ], -## which would first try to access M[ row ], -## and this is in general not possible. +## m1 := Matrix( Integers, [ [2,3], [5,6], [8,9] ] );; +## gap> v1 := CompatibleVector( m1 );; Unpack( v1 ); +## [ 0, 0, 0 ] +## gap> v1[1] := -1;; v1[3] := -1;; Unpack( v1 ); +## [ -1, 0, -1 ] +## gap> Print( v1 * m1 ); +## NewVector(IsPlistVectorRep,Integers,[ -10, -12 ]) +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperationKernel( "[,]", [ IsMatrixOrMatrixObj, IS_INT, IS_INT ], ELM_MAT ); -DeclareSynonym( "MatElm", ELM_MAT ); +DeclareOperation( "CompatibleVector", [ IsMatrixOrMatrixObj ] ); -############################################################################# +############################################################################ ## -#O SetMatElm( , , , ) . . . . set an entry in a matrix -#O [ , ]:= . . . . . . . . . set an entry in a matrix +#A RowsOfMatrix( ) ## -## <#GAPDoc Label="MatObj_SetMatElm"> +## <#GAPDoc Label="RowsOfMatrix"> ## -## +## ## -## nothing +## a plain list ## ## -## For a mutable matrix object M, this operation assigns the object -## obj to the position in row row and column col, -## provided that obj is compatible with the -## value of M. -##

-## Also the syntax -## M[ row, col ]:= obj -## is supported. -##

-## Note that this is not equivalent to -## M[ row ][ col ]:= obj, -## which would first try to access M[ row ], -## and this is in general not possible. +## Called with a matrix object M, this operation +## returns a plain list of objects in the representation given by the +## value +## of M (provided that such a representation exists), +## where the i-th entry describes the i-th row of the input. ##

-## If the global option check is set to false then -## need not perform consistency checks. +## m1 := Matrix( Integers, [ [3,4,5], [7,8,9] ] );; +## gap> Print( RowsOfMatrix( m1 ) ); +## [ NewVector(IsPlistVectorRep,Integers,[ 3, 4, 5 ]), +## NewVector(IsPlistVectorRep,Integers,[ 7, 8, 9 ]) ] +## ]]> ## ## ## <#/GAPDoc> ## -DeclareOperationKernel( "[,]:=", [ IsMatrixOrMatrixObj, IsInt, IsInt, IsObject ], - ASS_MAT ); -#T We want to require also 'IsMutable' for the first argument, -#T but some package may have installed methods without this requirement. -#T Note that if we declare the operation twice, once with requirement -#T 'IsMutable' and once without, each method installation will show -#T a complaint that it matches more than one declaration. -DeclareSynonym( "SetMatElm", ASS_MAT ); +## This function is used for creating an isomorphic permutation group +## of a matrix group that consists of matrix objects. +## +## +## We assume that the matrix knows how to create suitable vector objects; +## entering a template vector as the second argument is not an option +## in this situation. +## +DeclareAttribute( "RowsOfMatrix", IsMatrixOrMatrixObj ); ############################################################################# @@ -1618,64 +1725,6 @@ DeclareOperation( "CompanionMatrix", [ IsUnivariatePolynomial, IsSemiring ] ); -############################################################################ -## -#A CompatibleVector( ) -## -## <#GAPDoc Label="CompatibleVector"> -## -## -## -## a vector object -## -## -## Called with a matrix object M with m rows, -## this operation returns a mutable zero vector object v of length -## m and in the representation given by the -## value -## of M (provided that such a representation exists). -##

-## The idea is that there should be an efficient way to -## form the product vM. -## -## -## <#/GAPDoc> -## -DeclareOperation( "CompatibleVector", [ IsMatrixOrMatrixObj ] ); - - -############################################################################ -## -#A RowsOfMatrix( ) -## -## <#GAPDoc Label="RowsOfMatrix"> -## -## -## -## a plain list -## -## -## Called with a matrix object M, this operation -## returns a plain list of objects in the representation given by the -## value -## of M (provided that such a representation exists), -## where the i-th entry describes the i-th row of the input. -## -## -## <#/GAPDoc> -## -## This function is used for creating an isomorphic permutation group -## of a matrix group that consists of matrix objects. -## -## -## We assume that the matrix knows how to create suitable vector objects; -## entering a template vector as the second argument is not an option -## in this situation. -## -DeclareAttribute( "RowsOfMatrix", IsMatrixOrMatrixObj ); - - ############################################################################# ## #F DefaultVectorRepForBaseDomain( ) @@ -1692,7 +1741,6 @@ DeclareGlobalFunction( "DefaultMatrixRepForBaseDomain" ); ## Operations for Row List Matrix Objects ## - ############################################################################ ## #O [ ] @@ -1710,6 +1758,12 @@ DeclareGlobalFunction( "DefaultMatrixRepForBaseDomain" ); ## this operation returns the pos-th row of M. ##

## It is not specified what happens if pos is larger. +##

+## m1 := Matrix( Integers, [ [2,3], [5,6], [8,9] ] );; +## gap> Print( m1[2] ); +## NewVector(IsPlistVectorRep,Integers,[ 5, 6 ]) +## ]]> ## ## ## <#/GAPDoc> @@ -1740,6 +1794,13 @@ DeclareOperation( "[]", [ IsRowListMatrix, IsPosInt ] ); ## M. ##

## In all other situations, it is not specified what happens. +##

+## m1 := Matrix( Integers, [ [2,3], [5,6], [8,9] ] );; +## gap> v1 := ZeroVector( 2, m1 );; +## gap> m1[2] := v1;; Unpack( m1 ); +## [ [ 2, 3 ], [ 0, 0 ], [ 8, 9 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -1764,6 +1825,12 @@ DeclareOperation( "[]:=", [ IsRowListMatrix, IsPosInt, IsVectorObj ] ); ## row list matrix with the same representation as M, ## whose rows are identical to the rows at the positions ## in the list poss in M. +##

+## m1 := Matrix( Integers, [ [0,1], [3,4], [6,7], [9,0] ] );; +## gap> m2 := m1{ [2..3] };; Print( m2 ); +## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ 3, 4 ], [ 6, 7 ] ]) +## ]]> ## ## ## <#/GAPDoc> @@ -1792,6 +1859,13 @@ DeclareOperation( "{}", [IsRowListMatrix,IsList] ); ##

## It is not specified what happens if the resulting range of row positions ## is not dense. +##

+## m1 := Matrix( Integers, [ [1,1], [2,2], [3,3], [4,4], [5,5] ] );; +## gap> m2 := Matrix( [ [7,7], [8,8], [9,9] ], m1 );; +## gap> ## the following appears to fail at present +## gap> ## m1{ [2..4] } := m2; +## ]]> ## ## ## <#/GAPDoc> @@ -1814,6 +1888,12 @@ DeclareOperation( "{}:=", [IsRowListMatrix,IsList,IsRowListMatrix] ); ## IsBound( M[ pos ] ) returns ## true if pos is at most the number of rows of M, ## and false otherwise. +##

+## m1 := Matrix( Integers, [ [3,4,5], [7,8,9] ] );; +## gap> [ IsBound( m1[2] ), IsBound( m1[3] ) ]; +## [ true, false ] +## ]]> ## ## ## <#/GAPDoc> @@ -1836,6 +1916,12 @@ DeclareOperation( "IsBound[]", [ IsRowListMatrix, IsPosInt ] ); ## Unbind( M[ pos ] ) removes the last ## row. ## It is not specified what happens if pos has another value. +##

+## m1 := Matrix( Integers, [ [2,3], [5,6], [8,9] ] );; +## gap> Unbind( m1[3] ); Unpack( m1 ); +## [ [ 2, 3 ], [ 5, 6 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -1862,6 +1948,14 @@ DeclareOperation( "Unbind[]", [ IsRowListMatrix, IsPosInt ] ); ##

## If a positive integer pos is given then v is added in ## position pos, and all later rows are shifted up by one position. +##

+## m1 := Matrix( Integers, [ [2,3], [5,6], [8,9] ] );; +## gap> Add( m1, v1 ); Unpack( m1 ); +## [ [ 2, 3 ], [ 5, 6 ], [ 8, 9 ], [ 0, 0 ] ] +## gap> Add( m1, v1, 2 ); Unpack( m1 ); +## [ [ 2, 3 ], [ 0, 0 ], [ 5, 6 ], [ 8, 9 ], [ 0, 0 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -1884,11 +1978,21 @@ DeclareOperation( "Add", [ IsRowListMatrix, IsVectorObj, IsPosInt ] ); ## ## For a mutable row list matrix M, ## this operation removes the pos-th row and shifts the later rows -## down by one position. +## up by one position. ## The default for pos is the number of rows of M. ##

## If the pos-th row existed in M then it is returned, ## otherwise nothing is returned. +##

+## m1 := Matrix( Integers, [ [1,1], [2,2], [3,3], [4,4], [5,5] ] );; +## gap> v1 := Remove( m1 );; Unpack( v1 ); +## [ 5, 5 ] +## gap> Unpack( m1 ); +## [ [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ] ] +## gap> Remove( m1, 2 );; Unpack( m1 ); +## [ [ 1, 1 ], [ 3, 3 ], [ 4, 4 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -1914,6 +2018,13 @@ DeclareOperation( "Remove", [ IsRowListMatrix, IsPosInt ] ); ## values are equal, ## this operation appends the rows of M2 to the ## rows of M1. +##

+## m1 := Matrix( Integers, [ [3,4,5], [7,8,9] ] );; +## gap> m2 := Matrix( Integers, [ [1,0,1], [0,1,0] ] );; +## gap> Append( m1, m2 ); Unpack( m1 ); +## [ [ 3, 4, 5 ], [ 7, 8, 9 ], [ 1, 0, 1 ], [ 0, 1, 0 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -1959,6 +2070,10 @@ DeclareOperation( "Append", [ IsRowListMatrix, IsRowListMatrix ] ); ## (see ) of its rows, ## and the variant with two arguments returns the plain list of values ## of these rows under the function func. +##

+## ## ## ## <#/GAPDoc> @@ -1967,160 +2082,11 @@ DeclareOperation( "ListOp", [ IsRowListMatrix ] ); DeclareOperation( "ListOp", [ IsRowListMatrix, IsFunction ] ); -############################################################################# -## -## IsEmptyMatrix( ) -## -## <#GAPDoc Label="MatObj_IsEmptyMatrix"> -## -## -## A boolean -## -## Is true if the matrix object M either has zero columns -## or zero rows, and false otherwise. -## In other words, a matrix object is empty if it has no entries. -## -## -## <#/GAPDoc> -## -DeclareProperty( "IsEmptyMatrix", IsMatrixOrMatrixObj ); - - -############################################################################# -## -## TODO: -## -## Do we REALLY want to support and document the following feature? -## If yes then it is intended as permanent, -## although it contradicts the intended use of matrix objects. -## -## Is this a feature with a generic solution, -## such that the implementors of new kinds of matrix objects need not -## care about it? -## If not then it will be very annoying to be forced to support something -## which will not be used at all as long as the code is used as intended. -## (In particular, the documentation claims on the one hand that it is not -## compulsory to provide a compatible vector object representation for one's -## matrix object implementation, but the ``row access'' will force one to -## provide one.) - -############################################################################ -# In the following sense matrices behave like lists: -############################################################################ - -DeclareOperation( "[]", [IsMatrixOrMatrixObj,IsPosInt] ); # , -# This is guaranteed to return a vector object that has the property -# that changing it changes th row (?) of the matrix ! -# A matrix which is not a row-lists internally has to create an intermediate object that refers to some -# row within it to allow the old GAP syntax M[i][j] for read and write -# access to work. Note that this will never be particularly efficient -# for matrices which are not row-lists. Efficient code will have to use MatElm and -# SetMatElm instead. - -# TODO: ... resp. it will use use M[i,j] -# TODO: provide a default method which creates a proxy object for the given row -# and translates accesses to it to corresponding MatElm / SetMatElm calls; -# creating such a proxy object prints an InfoWarning; -# but for the method for plist matrices, no warning is shown, as it is efficient -# anyway - -# TODO: maybe also add GetRow(mat, i) and GetColumn(mat, i) ??? -# these return IsVectorObj objects. -# these again must be objects which are "linked" to the original matrix, as above... -# TODO: perhaps also have ExtractRow(mat, i) and ExtractColumn(mat, i) - - -############################################################################# -## -## Backwards compatibility -## -## We have to declare the operations/synonyms because otherwise -## the method installations in some packages may not work. -## We should remove them as soon as they are not used anymore. -## - -############################################################################# -## -#C IsRowVectorObj( ) -## -## Existing code which uses this name (most notably, the cvec package) -## should be supported for some time. -## -DeclareSynonym( "IsRowVectorObj", IsVectorObj ); - - -############################################################################# -## -#A DimensionsMat( ) -## -## only for backwards compatibility with existing code: -## -> [ NrRows( ), NrCols( ) ] -## -DeclareAttribute( "DimensionsMat", IsMatrixOrMatrixObj ); - - -############################################################################# -## -#A Length( ) -## -## They had been used in older versions. -## -DeclareAttribute( "Length", IsMatrixOrMatrixObj ); - - -############################################################################# -## -#O NewCompanionMatrix( , , ) -## -## This operation is intended for the installation of tag based methods for -## 'CompanionMatrix', such that 'CompanionMatrix' admits method dispatch -## based on . -## -## (Currently 'NewCompanionMatrix' is undocumented. -## Perhaps we can simply declare 'CompanionMatrix' itself as a tag based -## operation for the given requirement. -## This would work also for `DiagonalMatrix`, `RandomMatrix`, -## `ReflectionMatrix`, etc. -## We could even get rid of `NewMatrix`, `NewZeroMatrix`, -## `NewIdentityMatrix`, by declaring `Matrix`, `ZeroMatrix`, -## `IdentityMatrix` as tag based operations for the requirements in -## question, except that the ordering of the arguments for the four -## argument versions of `NewMatrix` and `Matrix` does not fit.) -## -DeclareTagBasedOperation( "NewCompanionMatrix", - [ IsOperation, IsUnivariatePolynomial, IsSemiring ] ); - - -############################################################################# -## -#O NewRowVector( ... ) -## -DeclareSynonym( "NewRowVector", NewVector ); - - -############################################################################# -## -#O Randomize( ... ) -## -## for backwards compatibility with the cvec package -## -DeclareOperation( "Randomize", [ IsVectorObj and IsMutable, IsRandomSource ] ); -DeclareOperation( "Randomize", [ IsMatrixOrMatrixObj and IsMutable, IsRandomSource ] ); - - -############################################################################# -## -#O [ , ] -#O [ , ]:= -## -DeclareOperation( "[]", [ IsMatrixOrMatrixObj, IsPosInt, IsPosInt ] ); -DeclareOperation( "[]:=", [ IsMatrixOrMatrixObj, IsPosInt, IsPosInt, IsObject ] ); - - ############################################################################ # Elementary matrix operations ############################################################################ # + ############################################################################ ## ## <#GAPDoc Label="MultMatrixRow"> @@ -2132,12 +2098,19 @@ DeclareOperation( "[]:=", [ IsMatrixOrMatrixObj, IsPosInt, IsPosInt, IsObject ] ## ## ##

-## Multiplies the i-th row of the mutable matrix mat with the scalar -## elm from the left in-place. +## Multiplies the i-th row of the mutable matrix mat +## with the scalar elm from the left in-place. ##

-## is a synonym of . This was chosen -## because linear combinations of rows of matrices are usually written as -## v \cdot A = [v_1, ... ,v_n] \cdot A which multiplies scalars from the left. +## is a synonym of . +## This was chosen because linear combinations of rows of matrices are usually +## written as v \cdot A = [v_1, ... ,v_n] \cdot A +## which multiplies scalars from the left. +##

+## m1 := Matrix( Integers, [ [2,3], [5,6], [8,9] ] );; +## gap> MultMatrixRow( m1, 2, -10 ); Unpack( m1 ); +## [ [ 2, 3 ], [ -50, -60 ], [ 8, 9 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -2174,12 +2147,20 @@ DeclareOperation( "MultMatrixRowRight", [ IsMatrixOrMatrixObj and IsMutable, IsI ## ## ##

-## Multiplies the i-th column of the mutable matrix M with the scalar -## elm from the right in-place. +## Multiplies the i-th column of the mutable matrix M +## with the scalar elm from the right in-place. +##

+## is a synonym of +## . +## This was chosen because linear combinations of columns of matrices +## are usually written as A \cdot v^T = A \cdot [v_1, ... ,v_n]^T +## which multiplies scalars from the right. ##

-## is a synonym of . This was -## chosen because linear combinations of columns of matrices are usually written as -## A \cdot v^T = A \cdot [v_1, ... ,v_n]^T which multiplies scalars from the right. +## m1 := Matrix( Integers, [ [3,4,5], [7,8,9] ] );; +## gap> MultMatrixColumn( m1, 2, -10 ); Unpack( m1 ); +## [ [ 3, -40, 5 ], [ 7, -80, 9 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -2197,8 +2178,8 @@ DeclareSynonym( "MultMatrixColumn", MultMatrixColumnRight); ## ## ##

-## Multiplies the i-th column of the mutable matrix M with the scalar -## elm from the left in-place. +## Multiplies the i-th column of the mutable matrix M +## with the scalar elm from the left in-place. ## ## ## <#/GAPDoc> @@ -2216,12 +2197,20 @@ DeclareOperation( "MultMatrixColumnLeft", [ IsMatrixOrMatrixObj and IsMutable, I ## ## ##

-## Adds the product of elm with the j-th row of the mutable matrix M to its i-th -## row in-place. The j-th row is multiplied with elm from the left. +## Adds the product of elm with the j-th row of the mutable +## matrix M to its i-th row in-place. +## The j-th row is multiplied with elm from the left. ##

-## is a synonym of . This was chosen -## because linear combinations of rows of matrices are usually written as -## v \cdot A = [v_1, ... ,v_n] \cdot A which multiplies scalars from the left. +## is a synonym of . +## This was chosen because linear combinations of rows of matrices are usually +## written as v \cdot A = [v_1, ... ,v_n] \cdot A +## which multiplies scalars from the left. +##

+## m1 := Matrix( Integers, [ [1,1,1], [2,2,2], [3,3,3] ] );; +## gap> AddMatrixRows( m1, 1, 3, 10 ); Unpack( m1 ); +## [ [ 31, 31, 31 ], [ 2, 2, 2 ], [ 3, 3, 3 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -2239,8 +2228,9 @@ DeclareSynonym( "AddMatrixRows", AddMatrixRowsLeft); ## ## ##

-## Adds the product of elm with the j-th row of the mutable matrix M to its i-th -## row in-place. The j-th row is multiplied with elm from the right. +## Adds the product of elm with the j-th row of the mutable +## matrix M to its i-th row in-place. +## The j-th row is multiplied with elm from the right. ## ## ## <#/GAPDoc> @@ -2258,12 +2248,21 @@ DeclareOperation( "AddMatrixRowsRight", [ IsMatrixOrMatrixObj and IsMutable, IsI ## ## ##

-## Adds the product of elm with the j-th column of the mutable matrix M to its i-th -## column in-place. The j-th column is multiplied with elm from the right. +## Adds the product of elm with the j-th column of the mutable +## matrix M to its i-th column in-place. +## The j-th column is multiplied with elm from the right. +##

+## is a synonym of +## . +## This was chosen because linear combinations of columns of matrices are +## usually written as A \cdot v^T = A \cdot [v_1, ... ,v_n]^T +## which multiplies scalars from the right. ##

-## is a synonym of . This was -## chosen because linear combinations of columns of matrices are usually written as -## A \cdot v^T = A \cdot [v_1, ... ,v_n]^T which multiplies scalars from the right. +## m1 := Matrix( Integers, [ [1,1,1], [2,2,2], [3,3,3] ] );; +## gap> AddMatrixColumns( m1, 1, 3, 10 ); Unpack( m1 ); +## [ [ 11, 1, 1 ], [ 22, 2, 2 ], [ 33, 3, 3 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -2303,6 +2302,12 @@ DeclareOperation( "AddMatrixColumnsLeft", [ IsMatrixOrMatrixObj and IsMutable, I ## the matrix M, or NrCols( M ) + 1 if the row is zero. ## If the optional argument from is given, the search starts after ## position from. +##

+## m1 := Matrix( Integers, [ [0,0,1,1,1], [1,0,0,1,1] ] );; +## gap> [ PositionNonZeroInRow( m1, 1 ), PositionNonZeroInRow( m1, 2, 2 ) ]; +## [ 3, 4 ] +## ]]> ## ## ## <#/GAPDoc> @@ -2321,6 +2326,12 @@ DeclareOperation( "PositionNonZeroInRow", [ IsMatrixOrMatrixObj, IsPosInt, IsInt ## ##

## Swaps the i-th row and j-th row of a mutable matrix M. +##

+## m1 := Matrix( Integers, [ [1,1], [2,2], [3,3], [4,4], [5,5] ] );; +## gap> SwapMatrixRows( m1, 2, 4 ); Unpack( m1 ); +## [ [ 1, 1 ], [ 4, 4 ], [ 3, 3 ], [ 2, 2 ], [ 5, 5 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -2338,6 +2349,12 @@ DeclareOperationKernel( "SwapMatrixRows", [ IsMatrixOrMatrixObj and IsMutable, I ## ##

## Swaps the i-th column and j-th column of a mutable matrix M. +##

+## m1 := Matrix( Integers, [ [1,2,3,4,5], [6,7,8,9,10] ] );; +## gap> SwapMatrixColumns( m1, 2, 4 ); Unpack( m1 ); +## [ [ 1, 4, 3, 2, 5 ], [ 6, 9, 8, 7, 10 ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -2407,7 +2424,8 @@ DeclareOperation( "AddMatrix", [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMa ## gap> MultMatrixRight(mat1, -2); ## gap> mat1; ## [ [ -2, -4 ], [ -6, -8 ] ] -## gap> MultMatrix(mat1, -2); # Note that this is the same as calling MultMatrixLeft(mat1, -2) +## gap> MultMatrix(mat1, -2); +## gap> # Note that this is the same as calling MultMatrixLeft(mat1, -2) ## gap> mat1; ## [ [ 4, 8 ], [ 12, 16 ] ] ## gap> A := FreeAssociativeAlgebra(Rationals, 2); @@ -2430,3 +2448,155 @@ DeclareOperation( "AddMatrix", [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMa DeclareOperation( "MultMatrixRight", [ IsMatrixOrMatrixObj and IsMutable, IsScalar ] ); DeclareOperation( "MultMatrixLeft", [ IsMatrixOrMatrixObj and IsMutable, IsScalar ] ); DeclareSynonym( "MultMatrix", MultMatrixLeft ); + + +############################################################################# +## +## IsEmptyMatrix( ) +## +## <#GAPDoc Label="MatObj_IsEmptyMatrix"> +## +## +## A boolean +## +## Is true if the matrix object M either has zero columns +## or zero rows, and false otherwise. +## In other words, a matrix object is empty if it has no entries. +## +## +## <#/GAPDoc> +## +DeclareProperty( "IsEmptyMatrix", IsMatrixOrMatrixObj ); + + +############################################################################# +## +## TODO: +## +## Do we REALLY want to support and document the following feature? +## If yes then it is intended as permanent, +## although it contradicts the intended use of matrix objects. +## +## Is this a feature with a generic solution, +## such that the implementors of new kinds of matrix objects need not +## care about it? +## If not then it will be very annoying to be forced to support something +## which will not be used at all as long as the code is used as intended. +## (In particular, the documentation claims on the one hand that it is not +## compulsory to provide a compatible vector object representation for one's +## matrix object implementation, but the ``row access'' will force one to +## provide one.) + +############################################################################ +# In the following sense matrices behave like lists: +############################################################################ + +DeclareOperation( "[]", [IsMatrixOrMatrixObj,IsPosInt] ); # , +# This is guaranteed to return a vector object that has the property +# that changing it changes th row (?) of the matrix ! +# A matrix which is not a row-lists internally has to create an intermediate object that refers to some +# row within it to allow the old GAP syntax M[i][j] for read and write +# access to work. Note that this will never be particularly efficient +# for matrices which are not row-lists. Efficient code will have to use MatElm and +# SetMatElm instead. + +# TODO: ... resp. it will use use M[i,j] +# TODO: provide a default method which creates a proxy object for the given row +# and translates accesses to it to corresponding MatElm / SetMatElm calls; +# creating such a proxy object prints an InfoWarning; +# but for the method for plist matrices, no warning is shown, as it is efficient +# anyway + +# TODO: maybe also add GetRow(mat, i) and GetColumn(mat, i) ??? +# these return IsVectorObj objects. +# these again must be objects which are "linked" to the original matrix, as above... +# TODO: perhaps also have ExtractRow(mat, i) and ExtractColumn(mat, i) + + +############################################################################# +## +## Backwards compatibility +## +## We have to declare the operations/synonyms because otherwise +## the method installations in some packages may not work. +## We should remove them as soon as they are not used anymore. +## + +############################################################################# +## +#C IsRowVectorObj( ) +## +## Existing code which uses this name (most notably, the cvec package) +## should be supported for some time. +## +DeclareSynonym( "IsRowVectorObj", IsVectorObj ); + + +############################################################################# +## +#A DimensionsMat( ) +## +## only for backwards compatibility with existing code: +## -> [ NrRows( ), NrCols( ) ] +## +DeclareAttribute( "DimensionsMat", IsMatrixOrMatrixObj ); + + +############################################################################# +## +#A Length( ) +## +## They had been used in older versions. +## +DeclareAttribute( "Length", IsMatrixOrMatrixObj ); + + +############################################################################# +## +#O NewCompanionMatrix( , , ) +## +## This operation is intended for the installation of tag based methods for +## 'CompanionMatrix', such that 'CompanionMatrix' admits method dispatch +## based on . +## +## (Currently 'NewCompanionMatrix' is undocumented. +## Perhaps we can simply declare 'CompanionMatrix' itself as a tag based +## operation for the given requirement. +## This would work also for `DiagonalMatrix`, `RandomMatrix`, +## `ReflectionMatrix`, etc. +## We could even get rid of `NewMatrix`, `NewZeroMatrix`, +## `NewIdentityMatrix`, by declaring `Matrix`, `ZeroMatrix`, +## `IdentityMatrix` as tag based operations for the requirements in +## question, except that the ordering of the arguments for the four +## argument versions of `NewMatrix` and `Matrix` does not fit.) +## +DeclareTagBasedOperation( "NewCompanionMatrix", + [ IsOperation, IsUnivariatePolynomial, IsSemiring ] ); + + +############################################################################# +## +#O NewRowVector( ... ) +## +DeclareSynonym( "NewRowVector", NewVector ); + + +############################################################################# +## +#O Randomize( ... ) +## +## for backwards compatibility with the cvec package +## +DeclareOperation( "Randomize", [ IsVectorObj and IsMutable, IsRandomSource ] ); +DeclareOperation( "Randomize", [ IsMatrixOrMatrixObj and IsMutable, IsRandomSource ] ); + + +############################################################################# +## +#O [ , ] +#O [ , ]:= +## +DeclareOperation( "[]", [ IsMatrixOrMatrixObj, IsPosInt, IsPosInt ] ); +DeclareOperation( "[]:=", [ IsMatrixOrMatrixObj, IsPosInt, IsPosInt, IsObject ] ); + + diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index b73e17a196..65ad5df236 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -1,10 +1,8 @@ gap> START_TEST("ExtractSubMatrix.tst"); - gap> IsBoundGlobal("EXTRACT_SUB_MATRIX"); true gap> EXTRACT_SUB_MATRIX = ExtractSubMatrix; true - gap> m1 := [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]; [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); @@ -12,7 +10,6 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] - # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -20,7 +17,6 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true - # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) > @@ -28,5 +24,4 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); < mutable compressed matrix 20x20 over GF(3) > gap> IsOne(m2); true - gap> STOP_TEST("ExtractSubMatrix.tst"); From ca03c6d9f91a451aead2fea6593e0cb63ff5ab96 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 7 May 2026 14:55:59 +0100 Subject: [PATCH 040/123] added examples for 26.13 and 26.14 --- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 65ad5df236..3f17d9a8d2 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -10,6 +10,7 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] + # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -17,6 +18,7 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true + # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) > From 0ee75556329ec5f751295933d50970a182399d3e Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 7 May 2026 15:18:57 +0100 Subject: [PATCH 041/123] added examples for 26.13 and 26.14 --- lib/matobj.gi | 2 +- lib/matobj2.gd | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/matobj.gi b/lib/matobj.gi index 4b5c1f72a8..a87274527e 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1159,7 +1159,7 @@ InstallMethod( MultVectorRight, ## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ 7, 12 ], [ 4, 7 ] ]) ## gap> Unpack( m3 * m4 ); ## [ [ 7, 12 ], [ 4, 7 ] ] -## gap> Unpack( m3^6 ); Unpack( m4^-1 ); +## gap> Unpack( m3^6 ); Unpack( m4^-1 ); ## [ [ 1, 6 ], [ 0, 1 ] ] ## [ [ 7, -5 ], [ -4, 3 ] ] ## ]]> diff --git a/lib/matobj2.gd b/lib/matobj2.gd index c4652e9152..58b77e14d7 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -652,7 +652,6 @@ DeclareOperation( "Matrix", [ IsList ]); ## gap> z5 := ZeroMatrix( IsGF2MatrixRep, GF(2), 2, 5 );; Display( z5 ); ## . . . . . ## . . . . . -## ]> ## ]]> ## ## @@ -1611,7 +1610,7 @@ DeclareOperationKernel( "CopySubMatrix", ## gap> m1 := Matrix( Integers, [ [2,3], [5,6], [8,9] ] );; ## gap> v1 := CompatibleVector( m1 );; Unpack( v1 ); ## [ 0, 0, 0 ] -## gap> v1[1] := -1;; v1[3] := -1;; Unpack( v1 ); +## gap> v1[1] := -1;; v1[3] := -1;; Unpack( v1 ); ## [ -1, 0, -1 ] ## gap> Print( v1 * m1 ); ## NewVector(IsPlistVectorRep,Integers,[ -10, -12 ]) @@ -2101,7 +2100,7 @@ DeclareOperation( "ListOp", [ IsRowListMatrix, IsFunction ] ); ## Multiplies the i-th row of the mutable matrix mat ## with the scalar elm from the left in-place. ##

-## is a synonym of . +## is a synonym of . ## This was chosen because linear combinations of rows of matrices are usually ## written as v \cdot A = [v_1, ... ,v_n] \cdot A ## which multiplies scalars from the left. From c28a132db76f0215a505fc135f5736bba651928f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 8 May 2026 11:34:48 +0100 Subject: [PATCH 042/123] Makefile.rules: add cleanall target, improve cleaning overall (#6378) --- Makefile.rules | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile.rules b/Makefile.rules index 1aec140fdd..74d62a9ca0 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -584,9 +584,13 @@ clean: rm -rf .libs rm -f doc/wsp.g rm -f cnf/GAP-* + rm -f configure~ src/config.h.in~ rmdir bin cnf dev doc extern src 2>/dev/null || : # remove dirs if they are now empty -.PHONY: clean distclean +cleanall: clean distclean clean-doc + rm -f src/config.h.in + +.PHONY: clean distclean cleanall ######################################################################## @@ -976,6 +980,7 @@ clean-doc: rm -f doc/*/chooser.html doc/*/manual*.pdf rm -f doc/*/*.{aux,bbl,blg,brf,idx,ilg,ind,lab,log,out,pnr,six,tex,toc} rm -f doc/manualbib.xml.bib + rm -f doc/ref/user_pref_list.xml # FIXME: we currently build the manual inside $srcdir; so we don't want "make clean" # to remove it, as other builds might share the manual. @@ -1007,6 +1012,7 @@ tst/testlibgap/%: build/obj/tst/testlibgap/%.c.o build/obj/tst/testlibgap/common clean: clean-testlibgap clean-testlibgap: rm -f ${LIBGAPTESTS} + rm -f $(addsuffix .out,$(LIBGAPTESTS)) # run all the tests in tst/testlibgap testlibgap: ${LIBGAPTESTS} @@ -1048,6 +1054,7 @@ tst/testkernel/%: build/obj/tst/testkernel/%.c.o libgap$(SHLIB_EXT) clean: clean-testkernel clean-testkernel: rm -f ${KERNELTESTS} + rm -f $(addsuffix .out,$(KERNELTESTS)) # run all the tests in tst/testkernel testkernel: ${KERNELTESTS} From 4bcb53b0eb7e143ae040dcaa9c9423690b02696c Mon Sep 17 00:00:00 2001 From: lhsoicher Date: Fri, 8 May 2026 13:01:14 +0100 Subject: [PATCH 043/123] Improve documentation of several action functions (#6370) Improve the documentation for the action functions - OnTuplesSets - OnTuplesTuples, - OnSetsTuples, - OnSetsSets, - OnSetsDisjointSets. --- lib/oprt.gd | 61 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/oprt.gd b/lib/oprt.gd index c369951114..20bae46045 100644 --- a/lib/oprt.gd +++ b/lib/oprt.gd @@ -2743,11 +2743,16 @@ DeclareGlobalFunction("OnLines"); ## ## ## implements the action on sets of sets. -## For the special case that the sets are pairwise disjoint, +## set must be a proper set whose entries are again proper sets +## (see ). +##

+## returns the proper set whose elements are +## the images obtained by applying the action function +## to x and g, +## for each element x of set. +##

+## For the special case that the elements of set are pairwise disjoint, ## it is possible to use . -## set must be a sorted list whose entries are again sorted lists, -## otherwise an error is triggered -## (see ). ## OnSetsSets( [ [ 1, 2 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 1, 4 ], [ 2, 3 ] ] @@ -2774,9 +2779,16 @@ DeclareGlobalFunction( "OnSetsSets" ); ## ## implements the action on sets of pairwise disjoint sets ## (see also ). -## set must be a sorted list whose entries are again sorted lists, -## otherwise an error is triggered -## (see ). +## set must be a proper set whose entries are pairwise +## disjoint proper sets. +## However, it is not checked that the entries of +## set are indeed pairwise disjoint. +##

+## returns the proper +## set whose elements are +## the images obtained by applying the action function +## to x and g, +## for each element x of set. ## ## ## <#/GAPDoc> @@ -2794,9 +2806,13 @@ DeclareGlobalFunction( "OnSetsDisjointSets" ); ## ## ## implements the action on sets of tuples. -## set must be a sorted list, -## otherwise an error is triggered -## (see ). +## set must be a proper set of lists without holes +## (see ). +##

+## returns the proper set whose elements are +## the images obtained by applying the action function +## to x and g, +## for each element x of set. ## OnSetsTuples( [ [ 1, 2 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 1, 4 ], [ 2, 3 ] ] @@ -2815,17 +2831,21 @@ DeclareGlobalFunction("OnSetsTuples"); ############################################################################# ## -#F OnTuplesSets( , ) +#F OnTuplesSets( , ) ## ## <#GAPDoc Label="OnTuplesSets"> ## -## +## ## ## ## implements the action on tuples of sets. -## set must be a list whose entries are again sorted lists, -## otherwise an error is triggered -## (see ). +## tup must be a list without holes whose entries are proper sets +## (see ). +##

+## returns the list of +## the corresponding images obtained by applying the action function +## to x and g, +## for each entry x of tup. ## OnTuplesSets( [ [ 2, 3 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 1, 3 ], [ 1, 4 ] ] @@ -2844,14 +2864,21 @@ DeclareGlobalFunction("OnTuplesSets"); ############################################################################# ## -#F OnTuplesTuples( , ) +#F OnTuplesTuples( , ) ## ## <#GAPDoc Label="OnTuplesTuples"> ## -## +## ## ## ## implements the action on tuples of tuples. +## tup must be a list without holes whose entries are again +## lists without holes. +##

+## returns the list of +## the corresponding images obtained by applying the action function +## to x and g, +## for each entry x of the list tup. ## OnTuplesTuples( [ [ 2, 3 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 3, 1 ], [ 1, 4 ] ] From ce84021e5802b82915e5e047638bf726df56cd56 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 22 Apr 2026 02:25:33 +0200 Subject: [PATCH 044/123] Faster {Copy,Extract}Sub{Matrix,Vector} for plist matrices/vectors (#6329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... by avoiding some method dispatch, providing optimized methods using `{...}` syntax, and turning ExtractSubVector, CopySubVector, ExtractSubMatrix, and CopySubMatrix into kernel ops. Then run some benchmarks via `benchmark/matobj/bench-submat.g` and the new `benchmark/matobj/bench-subvec.g`. Before: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 129 µs per iteration; 7749 iterations per second; (200 iterations) Testing ExtractSubMatrix: 720 µs per iteration; 1388 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 342 µs per iteration; 2921 iterations per second; (200 iterations) Testing CopySubMatrix: 1032 µs per iteration; 969 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 167 µs per iteration; 5999 iterations per second; (200 iterations) Testing ExtractSubMatrix: 3288 µs per iteration; 304 iterations per second; (92 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1992 µs per iteration; 502 iterations per second; (151 iterations) Testing CopySubMatrix: 2606 µs per iteration; 384 iterations per second; (116 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 393 µs per iteration; 2542 iterations per second; (200 iterations) Testing CopySubVector: 2324 µs per iteration; 430 iterations per second; (130 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 441 µs per iteration; 2266 iterations per second; (200 iterations) Testing CopySubVector: 2458 µs per iteration; 407 iterations per second; (123 iterations) After: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 136 µs per iteration; 7355 iterations per second; (200 iterations) Testing ExtractSubMatrix: 140 µs per iteration; 7135 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 301 µs per iteration; 3319 iterations per second; (200 iterations) Testing CopySubMatrix: 299 µs per iteration; 3347 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 154 µs per iteration; 6490 iterations per second; (200 iterations) Testing ExtractSubMatrix: 146 µs per iteration; 6854 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1895 µs per iteration; 528 iterations per second; (159 iterations) Testing CopySubMatrix: 1935 µs per iteration; 517 iterations per second; (156 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 428 µs per iteration; 2336 iterations per second; (200 iterations) Testing CopySubVector: 453 µs per iteration; 2209 iterations per second; (200 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 427 µs per iteration; 2344 iterations per second; (200 iterations) Testing CopySubVector: 460 µs per iteration; 2172 iterations per second; (200 iterations) So overall the Copy/Extract methods are now more or less on par with the code using `{...}` syntax. But actually this `ExtractSubMatrix` for a GF(2) rowlist is now *faster* than the optimized one for a compressed GF(2) matrix: +----------------------------------------------------------+ | Testing submatrix extraction for GF(2) compressed matrix | +----------------------------------------------------------+ Testing m{}{}: 1057 µs per iteration; 946 iterations per second; (200 iterations) Testing ExtractSubMatrix: 1618 µs per iteration; 618 iterations per second; (186 iterations) A substantial part of that is due to the the `ExtractSubMatrix` method for `IsGF2MatrixRep` calling `ConvertToMatrixRepNC(mm,2)`; after removing that, it went down from 1618 to 392 µs (which is still worse). --- AI assistance: Codex implemented the kernel plumbing, method cleanup, and test updates. It also created `benchmark/matobj/bench-subvec.g`. Co-authored-by: Codex --- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 3f17d9a8d2..7f80e2706b 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -26,4 +26,8 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); < mutable compressed matrix 20x20 over GF(3) > gap> IsOne(m2); true + +gap> m2 := IdentityMatrix( Integers, 4 );; +gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); +[ [ 0, 1 ], [ 1, 0 ] ] gap> STOP_TEST("ExtractSubMatrix.tst"); From 4ba4b8ec6995f955242bf073899ffc357eac2d6f Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 30 Apr 2026 15:04:45 +0100 Subject: [PATCH 045/123] examples for Matrix --- lib/matobj2.gd | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 58b77e14d7..6ca0cc1530 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1301,6 +1301,70 @@ DeclareGlobalFunction( "ConcatenationOfVectors" ); ## gap> v1 := Vector( Rationals, [-5..5] );; ## gap> v2 := ExtractSubVector( v1, [1,3,5,7,9,11] );; Print( v2 ); ## NewVector(IsPlistVectorRep,Rationals,[ -5, -3, -1, 1, 3, 5 ]) +## In the remaining cases with two arguments, +## the first argument is a list or a vector object +## that defines the entries of the result, +## and the second argument is a vector object whose +## and +## are taken for the +## result. +##

+## The variant Vector( v1, v2 ) +## is supported also for the case that v2 is a row vector but not +## a vector object. +## In this situation, the result is a row vector that is equal to +## v1 and whose internal representation fits to that of v2. +##

+## If only a list list is given then both the +## and the +## are guessed from +## this list. +##

+## If a filter filt is given as the first argument then +## a vector object is returned that has +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the vector object +## v, respectively. +##

+## If the global option check is set to false then +## +## need not perform consistency checks. +##

+## If the +## value of the result implies then the result is +## mutable if and only if the argument that determines the entries of the +## result (list, v, v1) is mutable. +##

+## In the case of a mutable result, it is not guaranteed that +## the given list of entries is copied. +##

+## Default methods for +## +## delegate to . +##

+## v1 := Vector( Integers, [3,4,7,8] );; Print( v1 ); +## NewVector(IsPlistVectorRep,Integers,[ 3, 4, 7, 8 ]) +## gap> v2 := Vector( Rationals, v1 );; Print( v2 ); +## NewVector(IsPlistVectorRep,Rationals,[ 3, 4, 7, 8 ]) +## gap> v3 := Vector( [ 11..13], v1) ;; Print( v3 ); +## NewVector(IsPlistVectorRep,Integers,[ 11, 12, 13 ]) +## gap> v0 := [6..9];; IsVector( v0 ); +## true +## gap> Print( Vector( v0, v1 ) ); +## NewVector(IsPlistVectorRep,Integers,[ 6, 7, 8, 9 ]) +## gap> v4 := Vector( [ 2, 5/2, 7/3, 3 ] );; Print( v4 ); +## NewVector(IsPlistVectorRep,Rationals,[ 2, 5/2, 7/3, 3 ]) +## gap> v5 := Vector( IsGF2VectorRep, GF(2), [ 0, 1, 2 ]*Z(2)^0 );; +## gap> Print( v5 ); +## [ 0*Z(2), Z(2)^0, 0*Z(2) ] +## gap> v6 := Vector( IsZmodnZVectorRep, ZmodnZ(8), v1 ); +## +## gap> BaseDomain( v6 ); +## (Integers mod 8) +## gap> v7 := Vector( IsZmodnZVectorRep, ZmodnZ(12), v0 ); +## ## ]]> ## ## @@ -1724,6 +1788,185 @@ DeclareOperation( "CompanionMatrix", [ IsUnivariatePolynomial, IsSemiring ] ); +############################################################################# +## +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , ) +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , ) +#O Matrix( ) +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , , , ) +#O Matrix( , , ) +## +## <#GAPDoc Label="MatObj_Matrix"> +## +## Matrix +## +## +## +## +## +## +## a matrix object +## +## If a semiring R is given as the first argument then +## a matrix object is returned whose +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the matrix object +## matobj, respectively. +## Here list can be either a list of plain lists that describe the +## entries of the rows, or a flat list of the entries in row major order, +## where ncols defines the number of columns. +##

+## In those cases where the last argument is a matrix object, +## the first argument is a list or a matrix object +## that defines (together with ncols if applicable) the entries of +## the result, and the +## and +## of the last argument +## are taken for the result. +##

+## If only a list list and perhaps ncols is given +## then both the +## and the +## are guessed from +## the list. +##

+## In the remaining cases a filter filt is given as the +## first argument and a matrix object is returned that has +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the matrix object +## M, respectively. +##

+## If the global option check is set to false then +## +## need not perform consistency checks. +##

+## If the +## value of the result implies then the result is +## mutable if and only if the argument that determines the entries of the +## result (list or matobj) is mutable. +##

+## In the case of a mutable result, it is guaranteed that the given list +## list is copied in the sense of , +## and if list is a nested list then it is not guaranteed +## that also the entries of list are copied. +##

+## Default methods for +## +## delegate to . +## m1 := Matrix( Integers, [ [3,4,5], [6,7,8] ] );; Print( m1 ); +## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ 3, 4, 5 ], [ 6, 7, 8 ] ]) +## gap> m2 := Matrix( Rationals, [10..30], 7 );; Display( m2 ); +## <3x7-matrix over Rationals: +## [[ 10 .. 16 ] +## [ 17 .. 23 ] +## [ 24 .. 30 ] +## ]> +gap> Print( Matrix( Integers, m2 ) ); +NewMatrix(IsPlistMatrixRep,Integers,7, +[ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) +gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); +NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) +gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); +NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) +gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); +true +gap> Print( Matrix( m0, m1 ) ); +NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) +gap> Print( Matrix( [-9..-4], 3, m1 ) ); +NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) +gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); +NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) +gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +gap> Display( m6 ); + 1 . 1 + . 1 . +gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); + +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList ] ); +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsList ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsList ]); + + +############################################################################ +## +#A CompatibleVector( ) +## +## <#GAPDoc Label="CompatibleVector"> +## +## +## +## a vector object +## +## +## Called with a matrix object M with m rows, +## this operation returns a mutable zero vector object v of length +## m and in the representation given by the +## value +## of M (provided that such a representation exists). +##

+## The idea is that there should be an efficient way to +## form the product vM. +## +## +## <#/GAPDoc> +## +DeclareOperation( "CompatibleVector", [ IsMatrixOrMatrixObj ] ); + + +############################################################################ +## +#A RowsOfMatrix( ) +## +## <#GAPDoc Label="RowsOfMatrix"> +## +## +## +## a plain list +## +## +## Called with a matrix object M, this operation +## returns a plain list of objects in the representation given by the +## value +## of M (provided that such a representation exists), +## where the i-th entry describes the i-th row of the input. +## +## +## <#/GAPDoc> +## +## This function is used for creating an isomorphic permutation group +## of a matrix group that consists of matrix objects. +## +## +## We assume that the matrix knows how to create suitable vector objects; +## entering a template vector as the second argument is not an option +## in this situation. +## +DeclareAttribute( "RowsOfMatrix", IsMatrixOrMatrixObj ); + + ############################################################################# ## #F DefaultVectorRepForBaseDomain( ) From 384ad09741ca4680b920f9c7ec103611d0251e9d Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 17:32:19 +0100 Subject: [PATCH 046/123] very minor change --- lib/matobj.gi | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/matobj.gi b/lib/matobj.gi index a87274527e..58e4184e6d 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1151,15 +1151,12 @@ InstallMethod( MultVectorRight, ## [ [ 3, 0, 3 ], [ 0, 3, 0 ] ] ## [ [ 5, 0, 5 ], [ 0, 5, 0 ] ] ## [ [ 1/2, 0, 1/2 ], [ 0, 1/2, 0 ] ] -## gap> m3 := Matrix( Integers, [ [1,1], [0,1] ] ); -## <2x2-matrix over Integers> ## gap> m3 := Matrix( Integers, [ [1,1], [0,1] ] );; ## gap> m4 := Matrix( Integers, [ [3,5], [4,7] ] );; ## gap> Print( m3 * m4 ); ## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ 7, 12 ], [ 4, 7 ] ]) -## gap> Unpack( m3 * m4 ); +## gap> Unpack( m3 * m4 ); Unpack( m3^6 ); Unpack( m4^-1 ); ## [ [ 7, 12 ], [ 4, 7 ] ] -## gap> Unpack( m3^6 ); Unpack( m4^-1 ); ## [ [ 1, 6 ], [ 0, 1 ] ] ## [ [ 7, -5 ], [ -4, 3 ] ] ## ]]> From ed61025eafde453a447b9e957b8195bf944d85db Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 18:02:53 +0100 Subject: [PATCH 047/123] fixed problem which arose during rebase --- lib/matobj2.gd | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 6ca0cc1530..ddc2983e25 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1870,27 +1870,27 @@ DeclareOperation( "CompanionMatrix", ## [ 17 .. 23 ] ## [ 24 .. 30 ] ## ]> -gap> Print( Matrix( Integers, m2 ) ); -NewMatrix(IsPlistMatrixRep,Integers,7, -[ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) -gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); -NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) -gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); -NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) -gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); -true -gap> Print( Matrix( m0, m1 ) ); -NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) -gap> Print( Matrix( [-9..-4], 3, m1 ) ); -NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) -gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); -NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) -gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; -gap> Display( m6 ); - 1 . 1 - . 1 . -gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); - +## gap> Print( Matrix( Integers, m2 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,7, +## [ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) +## gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); +## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) +## gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) +## gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); +## true +## gap> Print( Matrix( m0, m1 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) +## gap> Print( Matrix( [-9..-4], 3, m1 ) ); +## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) +## gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); +## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) +## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +## gap> Display( m6 ); +## 1 . 1 +## . 1 . +## gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); +## ## ]]> ## ## From 6cce307af6fea1f8378f2dfa57bf9aabeff1d162 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 18:14:35 +0100 Subject: [PATCH 048/123] fixed another rebase problem --- lib/matobj2.gd | 121 ------------------------------------------------- 1 file changed, 121 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index ddc2983e25..2e5049e7ce 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1788,127 +1788,6 @@ DeclareOperation( "CompanionMatrix", [ IsUnivariatePolynomial, IsSemiring ] ); -############################################################################# -## -#O Matrix( , ) -#O Matrix( , , ) -#O Matrix( , ) -#O Matrix( , ) -#O Matrix( , , ) -#O Matrix( , ) -#O Matrix( ) -#O Matrix( , ) -#O Matrix( , , ) -#O Matrix( , , , ) -#O Matrix( , , ) -## -## <#GAPDoc Label="MatObj_Matrix"> -## -## Matrix -## -## -## -## -## -## -## a matrix object -## -## If a semiring R is given as the first argument then -## a matrix object is returned whose -## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the matrix object -## matobj, respectively. -## Here list can be either a list of plain lists that describe the -## entries of the rows, or a flat list of the entries in row major order, -## where ncols defines the number of columns. -##

-## In those cases where the last argument is a matrix object, -## the first argument is a list or a matrix object -## that defines (together with ncols if applicable) the entries of -## the result, and the -## and -## of the last argument -## are taken for the result. -##

-## If only a list list and perhaps ncols is given -## then both the -## and the -## are guessed from -## the list. -##

-## In the remaining cases a filter filt is given as the -## first argument and a matrix object is returned that has -## -## value filt, is defined over the base domain R, -## and has the entries given by the list list or the matrix object -## M, respectively. -##

-## If the global option check is set to false then -## -## need not perform consistency checks. -##

-## If the -## value of the result implies then the result is -## mutable if and only if the argument that determines the entries of the -## result (list or matobj) is mutable. -##

-## In the case of a mutable result, it is guaranteed that the given list -## list is copied in the sense of , -## and if list is a nested list then it is not guaranteed -## that also the entries of list are copied. -##

-## Default methods for -## -## delegate to . -## m1 := Matrix( Integers, [ [3,4,5], [6,7,8] ] );; Print( m1 ); -## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ 3, 4, 5 ], [ 6, 7, 8 ] ]) -## gap> m2 := Matrix( Rationals, [10..30], 7 );; Display( m2 ); -## <3x7-matrix over Rationals: -## [[ 10 .. 16 ] -## [ 17 .. 23 ] -## [ 24 .. 30 ] -## ]> -## gap> Print( Matrix( Integers, m2 ) ); -## NewMatrix(IsPlistMatrixRep,Integers,7, -## [ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) -## gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); -## NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) -## gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); -## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) -## gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); -## true -## gap> Print( Matrix( m0, m1 ) ); -## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) -## gap> Print( Matrix( [-9..-4], 3, m1 ) ); -## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) -## gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); -## NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) -## gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; -## gap> Display( m6 ); -## 1 . 1 -## . 1 . -## gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); -## -## ]]> -## -## -## <#/GAPDoc> -## -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList ] ); -DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsList ] ); -DeclareOperation( "Matrix", [ IsSemiring, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsInt, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ] ); -DeclareOperation( "Matrix", [ IsList, IsInt ] ); -DeclareOperation( "Matrix", [ IsList ]); - - ############################################################################ ## #A CompatibleVector( ) From 14d9cfe795096c93ea9727f4a5ec7476fb255add Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 18:23:41 +0100 Subject: [PATCH 049/123] fixed another rebase problem --- lib/matobj2.gd | 58 -------------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 2e5049e7ce..a6b3a0db31 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1788,64 +1788,6 @@ DeclareOperation( "CompanionMatrix", [ IsUnivariatePolynomial, IsSemiring ] ); -############################################################################ -## -#A CompatibleVector( ) -## -## <#GAPDoc Label="CompatibleVector"> -## -## -## -## a vector object -## -## -## Called with a matrix object M with m rows, -## this operation returns a mutable zero vector object v of length -## m and in the representation given by the -## value -## of M (provided that such a representation exists). -##

-## The idea is that there should be an efficient way to -## form the product vM. -## -## -## <#/GAPDoc> -## -DeclareOperation( "CompatibleVector", [ IsMatrixOrMatrixObj ] ); - - -############################################################################ -## -#A RowsOfMatrix( ) -## -## <#GAPDoc Label="RowsOfMatrix"> -## -## -## -## a plain list -## -## -## Called with a matrix object M, this operation -## returns a plain list of objects in the representation given by the -## value -## of M (provided that such a representation exists), -## where the i-th entry describes the i-th row of the input. -## -## -## <#/GAPDoc> -## -## This function is used for creating an isomorphic permutation group -## of a matrix group that consists of matrix objects. -## -## -## We assume that the matrix knows how to create suitable vector objects; -## entering a template vector as the second argument is not an option -## in this situation. -## -DeclareAttribute( "RowsOfMatrix", IsMatrixOrMatrixObj ); - - ############################################################################# ## #F DefaultVectorRepForBaseDomain( ) From 7b0f3afbd78991b2068beaf6f789807d549b654d Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 19:07:28 +0100 Subject: [PATCH 050/123] remove blank lines in test file --- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 3 --- 1 file changed, 3 deletions(-) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 7f80e2706b..897430ac91 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -10,7 +10,6 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] - # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -18,7 +17,6 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true - # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) > @@ -26,7 +24,6 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); < mutable compressed matrix 20x20 over GF(3) > gap> IsOne(m2); true - gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] From c637dcbaefdae50195b2b34b1ae8ef625f6d327e Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 20:08:28 +0100 Subject: [PATCH 051/123] finding it hard to fix ExtractSubMatrix.tst --- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 897430ac91..445c4d82e8 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -10,6 +10,7 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] + # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -17,6 +18,7 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true + # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) > From 550f275a23d8e7f9c9fa005443f5db8042757da1 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 20:21:39 +0100 Subject: [PATCH 052/123] fix missing end of example --- lib/matobj2.gd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index a6b3a0db31..6a153401e2 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1301,6 +1301,8 @@ DeclareGlobalFunction( "ConcatenationOfVectors" ); ## gap> v1 := Vector( Rationals, [-5..5] );; ## gap> v2 := ExtractSubVector( v1, [1,3,5,7,9,11] );; Print( v2 ); ## NewVector(IsPlistVectorRep,Rationals,[ -5, -3, -1, 1, 3, 5 ]) +## ]]> +##

## In the remaining cases with two arguments, ## the first argument is a list or a vector object ## that defines the entries of the result, From 20f9989c312afbd56718e8a226ca3f4a6c19def1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 8 May 2026 18:48:30 +0200 Subject: [PATCH 053/123] Fix CI with GAP.jl (#6381) --- .github/workflows/gapjl.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gapjl.yml b/.github/workflows/gapjl.yml index 5e3a5ae291..626f1a52a1 100644 --- a/.github/workflows/gapjl.yml +++ b/.github/workflows/gapjl.yml @@ -56,7 +56,7 @@ jobs: run: | using Pkg if "${{ matrix.gapjl-version }}" == "latest-release" - Pkg.add("GAP") + Pkg.develop("GAP") else Pkg.add(;name="GAP", rev="${{ matrix.gapjl-version }}") end @@ -77,7 +77,7 @@ jobs: make -j`nproc` - name: "Override bundled GAP" run: | - julia --proj=override $GAPJLPATH/etc/setup_override_dir.jl /tmp/GAPROOT /tmp/gap_jll_override --enable-Werror + julia --project=$GAPJLPATH $GAPJLPATH/etc/setup_override_dir.jl /tmp/GAPROOT /tmp/gap_jll_override --enable-Werror - name: "Run tests" run: | - julia --proj=override $GAPJLPATH/etc/run_with_override.jl /tmp/gap_jll_override --depwarn=error -e "using Pkg; Pkg.test(\"GAP\")" + julia --project=$GAPJLPATH $GAPJLPATH/etc/run_with_override.jl /tmp/gap_jll_override --depwarn=error -e "using Pkg; Pkg.test(\"GAP\")" From b157197d5435f66f0c1a89d3b85718f5c019b19e Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Sat, 9 May 2026 05:25:06 +0200 Subject: [PATCH 054/123] Fix an inconsistent ordering of conjugacy classes (#6382) --- lib/ctblsymm.gi | 2 +- tst/testinstall/ctbl.tst | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/ctblsymm.gi b/lib/ctblsymm.gi index 74230ddc77..a15ca95f5b 100644 --- a/lib/ctblsymm.gi +++ b/lib/ctblsymm.gi @@ -1232,7 +1232,7 @@ InstallMethod( Irr, # Compute the correspondence of classes. cp:= gentbl.classparam[1]( deg ); perm:= []; - for i in ConjugacyClasses( G ) do + for i in ConjugacyClasses( cG ) do i:= List( Orbits( SubgroupNC( G, [ Representative(i) ] ), dom ), Length ); Sort( i ); diff --git a/tst/testinstall/ctbl.tst b/tst/testinstall/ctbl.tst index 47cba12b4e..f8d23bbc13 100644 --- a/tst/testinstall/ctbl.tst +++ b/tst/testinstall/ctbl.tst @@ -381,6 +381,15 @@ true gap> IsPerfectCharacterTable( t ); false +# test another bugfix +gap> G:= SymmetricGroup( 2 );; +gap> SetConjugacyClasses( G, +> List( [ (1,2), () ], x -> ConjugacyClass( G, x ) ) ); +gap> t:= CharacterTable( G );; +gap> lin:= Irr( t );; +gap> lin[1][1]; +1 + # compute indicators gap> t:= CharacterTable( SymmetricGroup( 4 ) );; gap> Indicator( t, 2 ); @@ -434,19 +443,19 @@ gap> HasIsIrreducibleCharacter( TrivialCharacter( SymmetricGroup( 4 ) ) ); true # concurring 'Irr' methods -gap> G:= SmallGroup( 24, 5 );; +gap> G:= PcGroupCode( 221729, 24 );; gap> IsSupersolvable( G ); true gap> Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Baum-Clausen Algorithm" -gap> G:= SmallGroup( 24, 5 );; +gap> G:= PcGroupCode( 221729, 24 );; gap> IsSupersolvable( G ); true gap> IrrConlon( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Conlon's Algorithm" -gap> G:= SmallGroup( 24, 5 );; +gap> G:= PcGroupCode( 221729, 24 );; gap> IrrDixonSchneider( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Dixon's Algorithm" From 8ad206d589ac0853665412d2f7ebecaf98ed6f70 Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Sat, 9 May 2026 13:01:31 +0800 Subject: [PATCH 055/123] scanner: don't print EOF sentinel as line context on syntax error (#6380) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a syntax error fires after the scanner has advanced past EOF — e.g. parsing `h := ;` via READ_ALL_COMMANDS from a string with no trailing newline — the input-line buffer is refilled with GAP's end-of-input sentinel (\377) before SyntaxErrorOrWarning() runs. SyntaxErrorOrWarning() then printed the buffer verbatim as the line context, leaking a literal 0xFF byte to *errout*. On a tty this is harmless: the byte either gets eaten by the terminal or shown as some replacement glyph. But anything that captures *errout* programmatically — log files, the JupyterKernel package, an OutputTextFile redirect — sees the stray byte. JSON/UTF-8 has no encoding for it, so a Jupyter front-end renders it as a literal `ÿ` just below the error message. Skip the line print (and the corresponding caret) when the line buffer is the bare sentinel. The fix is local to SyntaxErrorOrWarning and doesn't change tty behaviour: the line-context print was already useless in this case, since the scanner had moved past the offending line. Add a testspecial regression that reproduces the leak via READ_ALL_COMMANDS + an ERROR_OUTPUT redirect to a temp file, then checks that the captured bytes contain the error message but not \377. --- src/scanner.c | 22 ++++++++---- tst/testspecial/syntax-err-eof-sentinel.g | 33 +++++++++++++++++ tst/testspecial/syntax-err-eof-sentinel.g.out | 36 +++++++++++++++++++ 3 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 tst/testspecial/syntax-err-eof-sentinel.g create mode 100644 tst/testspecial/syntax-err-eof-sentinel.g.out diff --git a/src/scanner.c b/src/scanner.c index 3620454218..cc607b7582 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -62,13 +62,23 @@ static void SyntaxErrorOrWarning(ScannerState * s, Pr(" in %g:%d", (Int)name, GetInputLineNumber(s->input)); Pr("\n", 0, 0); - // print the current line + // print the current line — but skip the line print, and the + // caret below, if the buffer has been replaced by the scanner's + // end-of-input sentinel (0xFF). That happens when the syntax + // error fires after parsing has advanced past the offending + // line (e.g. `h := ;` parsed from a string with no trailing + // newline): the line buffer is refilled at EOF before the + // error is reported, so the pretty-printed context would leak + // a literal 0xFF byte to *errout* with no caret to anchor it. const char * line = GetInputLineBuffer(s->input); const UInt len = strlen(line); - if (len > 0 && line[len-1] != '\n') - Pr("%s\n", (Int)line, 0); - else - Pr("%s", (Int)line, 0); + const int line_is_sentinel = (len == 0 || line[0] == '\377'); + if (!line_is_sentinel) { + if (line[len-1] != '\n') + Pr("%s\n", (Int)line, 0); + else + Pr("%s", (Int)line, 0); + } // print a '^' pointing to the current position Int startPos = s->SymbolStartPos[tokenoffset]; @@ -83,7 +93,7 @@ static void SyntaxErrorOrWarning(ScannerState * s, pos = GetInputLinePosition(s->input); } - if (0 < pos && startPos <= pos) { + if (!line_is_sentinel && 0 < pos && startPos <= pos) { Int i; for (i = 0; i < startPos; i++) { if (line[i] == '\t') diff --git a/tst/testspecial/syntax-err-eof-sentinel.g b/tst/testspecial/syntax-err-eof-sentinel.g new file mode 100644 index 0000000000..06ea34bcd4 --- /dev/null +++ b/tst/testspecial/syntax-err-eof-sentinel.g @@ -0,0 +1,33 @@ +# Regression test for a 0xFF byte leak in syntax-error context lines. +# +# When a syntax error fires after the scanner has advanced past EOF +# (e.g. parsing "h := ;" via READ_ALL_COMMANDS from a string with no +# trailing newline), the input-line buffer is replaced with the +# scanner's end-of-input sentinel (0xFF). Before the fix in +# src/scanner.c the SyntaxErrorOrWarning() pretty-printer would dump +# that sentinel verbatim alongside the error message — visible as a +# stray `ÿ` glyph in any UTF-8 / log-file consumer of *errout* +# (e.g. the JupyterKernel package). +errFile := Filename(DirectoryTemporary(), "syntax.log");; +errStream := OutputTextFile(errFile, false);; +SetPrintFormattingStatus(errStream, false);; + +MakeReadWriteGlobal("ERROR_OUTPUT");; +saved := ERROR_OUTPUT;; +ERROR_OUTPUT := errStream;; +MakeReadOnlyGlobal("ERROR_OUTPUT");; + +READ_ALL_COMMANDS(InputTextString("h := ;"), false, false, IdFunc);; + +MakeReadWriteGlobal("ERROR_OUTPUT");; +ERROR_OUTPUT := saved;; +MakeReadOnlyGlobal("ERROR_OUTPUT");; +CloseStream(errStream);; + +inStream := InputTextFile(errFile);; +captured := ReadAll(inStream);; +CloseStream(inStream);; + +Print("contains-eof-sentinel: ", '\377' in captured, "\n"); +Print("contains-error-message: ", + PositionSublist(captured, "expression expected") <> fail, "\n"); diff --git a/tst/testspecial/syntax-err-eof-sentinel.g.out b/tst/testspecial/syntax-err-eof-sentinel.g.out new file mode 100644 index 0000000000..5dc7161cb8 --- /dev/null +++ b/tst/testspecial/syntax-err-eof-sentinel.g.out @@ -0,0 +1,36 @@ +gap> # Regression test for a 0xFF byte leak in syntax-error context lines. +gap> # +gap> # When a syntax error fires after the scanner has advanced past EOF +gap> # (e.g. parsing "h := ;" via READ_ALL_COMMANDS from a string with no +gap> # trailing newline), the input-line buffer is replaced with the +gap> # scanner's end-of-input sentinel (0xFF). Before the fix in +gap> # src/scanner.c the SyntaxErrorOrWarning() pretty-printer would dump +gap> # that sentinel verbatim alongside the error message — visible as a +gap> # stray `ÿ` glyph in any UTF-8 / log-file consumer of *errout* +gap> # (e.g. the JupyterKernel package). +gap> errFile := Filename(DirectoryTemporary(), "syntax.log");; +gap> errStream := OutputTextFile(errFile, false);; +gap> SetPrintFormattingStatus(errStream, false);; +gap> +gap> MakeReadWriteGlobal("ERROR_OUTPUT");; +gap> saved := ERROR_OUTPUT;; +gap> ERROR_OUTPUT := errStream;; +gap> MakeReadOnlyGlobal("ERROR_OUTPUT");; +gap> +gap> READ_ALL_COMMANDS(InputTextString("h := ;"), false, false, IdFunc);; +gap> +gap> MakeReadWriteGlobal("ERROR_OUTPUT");; +gap> ERROR_OUTPUT := saved;; +gap> MakeReadOnlyGlobal("ERROR_OUTPUT");; +gap> CloseStream(errStream);; +gap> +gap> inStream := InputTextFile(errFile);; +gap> captured := ReadAll(inStream);; +gap> CloseStream(inStream);; +gap> +gap> Print("contains-eof-sentinel: ", '\377' in captured, "\n"); +contains-eof-sentinel: false +gap> Print("contains-error-message: ", +> PositionSublist(captured, "expression expected") <> fail, "\n"); +contains-error-message: true +gap> QUIT; From 70cd9fd78dfb899be21e95f811da2b60c0a1bf24 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 9 May 2026 06:04:51 +0100 Subject: [PATCH 056/123] dev/releases: ignore dependabot PRs (#6375) Co-authored-by: Codex Co-authored-by: Reinis Cirpons <43414125+reiniscirpons@users.noreply.github.com> --- .github/workflows/release.yml | 4 +- Makefile.rules | 8 +++ dev/releases/release_notes.py | 11 ++- dev/releases/test_release_notes.py | 107 +++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 dev/releases/test_release_notes.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c8de8a0b1e..997d172106 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,8 +56,8 @@ jobs: #- name: "Validate types" # run: python -m mypy --disallow-untyped-calls --disallow-untyped-defs dev/releases/*.py - #- name: "Run tests" - # run: python -m pytest tools/tests/dev/releases*.py -vv + - name: "Run tests" + run: cd dev/releases && python -m pytest test_release_notes.py unix: name: "Create Unix archives and data" diff --git a/Makefile.rules b/Makefile.rules index 74d62a9ca0..ffe22eb1ba 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -21,6 +21,14 @@ default: all .PHONY: default +######################################################################## +# Developer helper targets +######################################################################## +test_release_notes: + cd dev/releases && python3 -m pytest test_release_notes.py +.PHONY: test_release_notes + + ######################################################################## # Source files # diff --git a/dev/releases/release_notes.py b/dev/releases/release_notes.py index 58e7119bb9..9d7eaf9cac 100755 --- a/dev/releases/release_notes.py +++ b/dev/releases/release_notes.py @@ -221,7 +221,7 @@ def get_pr_list(date: str, extra: str) -> List[Dict[str, Any]]: "--search", query, "--json", - "number,title,closedAt,labels,mergedAt", + "number,title,closedAt,labels,mergedAt,author", "--limit", "200", ], @@ -245,6 +245,14 @@ def has_label(pr: Dict[str, Any], label: str) -> bool: return any(x["name"] == label for x in pr["labels"]) +def is_dependabot_pr(pr: Dict[str, Any]) -> bool: + author = pr.get("author") or {} + login = author.get("login") + if login in ("app/dependabot", "dependabot[bot]"): + return True + return author.get("is_bot", False) and has_label(pr, "dependencies") + + def changes_overview( prs: List[Dict[str, Any]], startdate: str, new_version: str ) -> None: @@ -361,6 +369,7 @@ def main(new_version: str) -> None: print("Downloading filtered PR list") prs = get_pr_list(startdate, extra) + prs = [pr for pr in prs if not is_dependabot_pr(pr)] # print(json.dumps(prs, sort_keys=True, indent=4)) changes_overview(prs, startdate, new_version) diff --git a/dev/releases/test_release_notes.py b/dev/releases/test_release_notes.py new file mode 100644 index 0000000000..a06161afed --- /dev/null +++ b/dev/releases/test_release_notes.py @@ -0,0 +1,107 @@ +import release_notes + + +def test_is_dependabot_pr_detects_dependabot_author(): + pr = { + "author": {"is_bot": True, "login": "app/dependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": True, "login": "app/notdependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/dependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/notdependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/dependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/notdependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": True, "login": "app/notdependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "dependabot[bot]"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"login": "dependabot[bot]"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"login": "app/notdependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"login": "app/notdependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) From 62c95cbafd9aca4b442ffeef2d904315ec31029d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 9 May 2026 10:15:58 +0100 Subject: [PATCH 057/123] Minor cleanup of random suff (#6377) --- lib/clas.gi | 4 ++-- lib/oprt.gi | 9 ++++----- src/ariths.c | 2 +- src/code.c | 10 +++++----- src/dt.c | 21 ++++++++++----------- src/error.h | 14 +++++++------- src/stringobj.c | 4 ++-- 7 files changed, 31 insertions(+), 33 deletions(-) diff --git a/lib/clas.gi b/lib/clas.gi index 864fdea22c..b933b7d50b 100644 --- a/lib/clas.gi +++ b/lib/clas.gi @@ -116,7 +116,7 @@ local fam, filter, cl; fi; filter:=filter and HasActingDomain and HasRepresentative and HasFunctionAction; - fam!.defaultClassType:=NewType( FamilyObj( G ), filter ); + fam!.defaultClassType:=NewType( fam, filter ); fi; cl:=rec( start := [ g ] ); @@ -141,7 +141,7 @@ local fam, filter, cl; fi; filter:=filter and HasActingDomain and HasRepresentative and HasFunctionAction and HasStabilizerOfExternalSet; - fam!.defaultClassCentType:=NewType( FamilyObj( G ), filter ); + fam!.defaultClassCentType:=NewType( fam, filter ); fi; cl:=rec( start := [ g ]); diff --git a/lib/oprt.gi b/lib/oprt.gi index d9d6b34a81..9710eac495 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -587,10 +587,9 @@ end ); ## #M ActionHomomorphismConstructor( , ) ## -InstallGlobalFunction( ActionHomomorphismConstructor, function(arg) -local xset,surj,G, D, act, fam, filter, hom, i,blockacttest; +InstallGlobalFunction( ActionHomomorphismConstructor, function(xset, surj, arg...) +local G, D, act, fam, filter, hom, i,blockacttest; - xset:=arg[1];surj:=arg[2]; G := ActingDomain( xset ); D := HomeEnumerator( xset ); act := FunctionAction( xset ); @@ -650,8 +649,8 @@ local xset,surj,G, D, act, fam, filter, hom, i,blockacttest; end; hom := rec( ); - if Length(arg)>2 then - filter:=arg[3]; + if Length(arg)>0 then + filter:=arg[1]; elif IsExternalSetByActorsRep( xset ) then filter := filter and IsActionHomomorphismByActors; elif IsMatrixGroup( G ) diff --git a/src/ariths.c b/src/ariths.c index f908e4761a..92201121a3 100644 --- a/src/ariths.c +++ b/src/ariths.c @@ -20,7 +20,7 @@ #define RequireValue(funcname, val) \ do { \ - if (!val) \ + if (!(val)) \ ErrorMayQuit(funcname ": method should have returned a value", \ 0, 0); \ } while (0) diff --git a/src/code.c b/src/code.c index a5daa42082..85c73298ae 100644 --- a/src/code.c +++ b/src/code.c @@ -1755,14 +1755,14 @@ void CodeListExprEnd( } // allocate the list expression - if ( ! range && ! (top && tilde) ) { - list = NewExpr(cs, EXPR_LIST, INT_INTEXPR(pos) * sizeof(Expr)); + if (range) { + list = NewExpr(cs, EXPR_RANGE, INT_INTEXPR(pos) * sizeof(Expr)); } - else if ( ! range && (top && tilde) ) { + else if (top && tilde) { list = NewExpr(cs, EXPR_LIST_TILDE, INT_INTEXPR(pos) * sizeof(Expr)); } - else /* if ( range && ! (top && tilde) ) */ { - list = NewExpr(cs, EXPR_RANGE, INT_INTEXPR(pos) * sizeof(Expr)); + else { + list = NewExpr(cs, EXPR_LIST, INT_INTEXPR(pos) * sizeof(Expr)); } // enter the entries diff --git a/src/dt.c b/src/dt.c index e9f44de22b..67f2912197 100644 --- a/src/dt.c +++ b/src/dt.c @@ -61,7 +61,7 @@ #include "modules.h" #include "plist.h" -static void UnmarkTree(Obj z); +static void UnmarkTree(Obj tree); static UInt Mark(Obj tree, Obj reftree, Int indexx); static Int AlmostEqual(Obj tree1, Int index1, Obj tree2, Int index2); static Int Equal(Obj tree1, Int index1, Obj tree2, Int index2); @@ -726,16 +726,15 @@ static Int Leftof(Obj tree1, Int index1, Obj tree2, Int index2) */ static Int Leftof2(Obj tree1, Int index1, Obj tree2, Int index2) { - if ( DT_GEN(tree2, index2) < DT_GEN(tree1, DT_RIGHT(tree1, index1) ) ) - return 0; - else if (Equal(tree1, DT_RIGHT(tree1, index1), tree2, index2 ) ) - return 0; - else if (DT_GEN(tree2, index2) == DT_GEN(tree1, DT_RIGHT(tree1, index1)) ) - return Leftof(tree1, DT_RIGHT(tree1, index1), tree2, index2 ); - else if (Equal(tree1, DT_LEFT(tree1, index1), tree2, index2) ) - return 0; - else - return Leftof(tree1, DT_LEFT(tree1, index1), tree2, index2); + if (DT_GEN(tree2, index2) < DT_GEN(tree1, DT_RIGHT(tree1, index1))) + return 0; + if (Equal(tree1, DT_RIGHT(tree1, index1), tree2, index2)) + return 0; + if (DT_GEN(tree2, index2) == DT_GEN(tree1, DT_RIGHT(tree1, index1))) + return Leftof(tree1, DT_RIGHT(tree1, index1), tree2, index2); + if (Equal(tree1, DT_LEFT(tree1, index1), tree2, index2)) + return 0; + return Leftof(tree1, DT_LEFT(tree1, index1), tree2, index2); } diff --git a/src/error.h b/src/error.h index 64c3aa5a3f..7915e12756 100644 --- a/src/error.h +++ b/src/error.h @@ -192,13 +192,13 @@ void ErrorBoundedInt(const char * funcname, int min, int max) NORETURN; -#define RequireBoundedIntEx(funcname, op, argname, min, max) \ - do { \ - if (!(IS_INTOBJ(op) && min <= INT_INTOBJ(op) && \ - INT_INTOBJ(op) <= max)) { \ - ErrorBoundedInt(funcname, op, argname, min, max); \ - } \ - } while (0) +EXPORT_INLINE void RequireBoundedIntEx( + const char * funcname, Obj op, const char * argname, int min, int max) +{ + if (!(IS_INTOBJ(op) && min <= INT_INTOBJ(op) && INT_INTOBJ(op) <= max)) { + ErrorBoundedInt(funcname, op, argname, min, max); + } +} #define RequireBoundedInt(funcname, op, min, max) \ RequireBoundedIntEx(funcname, op, NICE_ARGNAME(op), min, max) diff --git a/src/stringobj.c b/src/stringobj.c index 9e70b53f53..c3f659de5b 100644 --- a/src/stringobj.c +++ b/src/stringobj.c @@ -1062,7 +1062,7 @@ static BOOL IsSSortString(Obj list) len = GET_LEN_STRING( list ); ptr = CONST_CHARS_STRING(list); for ( i = 1; i < len; i++ ) { - if ( ! (ptr[i-1] < ptr[i]) ) + if (ptr[i - 1] >= ptr[i]) break; } @@ -1468,7 +1468,7 @@ static Obj FuncPOSITION_SUBSTRING(Obj self, Obj string, Obj substr, Obj off) for (i = ipos; i < max; i++) { if (c == s[i]) { for (j = 1; j < lenss; j++) { - if (! (s[i+j] == ss[j])) + if (s[i + j] != ss[j]) break; } if (j == lenss) From 1fab8e8e057d65ad561ecb6a30ff1b99a1d5c9e5 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 9 May 2026 19:12:12 +0100 Subject: [PATCH 058/123] Avoid `IdGroup` in `IsSymmetricGroup` (#6383) --- lib/grpnames.gi | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/grpnames.gi b/lib/grpnames.gi index 32aa8f6368..6accd41db1 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1278,12 +1278,23 @@ InstallMethod( IsSymmetricGroup, return true; fi; + # the derived subgroup must be alternating and have index 2 G1 := DerivedSubgroup(G); - if not (IsAlternatingGroup(G1) and Index(G,G1) = 2) - # this requires deg>=4 - or not IsTrivial(Centralizer(G,G1)) - or Size(G) = 720 and IdGroup(G) <> [ 720, 763 ] - then return false; fi; + if not (IsAlternatingGroup(G1) and Index(G,G1) = 2) then + return false; + fi; + # the derived subgroup must have trivial centralizer (since degree >= 4) + if not IsTrivial(Centralizer(G,G1)) then + return false; + fi; + # one more special case: there are three groups of order 720 which satisfy + # the above (those with small group ids 763, 764, 765). So here we need + # extra work to pick the correct one: it is only one in which all elements + # have order <= 6. Conversely, the other two groups contain elements of + # order 8 or 10, but none of order 6 + if Size(G) = 720 and Order(First(G,x->Order(x)>=6)) > 6 then + return false; + fi; SetSymmetricDegree(G,AlternatingDegree(G1)); return true; end ); From 1fc2b450ffa02b8c45273c60faa8500b5d4e90fd Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 May 2026 10:46:15 +0200 Subject: [PATCH 059/123] kernel: turn global GAP and module states back into static globals (#6376) ... at least in plain GAP; keep them as before in HPC-GAP. The whole concept was invented to allow HPC-GAP to have thread local GAP and module state. In plain GAP, though, it introduced some minor overhead. Changing this here allows us to avoid the overhead, and it also prevents GAPState from becoming larger than 32kb. This can happen on platforms with a large jmp_buf (e.g., powerpc64). --- src/code.c | 16 ++- src/collectors.cc | 114 ++++++++++--------- src/cyclotom.c | 20 ++-- src/exprs.c | 11 +- src/funcs.c | 23 ++-- src/gap.c | 15 ++- src/gapstate.h | 66 ++++++----- src/io.c | 271 ++++++++++++++++++++++++---------------------- src/modules.c | 7 ++ src/modules.h | 6 + src/objcftl.c | 43 +++++--- src/objects.c | 108 +++++++++--------- src/objfgelm.cc | 2 + src/objpcgel.cc | 2 + src/opers.cc | 2 + src/permutat.cc | 10 +- src/pperm.cc | 11 +- src/trans.cc | 23 ++-- 18 files changed, 431 insertions(+), 319 deletions(-) diff --git a/src/code.c b/src/code.c index 85c73298ae..5ff2315c98 100644 --- a/src/code.c +++ b/src/code.c @@ -44,12 +44,15 @@ GAP_STATIC_ASSERT(sizeof(StatHeader) == 8, "StatHeader has wrong size"); +#ifdef HPCGAP struct CodeModuleState { - Bag StackStat; - Int CountStat; +#endif +DECL_MODULE_STATE Bag StackStat; +DECL_MODULE_STATE Int CountStat; - Bag StackExpr; - Int CountExpr; +DECL_MODULE_STATE Bag StackExpr; +DECL_MODULE_STATE Int CountExpr; +#ifdef HPCGAP }; static ModuleStateOffset CodeStateOffset = -1; @@ -60,6 +63,9 @@ extern inline struct CodeModuleState * CShelper(void) } #define CS(x) (CShelper()->x) +#else +#define CS(x) (x) +#endif /**************************************************************************** @@ -3250,8 +3256,10 @@ static StructInitInfo module = { .preSave = PreSave, .postRestore = PostRestore, +#ifdef HPCGAP .moduleStateSize = sizeof(struct CodeModuleState), .moduleStateOffsetPtr = &CodeStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/collectors.cc b/src/collectors.cc index 9a127eda65..3a8f37b314 100644 --- a/src/collectors.cc +++ b/src/collectors.cc @@ -46,15 +46,19 @@ extern "C" { *F * * * * * * * * * * * * * module specific state * * * * * * * * * * * * * */ +#ifdef HPCGAP struct CollectorsState_ { - Obj SC_NW_STACK; - Obj SC_LW_STACK; - Obj SC_PW_STACK; - Obj SC_EW_STACK; - Obj SC_GE_STACK; - Obj SC_CW_VECTOR; - Obj SC_CW2_VECTOR; - UInt SC_MAX_STACK_SIZE; +#endif + +DECL_MODULE_STATE Obj SC_NW_STACK; +DECL_MODULE_STATE Obj SC_LW_STACK; +DECL_MODULE_STATE Obj SC_PW_STACK; +DECL_MODULE_STATE Obj SC_EW_STACK; +DECL_MODULE_STATE Obj SC_GE_STACK; +DECL_MODULE_STATE Obj SC_CW_VECTOR; +DECL_MODULE_STATE Obj SC_CW2_VECTOR; +DECL_MODULE_STATE UInt SC_MAX_STACK_SIZE; +#ifdef HPCGAP }; static ModuleStateOffset CollectorsStateOffset = -1; @@ -64,6 +68,17 @@ extern inline struct CollectorsState_ * CollectorsState(void) return (struct CollectorsState_ *)StateSlotsAtOffset(CollectorsStateOffset); } +#define SC_NW_STACK (CollectorsState()->SC_NW_STACK) +#define SC_LW_STACK (CollectorsState()->SC_LW_STACK) +#define SC_PW_STACK (CollectorsState()->SC_PW_STACK) +#define SC_EW_STACK (CollectorsState()->SC_EW_STACK) +#define SC_GE_STACK (CollectorsState()->SC_GE_STACK) +#define SC_CW_VECTOR (CollectorsState()->SC_CW_VECTOR) +#define SC_CW2_VECTOR (CollectorsState()->SC_CW2_VECTOR) +#define SC_MAX_STACK_SIZE (CollectorsState()->SC_MAX_STACK_SIZE) + +#endif + /**************************************************************************** ** @@ -84,7 +99,7 @@ extern inline struct CollectorsState_ * CollectorsState(void) */ #define SC_PUSH_WORD( word, exp ) \ if ( ++sp == max ) { \ - CollectorsState()->SC_MAX_STACK_SIZE *= 2; \ + SC_MAX_STACK_SIZE *= 2; \ return -1; \ } \ *++nw = DATA_WORD(word); \ @@ -95,7 +110,7 @@ extern inline struct CollectorsState_ * CollectorsState(void) #define SC_PUSH_GEN( gen, exp ) \ if ( ++sp == max ) { \ - CollectorsState()->SC_MAX_STACK_SIZE *= 2; \ + SC_MAX_STACK_SIZE *= 2; \ return -1; \ } \ *++nw = DATA_WORD(gen); \ @@ -385,22 +400,22 @@ static Int SingleCollectWord(Obj sc, Obj vv, Obj w) exps = (UInt)1 << (ebits-1); // contains the stack of words to insert - vnw = CollectorsState()->SC_NW_STACK; + vnw = SC_NW_STACK; // contains the word end of the word in - vlw = CollectorsState()->SC_LW_STACK; + vlw = SC_LW_STACK; // contains the position of the word in to look at - vpw = CollectorsState()->SC_PW_STACK; + vpw = SC_PW_STACK; // contains the unprocessed exponents at position - vew = CollectorsState()->SC_EW_STACK; + vew = SC_EW_STACK; // contains the global exponent of the word - vge = CollectorsState()->SC_GE_STACK; + vge = SC_GE_STACK; // get the maximal stack size - max = CollectorsState()->SC_MAX_STACK_SIZE; + max = SC_MAX_STACK_SIZE; // ensure that the stacks are large enough const UInt desiredStackSize = sizeof(Obj) * (max + 2); @@ -893,22 +908,22 @@ static Int CombiCollectWord(Obj sc, Obj vv, Obj w) exps = (UInt)1 << (ebits-1); // contains the stack of words to insert - vnw = CollectorsState()->SC_NW_STACK; + vnw = SC_NW_STACK; // contains the word end of the word in - vlw = CollectorsState()->SC_LW_STACK; + vlw = SC_LW_STACK; // contains the position of the word in to look at - vpw = CollectorsState()->SC_PW_STACK; + vpw = SC_PW_STACK; // contains the unprocessed exponents at position - vew = CollectorsState()->SC_EW_STACK; + vew = SC_EW_STACK; // contains the global exponent of the word - vge = CollectorsState()->SC_GE_STACK; + vge = SC_GE_STACK; // get the maximal stack size - max = CollectorsState()->SC_MAX_STACK_SIZE; + max = SC_MAX_STACK_SIZE; // ensure that the stacks are large enough const UInt desiredStackSize = sizeof(Obj) * (max + 2); @@ -1267,7 +1282,7 @@ static Obj ReducedComm(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vc2; // collect vector // use 'cwVector' to collect word * to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length, unpack into it @@ -1283,7 +1298,7 @@ static Obj ReducedComm(FinPowConjCol * fc, Obj sc, Obj w, Obj u) } // use 'cw2Vector' to collect word * to - vc2 = CollectorsState()->SC_CW2_VECTOR; + vc2 = SC_CW2_VECTOR; // check that it has the correct length, unpack into it if ( fc->vectorWord( vc2, w, num ) == -1 ) { @@ -1325,7 +1340,7 @@ static Obj ReducedForm(FinPowConjCol * fc, Obj sc, Obj w) Obj type; // type of the return objue // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length @@ -1358,7 +1373,7 @@ static Obj ReducedLeftQuotient(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vc2; // collect vector // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length, unpack into it @@ -1368,7 +1383,7 @@ static Obj ReducedLeftQuotient(FinPowConjCol * fc, Obj sc, Obj w, Obj u) } // use 'cw2Vector' to collect word to - vc2 = CollectorsState()->SC_CW2_VECTOR; + vc2 = SC_CW2_VECTOR; // check that it has the correct length, unpack into it if ( fc->vectorWord( vc2, u, num ) == -1 ) { @@ -1402,7 +1417,7 @@ static Obj ReducedProduct(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vcw; // collect vector // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length, unpack into it @@ -1441,8 +1456,8 @@ static Obj ReducedPowerSmallInt(FinPowConjCol * fc, Obj sc, Obj w, Obj vpow) pow = INT_INTOBJ(vpow); // use 'cwVector' and 'cw2Vector to collect words to - vcw = CollectorsState()->SC_CW_VECTOR; - vc2 = CollectorsState()->SC_CW2_VECTOR; + vcw = SC_CW_VECTOR; + vc2 = SC_CW2_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); type = SC_DEFAULT_TYPE(sc); @@ -1528,8 +1543,8 @@ static Obj ReducedQuotient(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vc2; // collect vector // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; - vc2 = CollectorsState()->SC_CW2_VECTOR; + vcw = SC_CW_VECTOR; + vc2 = SC_CW2_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); type = SC_DEFAULT_TYPE(sc); @@ -1647,8 +1662,7 @@ static Obj FuncFinPowConjCol_ReducedQuotient ( Obj self, Obj sc, Obj w, Obj u ) */ static Obj FuncSET_SCOBJ_MAX_STACK_SIZE(Obj self, Obj size) { - CollectorsState()->SC_MAX_STACK_SIZE = - GetPositiveSmallInt(SELF_NAME, size); + SC_MAX_STACK_SIZE = GetPositiveSmallInt(SELF_NAME, size); return 0; } @@ -1739,25 +1753,25 @@ static Int InitLibrary ( static Int InitModuleState(void) { // register global bags with the garbage collector - InitGlobalBag( &CollectorsState()->SC_NW_STACK, "SC_NW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_LW_STACK, "SC_LW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_PW_STACK, "SC_PW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_EW_STACK, "SC_EW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_GE_STACK, "SC_GE_STACK" ); - InitGlobalBag( &CollectorsState()->SC_CW_VECTOR, "SC_CW_VECTOR" ); - InitGlobalBag( &CollectorsState()->SC_CW2_VECTOR, "SC_CW2_VECTOR" ); + InitGlobalBag(&SC_NW_STACK, "SC_NW_STACK"); + InitGlobalBag(&SC_LW_STACK, "SC_LW_STACK"); + InitGlobalBag(&SC_PW_STACK, "SC_PW_STACK"); + InitGlobalBag(&SC_EW_STACK, "SC_EW_STACK"); + InitGlobalBag(&SC_GE_STACK, "SC_GE_STACK"); + InitGlobalBag(&SC_CW_VECTOR, "SC_CW_VECTOR"); + InitGlobalBag(&SC_CW2_VECTOR, "SC_CW2_VECTOR"); const UInt maxStackSize = 256; const UInt desiredStackSize = sizeof(Obj) * (maxStackSize + 2); - CollectorsState()->SC_NW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_LW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_PW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_EW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_GE_STACK = NewKernelBuffer(desiredStackSize); + SC_NW_STACK = NewKernelBuffer(desiredStackSize); + SC_LW_STACK = NewKernelBuffer(desiredStackSize); + SC_PW_STACK = NewKernelBuffer(desiredStackSize); + SC_EW_STACK = NewKernelBuffer(desiredStackSize); + SC_GE_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_CW_VECTOR = NEW_STRING(0); - CollectorsState()->SC_CW2_VECTOR = NEW_STRING(0); - CollectorsState()->SC_MAX_STACK_SIZE = maxStackSize; + SC_CW_VECTOR = NEW_STRING(0); + SC_CW2_VECTOR = NEW_STRING(0); + SC_MAX_STACK_SIZE = maxStackSize; return 0; } @@ -1779,8 +1793,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(CollectorsState_), /* moduleStateOffsetPtr = */ &CollectorsStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/cyclotom.c b/src/cyclotom.c index 0686e459cd..3025530f94 100644 --- a/src/cyclotom.c +++ b/src/cyclotom.c @@ -142,10 +142,11 @@ static inline void SET_NOF_CYC(Obj cyc, Obj val) // #define XXX_CYC(cyc,len) (EXPOS_CYC(cyc,len)[0]) - +#ifdef HPCGAP static ModuleStateOffset CycStateOffset = -1; struct CycModuleState { +#endif /**************************************************************************** ** @@ -158,7 +159,7 @@ struct CycModuleState { ** It is created in 'InitCyc' with room for up to 1000 coefficients and is ** resized when need arises. */ -Obj ResultCyc; +DECL_MODULE_STATE Obj ResultCyc; /**************************************************************************** ** @@ -178,9 +179,10 @@ Obj ResultCyc; ** is called to compute $e_n^i$ and can then do this easier by just putting ** 1 at the th place in 'ResultCyc' and then calling 'Cyclotomic'. */ -Obj LastECyc; -UInt LastNCyc; +DECL_MODULE_STATE Obj LastECyc; +DECL_MODULE_STATE UInt LastNCyc; +#ifdef HPCGAP }; // end of struct CycModuleState extern inline struct CycModuleState *CycState(void) @@ -189,10 +191,10 @@ extern inline struct CycModuleState *CycState(void) } // For convenience and readability -#define ResultCyc CycState()->ResultCyc -#define LastECyc CycState()->LastECyc -#define LastNCyc CycState()->LastNCyc - +#define ResultCyc (CycState()->ResultCyc) +#define LastECyc (CycState()->LastECyc) +#define LastNCyc (CycState()->LastNCyc) +#endif static void GrowResultCyc(UInt size) { @@ -2201,8 +2203,10 @@ static StructInitInfo module = { .initKernel = InitKernel, .initLibrary = InitLibrary, +#ifdef HPCGAP .moduleStateSize = sizeof(struct CycModuleState), .moduleStateOffsetPtr = &CycStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/exprs.c b/src/exprs.c index 511188322b..2c234633ad 100644 --- a/src/exprs.c +++ b/src/exprs.c @@ -40,7 +40,9 @@ #include "hpc/aobjects.h" #endif +#ifdef HPCGAP struct ExprsState { +#endif /**************************************************************************** ** @@ -55,10 +57,11 @@ struct ExprsState { ** This sometimes puts in superfluous parenthesis: 2 * f( (3 + 4) ), since it ** doesn't know that a function call adds automatically parenthesis. */ -UInt PrintPrecedence; +DECL_MODULE_STATE UInt PrintPrecedence; -UInt OldPrintPrecedence; +DECL_MODULE_STATE UInt OldPrintPrecedence; +#ifdef HPCGAP }; static ModuleStateOffset ExprsStateOffset = -1; @@ -70,6 +73,7 @@ extern inline struct ExprsState * ExprsState(void) #define PrintPrecedence ExprsState()->PrintPrecedence #define OldPrintPrecedence ExprsState()->OldPrintPrecedence +#endif /**************************************************************************** ** @@ -1814,9 +1818,10 @@ static StructInitInfo module = { .name = "exprs", .initKernel = InitKernel, .initLibrary = InitLibrary, - +#ifdef HPCGAP .moduleStateSize = sizeof(struct ExprsState), .moduleStateOffsetPtr = &ExprsStateOffset, +#endif }; StructInitInfo * InitInfoExprs ( void ) diff --git a/src/funcs.c b/src/funcs.c index 9937ad4699..62919177f5 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -41,10 +41,13 @@ #endif +#ifdef HPCGAP static ModuleStateOffset FuncsStateOffset = -1; struct FuncsModuleState { - Int RecursionDepth; +#endif + DECL_MODULE_STATE Int RecursionDepth; +#ifdef HPCGAP }; extern inline struct FuncsModuleState *FuncsState(void) @@ -52,32 +55,35 @@ extern inline struct FuncsModuleState *FuncsState(void) return (struct FuncsModuleState *)StateSlotsAtOffset(FuncsStateOffset); } +#define RecursionDepth (FuncsState()->RecursionDepth) +#endif + Int IncRecursionDepth(void) { - int depth = ++(FuncsState()->RecursionDepth); + int depth = ++RecursionDepth; return depth; } void DecRecursionDepth(void) { - FuncsState()->RecursionDepth--; + RecursionDepth--; /* FIXME: According to a comment in the function RecursionDepthTrap below, RecursionDepth can become "slightly" negative. This needs some investigation. - GAP_ASSERT(FuncsState()->RecursionDepth >= 0); + GAP_ASSERT(RecursionDepth >= 0); */ } Int GetRecursionDepth(void) { - return FuncsState()->RecursionDepth; + return RecursionDepth; } void SetRecursionDepth(Int depth) { GAP_ASSERT(depth >= 0); - FuncsState()->RecursionDepth = depth; + RecursionDepth = depth; } /**************************************************************************** @@ -879,7 +885,7 @@ static Int InitKernel ( static Int InitModuleState(void) { - FuncsState()->RecursionDepth = 0; + RecursionDepth = 0; return 0; } @@ -895,9 +901,10 @@ static StructInitInfo module = { .name = "funcs", .initKernel = InitKernel, .initLibrary = InitLibrary, - +#ifdef HPCGAP .moduleStateSize = sizeof(struct FuncsModuleState), .moduleStateOffsetPtr = &FuncsStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/gap.c b/src/gap.c index a2b02693be..711c0eb142 100644 --- a/src/gap.c +++ b/src/gap.c @@ -18,10 +18,10 @@ #include "compiler.h" #include "error.h" #include "funcs.h" -#include "gapstate.h" #ifdef USE_GASMAN #include "gasman_intern.h" #endif +#include "gapstate.h" #include "gaptime.h" #include "gvars.h" #include "integer.h" @@ -123,11 +123,18 @@ static UInt Time; */ static UInt MemoryAllocated; - #ifndef HPCGAP -GAPState MainGAPState; -#endif +// HACK: include gapstate a second time, but with DECL_GAP_STATE +// defined to be empty, to root the global variables here; i.e., +// `DECL_GAP_STATE Obj Tilde;` is turned into just `Obj Tilde;` +// and so on. +#undef GAP_GAPSTATE_H +#undef DECL_GAP_STATE +#define DECL_GAP_STATE +#include "gapstate.h" + +#endif /**************************************************************************** ** diff --git a/src/gapstate.h b/src/gapstate.h index 16d74d2c8a..4cb6060d63 100644 --- a/src/gapstate.h +++ b/src/gapstate.h @@ -23,31 +23,35 @@ #include +#ifdef HPCGAP enum { STATE_SLOTS_SIZE = 32768 - 1024, }; +#define DECL_GAP_STATE + typedef struct GAPState { -#ifdef HPCGAP // TLS data -- this *must* come first, so that we can safely // cast a GAPState pointer into a ThreadLocalStorage pointer ThreadLocalStorage tls; +#elif !defined(DECL_GAP_STATE) +#define DECL_GAP_STATE extern #endif // for Boehm GC #if defined(USE_BOEHM_GC) #define MAX_GC_PREFIX_DESC 4 - void ** FreeList[MAX_GC_PREFIX_DESC + 2]; + DECL_GAP_STATE void ** FreeList[MAX_GC_PREFIX_DESC + 2]; #endif // From intrprtr.c - Obj Tilde; + DECL_GAP_STATE Obj Tilde; // The current assertion level for use in Assert - Int CurrentAssertionLevel; + DECL_GAP_STATE Int CurrentAssertionLevel; // From gvar.c - Obj CurrNamespace; + DECL_GAP_STATE Obj CurrNamespace; // From vars.c @@ -57,19 +61,19 @@ typedef struct GAPState { // Assignments to the local variables change this bag. We do not call // 'CHANGED_BAG' for each of such change. Instead we wait until a garbage // collection begins and then call 'CHANGED_BAG' in 'BeginCollectBags'. - Bag CurrLVars; + DECL_GAP_STATE Bag CurrLVars; // 'PtrLVars' is a pointer to the 'STATE(CurrLVars)' bag. This makes it // faster to access local variables. // // Since a garbage collection may move this bag around, the pointer // 'PtrLVars' must be recalculated afterwards in 'VarsAfterCollectBags'. - Obj * PtrLVars; + DECL_GAP_STATE Obj * PtrLVars; - Bag LVarsPool[16]; + DECL_GAP_STATE Bag LVarsPool[16]; // From read.c - jmp_buf ReadJmpError; + DECL_GAP_STATE jmp_buf ReadJmpError; // 'Prompt' holds the string that is to be printed if a new line is read // from the interactive files '*stdin*' or '*errin*'. @@ -77,19 +81,19 @@ typedef struct GAPState { // It is set to 'gap> ' or 'brk> ' in the read-eval-print loops and // changed to the partial prompt '> ' in 'Read' after the first symbol is // read. - char Prompt[80]; + DECL_GAP_STATE char Prompt[80]; // From stats.c // `ReturnObjStat` is the result of the return-statement that was last // executed. It is set in `ExecReturnObj` and used in the handlers that // interpret functions. - Obj ReturnObjStat; + DECL_GAP_STATE Obj ReturnObjStat; - ExecStatFunc * CurrExecStatFuncs; + DECL_GAP_STATE ExecStatFunc * CurrExecStatFuncs; // From code.c - void * PtrBody; + DECL_GAP_STATE void * PtrBody; // From opers.c #ifdef HPCGAP @@ -99,36 +103,37 @@ typedef struct GAPState { #endif // for use by GAP_TRY / GAP_CATCH and related code - int TryCatchDepth; + DECL_GAP_STATE int TryCatchDepth; // Set by `FuncJUMP_TO_CATCH` to the value of its second argument, and // and then later extracted by `CALL_WITH_CATCH`. Not currently used by // the GAP kernel itself, as far as I can tell. - Obj ThrownObject; + DECL_GAP_STATE Obj ThrownObject; // Set to TRUE when a read-eval-loop encounters a `quit` statement. - BOOL UserHasQuit; + DECL_GAP_STATE BOOL UserHasQuit; // Set to TRUE when a read-eval-loop encounters a `QUIT` statement. - BOOL UserHasQUIT; + DECL_GAP_STATE BOOL UserHasQUIT; // Set by the primary read-eval loop in `FuncSHELL`, based on the value of // `ErrorLLevel`. Also, `ReadEvalCommand` saves and restores this value // before executing code. - Obj ErrorLVars; + DECL_GAP_STATE Obj ErrorLVars; // Records where on the stack `ErrorLVars` is relative to the top; this is // modified by `FuncDownEnv` / `FuncUpEnv`, and ultimately used and // controlled by the primary read-eval loop in `FuncSHELL`. - Int ErrorLLevel; + DECL_GAP_STATE Int ErrorLLevel; // This callback is called in FuncJUMP_TO_CATCH, this is not used by GAP // itself but by programs that use GAP as a library to handle errors - void (*JumpToCatchCallback)(void); + DECL_GAP_STATE void (*JumpToCatchCallback)(void); // From info.c - Int ShowUsedInfoClassesActive; + DECL_GAP_STATE Int ShowUsedInfoClassesActive; +#ifdef HPCGAP UInt1 StateSlots[STATE_SLOTS_SIZE]; } GAPState; @@ -136,26 +141,25 @@ typedef struct GAPState { // so that all its members can be access with a 16 bit signed offset GAP_STATIC_ASSERT(sizeof(GAPState) < 32768, "GAPState is too big"); -#ifdef HPCGAP +#define DECL_MODULE_STATE EXPORT_INLINE GAPState * ActiveGAPState(void) { return (GAPState *)GetTLS(); } +#define STATE(x) (ActiveGAPState()->x) + #else -extern GAPState MainGAPState; +#define DECL_MODULE_STATE static -EXPORT_INLINE GAPState * ActiveGAPState(void) -{ - return &MainGAPState; -} +#define STATE(x) (x) #endif -#define STATE(x) (ActiveGAPState()->x) +#ifdef HPCGAP // Offset into StateSlots typedef Int ModuleStateOffset; @@ -167,7 +171,9 @@ EXPORT_INLINE void * StateSlotsAtOffset(ModuleStateOffset offset) } // Access a module's registered state -#define MODULE_STATE(module) \ - (*(module ## ModuleState *)StateSlotsAtOffset(module ## StateOffset)) +#define MODULE_STATE(module, ident) \ + (((module ## ModuleState *)StateSlotsAtOffset(module ## StateOffset))->ident) + +#endif #endif // GAP_GAPSTATE_H diff --git a/src/io.c b/src/io.c index d3d24163a8..f17e34e606 100644 --- a/src/io.c +++ b/src/io.c @@ -74,65 +74,73 @@ static Obj SetPrintFormattingStatus; static Obj FilenameCache; static SymbolTable FilenameSymbolTable; -static ModuleStateOffset IOStateOffset = -1; - enum { MAX_OPEN_FILES = 16, }; +#ifdef HPCGAP +static ModuleStateOffset IOStateOffset = -1; + struct IOModuleState { +#endif // A pointer to the current input file - TypInputFile * Input; + DECL_MODULE_STATE TypInputFile * Input; // A pointer to the current output file. It points to the top of the // stack 'OutputFiles'. - TypOutputFile * Output; + DECL_MODULE_STATE TypOutputFile * Output; // - TypOutputFile * IgnoreStdoutErrout; + DECL_MODULE_STATE TypOutputFile * IgnoreStdoutErrout; // The file identifier of the current input logfile. If it is not 0 the // scanner echoes all input from the files '*stdin*' and '*errin*' to // this file. - TypOutputFile * InputLog; + DECL_MODULE_STATE TypOutputFile * InputLog; // The file identifier of the current output logfile. If it is not 0 the // scanner echoes all output to the files '*stdout*' and '*errout*' to // this file. - TypOutputFile * OutputLog; + DECL_MODULE_STATE TypOutputFile * OutputLog; - TypOutputFile InputLogFileOrStream; - TypOutputFile OutputLogFileOrStream; + DECL_MODULE_STATE TypOutputFile InputLogFileOrStream; + DECL_MODULE_STATE TypOutputFile OutputLogFileOrStream; - TypOutputFile DefaultOutput; + DECL_MODULE_STATE TypOutputFile DefaultOutput; #ifdef HPCGAP - Obj DefaultOutputStream; - Obj DefaultInputStream; + DECL_MODULE_STATE Obj DefaultOutputStream; + DECL_MODULE_STATE Obj DefaultInputStream; #endif - Int NoSplitLine; + DECL_MODULE_STATE Int NoSplitLine; - BOOL PrintFormattingForStdout; - BOOL PrintFormattingForErrout; + DECL_MODULE_STATE BOOL PrintFormattingForStdout; + DECL_MODULE_STATE BOOL PrintFormattingForErrout; +#ifdef HPCGAP }; // for debugging from GDB / lldb, we mark this as extern inline -extern inline struct IOModuleState * IO(void) +extern inline struct IOModuleState * IOHelper(void) { return (struct IOModuleState *)StateSlotsAtOffset(IOStateOffset); } +#define IO(x) (IOHelper()->x) +#else +#define IO(x) (x) +#endif + void LockCurrentOutput(BOOL lock) { - IO()->IgnoreStdoutErrout = lock ? IO()->Output : NULL; + IO(IgnoreStdoutErrout) = lock ? IO(Output) : NULL; } TypInputFile * GetCurrentInput(void) { - return IO()->Input; + return IO(Input); } /**************************************************************************** @@ -279,7 +287,7 @@ static GVarDescriptor DEFAULT_OUTPUT_STREAM; static UInt OpenDefaultInput(TypInputFile * input) { Obj func, stream; - stream = IO()->DefaultInputStream; + stream = IO(DefaultInputStream); if (stream) return OpenInputStream(input, stream, FALSE); func = GVarOptFunction(&DEFAULT_INPUT_STREAM); @@ -290,14 +298,14 @@ static UInt OpenDefaultInput(TypInputFile * input) ErrorQuit("DEFAULT_INPUT_STREAM() did not return a stream", 0, 0); if (IsStringConv(stream)) return OpenInput(input, CONST_CSTR_STRING(stream)); - IO()->DefaultInputStream = stream; + IO(DefaultInputStream) = stream; return OpenInputStream(input, stream, FALSE); } static UInt OpenDefaultOutput(TypOutputFile * output) { Obj func, stream; - stream = IO()->DefaultOutputStream; + stream = IO(DefaultOutputStream); if (stream) return OpenOutputStream(output, stream); func = GVarOptFunction(&DEFAULT_OUTPUT_STREAM); @@ -308,7 +316,7 @@ static UInt OpenDefaultOutput(TypOutputFile * output) ErrorQuit("DEFAULT_OUTPUT_STREAM() did not return a stream", 0, 0); if (IsStringConv(stream)) return OpenOutput(output, CONST_CSTR_STRING(stream), FALSE); - IO()->DefaultOutputStream = stream; + IO(DefaultOutputStream) = stream; return OpenOutputStream(output, stream); } #endif @@ -353,7 +361,7 @@ UInt OpenInput(TypInputFile * input, const Char * filename) /* Handle *defin*; redirect *errin* to *defin* if the default * channel is already open. */ if (streq(filename, "*defin*") || - (streq(filename, "*errin*") && IO()->DefaultInputStream)) + (streq(filename, "*errin*") && IO(DefaultInputStream))) return OpenDefaultInput(input); #endif @@ -367,7 +375,7 @@ UInt OpenInput(TypInputFile * input, const Char * filename) // paranoia: fill with garbage, to verify we initialize everything memset(input, 0x47, sizeof(TypInputFile)); #endif - input->prev = IO()->Input; + input->prev = IO(Input); input->stream = 0; input->file = file; @@ -386,7 +394,7 @@ UInt OpenInput(TypInputFile * input, const Char * filename) input->number = 1; input->lastErrorLine = 0; - IO()->Input = input; + IO(Input) = input; // indicate success return 1; @@ -408,7 +416,7 @@ UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo) // paranoia: fill with garbage, to verify we initialize everything memset(input, 0x47, sizeof(TypInputFile)); #endif - input->prev = IO()->Input; + input->prev = IO(Input); input->stream = stream; input->file = -1; input->isstringstream = (CALL_1ARGS(IsInputStringStream, stream) == True); @@ -429,7 +437,7 @@ UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo) input->number = 1; input->lastErrorLine = 0; - IO()->Input = input; + IO(Input) = input; // indicate success return 1; @@ -454,10 +462,10 @@ UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo) UInt CloseInput(TypInputFile * input) { GAP_ASSERT(input); - GAP_ASSERT(input == IO()->Input); + GAP_ASSERT(input == IO(Input)); // revert to previous input - IO()->Input = input->prev; + IO(Input) = input->prev; if (input->stream) { // if the input stream supports seeking, update its position to @@ -515,17 +523,17 @@ UInt OpenLog ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0 || IO()->OutputLog != 0) + if (IO(InputLog) != 0 || IO(OutputLog) != 0) return 0; // try to open the file - IO()->OutputLogFileOrStream.file = SyFopen(filename, "w", FALSE); - IO()->OutputLogFileOrStream.stream = 0; - if (IO()->OutputLogFileOrStream.file == -1) + IO(OutputLogFileOrStream).file = SyFopen(filename, "w", FALSE); + IO(OutputLogFileOrStream).stream = 0; + if (IO(OutputLogFileOrStream).file == -1) return 0; - IO()->InputLog = &IO()->OutputLogFileOrStream; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(InputLog) = &IO(OutputLogFileOrStream); + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -543,15 +551,15 @@ UInt OpenLogStream ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0 || IO()->OutputLog != 0) + if (IO(InputLog) != 0 || IO(OutputLog) != 0) return 0; // try to open the file - IO()->OutputLogFileOrStream.stream = stream; - IO()->OutputLogFileOrStream.file = -1; + IO(OutputLogFileOrStream).stream = stream; + IO(OutputLogFileOrStream).file = -1; - IO()->InputLog = &IO()->OutputLogFileOrStream; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(InputLog) = &IO(OutputLogFileOrStream); + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -572,16 +580,16 @@ UInt OpenLogStream ( UInt CloseLog ( void ) { // refuse to close a non existent logfile - if (IO()->InputLog == 0 || IO()->OutputLog == 0 || - IO()->InputLog != IO()->OutputLog) + if (IO(InputLog) == 0 || IO(OutputLog) == 0 || + IO(InputLog) != IO(OutputLog)) return 0; // close the logfile - if (!IO()->InputLog->stream) { - SyFclose(IO()->InputLog->file); + if (!IO(InputLog)->stream) { + SyFclose(IO(InputLog)->file); } - IO()->InputLog = 0; - IO()->OutputLog = 0; + IO(InputLog) = 0; + IO(OutputLog) = 0; // indicate success return 1; @@ -608,16 +616,16 @@ UInt OpenInputLog ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0) + if (IO(InputLog) != 0) return 0; // try to open the file - IO()->InputLogFileOrStream.file = SyFopen(filename, "w", FALSE); - IO()->InputLogFileOrStream.stream = 0; - if (IO()->InputLogFileOrStream.file == -1) + IO(InputLogFileOrStream).file = SyFopen(filename, "w", FALSE); + IO(InputLogFileOrStream).stream = 0; + if (IO(InputLogFileOrStream).file == -1) return 0; - IO()->InputLog = &IO()->InputLogFileOrStream; + IO(InputLog) = &IO(InputLogFileOrStream); // otherwise indicate success return 1; @@ -635,14 +643,14 @@ UInt OpenInputLogStream ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0) + if (IO(InputLog) != 0) return 0; // try to open the file - IO()->InputLogFileOrStream.stream = stream; - IO()->InputLogFileOrStream.file = -1; + IO(InputLogFileOrStream).stream = stream; + IO(InputLogFileOrStream).file = -1; - IO()->InputLog = &IO()->InputLogFileOrStream; + IO(InputLog) = &IO(InputLogFileOrStream); // otherwise indicate success return 1; @@ -663,19 +671,19 @@ UInt OpenInputLogStream ( UInt CloseInputLog ( void ) { // refuse to close a non existent logfile - if (IO()->InputLog == 0) + if (IO(InputLog) == 0) return 0; // refuse to close a log opened with LogTo - if (IO()->InputLog == IO()->OutputLog) + if (IO(InputLog) == IO(OutputLog)) return 0; // close the logfile - if (!IO()->InputLog->stream) { - SyFclose(IO()->InputLog->file); + if (!IO(InputLog)->stream) { + SyFclose(IO(InputLog)->file); } - IO()->InputLog = 0; + IO(InputLog) = 0; // indicate success return 1; @@ -702,17 +710,17 @@ UInt OpenOutputLog ( { // refuse to open a logfile if we already log to one - if (IO()->OutputLog != 0) + if (IO(OutputLog) != 0) return 0; // try to open the file - memset(&IO()->OutputLogFileOrStream, 0, sizeof(TypOutputFile)); - IO()->OutputLogFileOrStream.stream = 0; - IO()->OutputLogFileOrStream.file = SyFopen(filename, "w", FALSE); - if (IO()->OutputLogFileOrStream.file == -1) + memset(&IO(OutputLogFileOrStream), 0, sizeof(TypOutputFile)); + IO(OutputLogFileOrStream).stream = 0; + IO(OutputLogFileOrStream).file = SyFopen(filename, "w", FALSE); + if (IO(OutputLogFileOrStream).file == -1) return 0; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -730,15 +738,15 @@ UInt OpenOutputLogStream ( { // refuse to open a logfile if we already log to one - if (IO()->OutputLog != 0) + if (IO(OutputLog) != 0) return 0; // try to open the file - memset(&IO()->OutputLogFileOrStream, 0, sizeof(TypOutputFile)); - IO()->OutputLogFileOrStream.stream = stream; - IO()->OutputLogFileOrStream.file = -1; + memset(&IO(OutputLogFileOrStream), 0, sizeof(TypOutputFile)); + IO(OutputLogFileOrStream).stream = stream; + IO(OutputLogFileOrStream).file = -1; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -759,19 +767,19 @@ UInt OpenOutputLogStream ( UInt CloseOutputLog ( void ) { // refuse to close a non existent logfile - if (IO()->OutputLog == 0) + if (IO(OutputLog) == 0) return 0; // refuse to close a log opened with LogTo - if (IO()->OutputLog == IO()->InputLog) + if (IO(OutputLog) == IO(InputLog)) return 0; // close the logfile - if (!IO()->OutputLog->stream) { - SyFclose(IO()->OutputLog->file); + if (!IO(OutputLog)->stream) { + SyFclose(IO(OutputLog)->file); } - IO()->OutputLog = 0; + IO(OutputLog) = 0; // indicate success return 1; @@ -816,7 +824,7 @@ UInt OpenOutput(TypOutputFile * output, const Char * filename, BOOL append) GAP_ASSERT(output); // do nothing for stdout and errout if caught - if (IO()->Output != NULL && IO()->IgnoreStdoutErrout == IO()->Output && + if (IO(Output) != NULL && IO(IgnoreStdoutErrout) == IO(Output) && (streq(filename, "*errout*") || streq(filename, "*stdout*"))) { return 1; } @@ -839,17 +847,17 @@ UInt OpenOutput(TypOutputFile * output, const Char * filename, BOOL append) // paranoia: fill with garbage, to verify we initialize everything memset(output, 0x47, sizeof(TypOutputFile)); #endif - output->prev = IO()->Output; - IO()->Output = output; + output->prev = IO(Output); + IO(Output) = output; output->isstringstream = FALSE; output->stream = 0; output->file = file; output->line[0] = '\0'; output->pos = 0; if (streq(filename, "*stdout*")) - output->format = IO()->PrintFormattingForStdout; + output->format = IO(PrintFormattingForStdout); else if (streq(filename, "*errout*")) - output->format = IO()->PrintFormattingForErrout; + output->format = IO(PrintFormattingForErrout); else output->format = TRUE; output->indent = 0; @@ -879,8 +887,8 @@ UInt OpenOutputStream(TypOutputFile * output, Obj stream) // paranoia: fill with garbage, to verify we initialize everything memset(output, 0x47, sizeof(TypOutputFile)); #endif - output->prev = IO()->Output; - IO()->Output = output; + output->prev = IO(Output); + IO(Output) = output; output->isstringstream = (CALL_1ARGS(IsOutputStringStream, stream) == True); output->stream = stream; output->file = -1; @@ -921,15 +929,15 @@ UInt CloseOutput(TypOutputFile * output) // silently refuse to close the test output file; this is probably an // attempt to close *errout* which is silently not opened, so let's // silently not close it - if (IO()->IgnoreStdoutErrout == IO()->Output) + if (IO(IgnoreStdoutErrout) == IO(Output)) return 1; - GAP_ASSERT(output == IO()->Output); + GAP_ASSERT(output == IO(Output)); // refuse to close the initial output file '*stdout*' #ifdef HPCGAP if (output->prev == 0 && output->stream && - IO()->DefaultOutputStream == output->stream) + IO(DefaultOutputStream) == output->stream) return 0; #else if (output->prev == 0) @@ -943,7 +951,7 @@ UInt CloseOutput(TypOutputFile * output) } // revert to previous output file and indicate success - IO()->Output = output->prev; + IO(Output) = output->prev; // don't keep GAP objects alive unnecessarily output->stream = 0; @@ -1068,7 +1076,7 @@ static Char GetLine(TypInputFile * input) Pr("%c", (Int)'\03', 0); } else if (input->file == 0 || input->file == 2) { - if (IO()->Output->pos > 0) + if (IO(Output)->pos > 0) Pr("\n", 0, 0); if ( PrintPromptHook ) Call0ArgsInNewReader( PrintPromptHook ); @@ -1095,9 +1103,9 @@ static Char GetLine(TypInputFile * input) } // if necessary echo the line to the logfile - if (IO()->InputLog != 0 && input->echo == 1) + if (IO(InputLog) != 0 && input->echo == 1) if (!(input->ptr[0] == '\377' && input->ptr[1] == '\0')) - PutLine2(IO()->InputLog, input->ptr, strlen(input->ptr)); + PutLine2(IO(InputLog), input->ptr, strlen(input->ptr)); // return the current character return *input->ptr; @@ -1156,9 +1164,9 @@ static void PutLineTo(TypOutputFile * stream, UInt len) PutLine2( stream, stream->line, len ); // if necessary echo it to the logfile - if (IO()->OutputLog != 0 && !stream->stream) { + if (IO(OutputLog) != 0 && !stream->stream) { if (stream->file == 1 || stream->file == 3) { - PutLine2(IO()->OutputLog, stream->line, len); + PutLine2(IO(OutputLog), stream->line, len); } } } @@ -1298,9 +1306,9 @@ static void PutChrTo(TypOutputFile * stream, Char ch) /* TODO: For threads other than the main thread, reserve some extra space for the thread id indicator. See issue #136. */ else if (stream->pos < - SyNrCols - 2 - 6 * (TLS(threadID) != 0) - IO()->NoSplitLine) { + SyNrCols - 2 - 6 * (TLS(threadID) != 0) - IO(NoSplitLine)) { #else - else if (stream->pos < SyNrCols - 2 - IO()->NoSplitLine) { + else if (stream->pos < SyNrCols - 2 - IO(NoSplitLine)) { #endif // put the character on this line @@ -1390,7 +1398,7 @@ static void PutChrTo(TypOutputFile * stream, Char ch) */ static Obj FuncToggleEcho(Obj self) { - IO()->Input->echo = !IO()->Input->echo; + IO(Input)->echo = !IO(Input)->echo; return (Obj)0; } @@ -1428,8 +1436,8 @@ static Obj FuncPRINT_CPROMPT(Obj self, Obj prompt) void ResetOutputIndent(void) { - GAP_ASSERT(IO()->Output); - IO()->Output->indent = 0; + GAP_ASSERT(IO(Output)); + IO(Output)->indent = 0; } @@ -1625,14 +1633,14 @@ static inline void FormatOutput( // with null bytes, behavior of 'prec' is undefined. if (*q == '\0') continue; - if (*q == '\\' && IO()->NoSplitLine == 0) { + if (*q == '\\' && IO(NoSplitLine) == 0) { if (*(q + 1) < '8' && *(q + 1) >= '0') - IO()->NoSplitLine = 3; + IO(NoSplitLine) = 3; else - IO()->NoSplitLine = 1; + IO(NoSplitLine) = 1; } - else if (IO()->NoSplitLine > 0) - IO()->NoSplitLine--; + else if (IO(NoSplitLine) > 0) + IO(NoSplitLine)--; put_a_char(state, *q); if (arg1obj) { @@ -1788,11 +1796,11 @@ void Pr ( Int arg2 ) { #ifdef HPCGAP - if (!IO()->Output) { - OpenDefaultOutput(&IO()->DefaultOutput); + if (!IO(Output)) { + OpenDefaultOutput(&IO(DefaultOutput)); } #endif - PrTo(IO()->Output, format, arg1, arg2); + PrTo(IO(Output), format, arg1, arg2); } typedef struct { @@ -1818,52 +1826,52 @@ void SPrTo(Char *buffer, UInt maxlen, const Char *format, Int arg1, Int arg2) static Obj FuncINPUT_FILENAME(Obj self) { - if (IO()->Input == 0) + if (IO(Input) == 0) return MakeImmString("*defin*"); - UInt gapnameid = GetInputFilenameID(IO()->Input); + UInt gapnameid = GetInputFilenameID(IO(Input)); return GetCachedFilename(gapnameid); } static Obj FuncINPUT_LINENUMBER(Obj self) { - return INTOBJ_INT(IO()->Input ? IO()->Input->number : 0); + return INTOBJ_INT(IO(Input) ? IO(Input)->number : 0); } static Obj FuncSET_PRINT_FORMATTING_STDOUT(Obj self, Obj val) { BOOL format = (val != False); - TypOutputFile * output = IO()->Output; + TypOutputFile * output = IO(Output); while (output) { if (!output->stream && output->file == 1) output->format = format; output = output->prev; } - IO()->PrintFormattingForStdout = format; + IO(PrintFormattingForStdout) = format; return 0; } static Obj FuncPRINT_FORMATTING_STDOUT(Obj self) { - return IO()->PrintFormattingForStdout ? True : False; + return IO(PrintFormattingForStdout) ? True : False; } static Obj FuncSET_PRINT_FORMATTING_ERROUT(Obj self, Obj val) { BOOL format = (val != False); - TypOutputFile * output = IO()->Output; + TypOutputFile * output = IO(Output); while (output) { if (!output->stream && output->file == 3) output->format = format; output = output->prev; } - IO()->PrintFormattingForErrout = format; + IO(PrintFormattingForErrout) = format; return 0; } static Obj FuncPRINT_FORMATTING_ERROUT(Obj self) { - return IO()->PrintFormattingForErrout ? True : False; + return IO(PrintFormattingForErrout) ? True : False; } /**************************************************************************** @@ -1878,7 +1886,7 @@ static Obj FuncCALL_WITH_FORMATTING_STATUS(Obj self, Obj status, Obj func, Obj a RequireTrueOrFalse(SELF_NAME, status); RequireSmallList(SELF_NAME, args); - TypOutputFile * output = IO()->Output; + TypOutputFile * output = IO(Output); if (!output) ErrorMayQuit("CALL_WITH_FORMATTING_STATUS called while no output is open", 0, 0); @@ -1902,18 +1910,18 @@ static Obj FuncCALL_WITH_FORMATTING_STATUS(Obj self, Obj status, Obj func, Obj a static Obj FuncIS_INPUT_TTY(Obj self) { - GAP_ASSERT(IO()->Input); - if (IO()->Input->stream) + GAP_ASSERT(IO(Input)); + if (IO(Input)->stream) return False; - return SyBufIsTTY(IO()->Input->file) ? True : False; + return SyBufIsTTY(IO(Input)->file) ? True : False; } static Obj FuncIS_OUTPUT_TTY(Obj self) { - GAP_ASSERT(IO()->Output); - if (IO()->Output->stream) + GAP_ASSERT(IO(Output)); + if (IO(Output)->stream) return False; - return SyBufIsTTY(IO()->Output->file) ? True : False; + return SyBufIsTTY(IO(Output)->file) ? True : False; } static Obj FuncGET_FILENAME_CACHE(Obj self) @@ -1960,14 +1968,14 @@ static Int InitLibrary ( static Int InitKernel ( StructInitInfo * module ) { - IO()->Input = 0; - IO()->Output = 0; - IO()->InputLog = 0; - IO()->OutputLog = 0; - IO()->PrintFormattingForStdout = TRUE; - IO()->PrintFormattingForErrout = TRUE; + IO(Input) = 0; + IO(Output) = 0; + IO(InputLog) = 0; + IO(OutputLog) = 0; + IO(PrintFormattingForStdout) = TRUE; + IO(PrintFormattingForErrout) = TRUE; - OpenOutput(&IO()->DefaultOutput, "*stdout*", FALSE); + OpenOutput(&IO(DefaultOutput), "*stdout*", FALSE); InitSymbolTableKernel(&FilenameSymbolTable, "FilenameSymbolCount", "FilenameSymbolTable", GetCachedFilename, @@ -1982,9 +1990,9 @@ static Int InitKernel ( #else // register global bags with the garbage collector - InitGlobalBag(&(IO()->InputLogFileOrStream.stream), + InitGlobalBag(&(IO(InputLogFileOrStream).stream), "src/io.c:InputLogFileOrStream"); - InitGlobalBag(&(IO()->OutputLogFileOrStream.stream), + InitGlobalBag(&(IO(OutputLogFileOrStream).stream), "src/io.c:OutputLogFileOrStream"); #endif @@ -2014,9 +2022,10 @@ static StructInitInfo module = { .name = "io", .initKernel = InitKernel, .initLibrary = InitLibrary, - +#ifdef HPCGAP .moduleStateSize = sizeof(struct IOModuleState), .moduleStateOffsetPtr = &IOStateOffset, +#endif }; StructInitInfo * InitInfoIO ( void ) diff --git a/src/modules.c b/src/modules.c index 5b7a0f832c..6b1b689c6b 100644 --- a/src/modules.c +++ b/src/modules.c @@ -97,6 +97,8 @@ static Int NrImportedGVars; static StructImportedGVars ImportedFuncs[MAX_IMPORTED_GVARS]; static Int NrImportedFuncs; +#ifdef HPCGAP + static Int StateNextFreeOffset = 0; // Start of next free memory area (as offset into GAPState.StateSlots) static void RegisterModuleState(StructInitInfo * info) @@ -123,6 +125,7 @@ static void RegisterModuleState(StructInitInfo * info) StateNextFreeOffset = (StateNextFreeOffset + sizeof(Obj)-1) & ~(sizeof(Obj)-1); } +#endif /************************************************************************* ** @@ -149,7 +152,9 @@ Int ActivateModule(StructInitInfo * info) { Int res = 0; +#ifdef HPCGAP RegisterModuleState(info); +#endif if (info->initKernel) { res = info->initKernel(info); @@ -941,7 +946,9 @@ void ModulesSetup(void) fputs(")\n", stderr); } +#ifdef HPCGAP RegisterModuleState(info); +#endif } NrBuiltinModules = NrModules; } diff --git a/src/modules.h b/src/modules.h index def31697c2..1c21120aed 100644 --- a/src/modules.h +++ b/src/modules.h @@ -90,12 +90,18 @@ struct init_info { // function to call after restoring workspace Int (*postRestore)(StructInitInfo *); +#ifdef HPCGAP // number of bytes this module needs for its per-thread module state + // Only used in HPC-GAP, but not behind an #ifdef guard to avoid API + // breakage for C++ kernel extensions UInt moduleStateSize; // if this is not zero, then the module state offset is stored into // the address this points at + // Only used in HPC-GAP, but not behind an #ifdef guard to avoid API + // breakage for C++ kernel extensions Int * moduleStateOffsetPtr; +#endif // initialize thread local module state Int (*initModuleState)(void); diff --git a/src/objcftl.c b/src/objcftl.c index 557827816f..472fd33772 100644 --- a/src/objcftl.c +++ b/src/objcftl.c @@ -32,13 +32,16 @@ #include "plist.h" +#ifdef HPCGAP static ModuleStateOffset CFTLStateOffset = -1; struct CFTLModuleState { - Obj WORD_STACK; - Obj WORD_EXPONENT_STACK; - Obj SYLLABLE_STACK; - Obj EXPONENT_STACK; +#endif + DECL_MODULE_STATE Obj WORD_STACK; + DECL_MODULE_STATE Obj WORD_EXPONENT_STACK; + DECL_MODULE_STATE Obj SYLLABLE_STACK; + DECL_MODULE_STATE Obj EXPONENT_STACK; +#ifdef HPCGAP }; extern inline struct CFTLModuleState *CFTLState(void) @@ -46,6 +49,12 @@ extern inline struct CFTLModuleState *CFTLState(void) return (struct CFTLModuleState *)StateSlotsAtOffset(CFTLStateOffset); } +#define WORD_STACK (CFTLState()->WORD_STACK) +#define WORD_EXPONENT_STACK (CFTLState()->WORD_EXPONENT_STACK) +#define SYLLABLE_STACK (CFTLState()->SYLLABLE_STACK) +#define EXPONENT_STACK (CFTLState()->EXPONENT_STACK) +#endif + static inline Obj IncInt(Obj x) { if (IS_INTOBJ(x) && x != INTOBJ_MAX) { @@ -133,10 +142,10 @@ static Obj CollectPolycyc(Obj pcp, Obj list, Obj word) Obj ipow = CONST_ADDR_OBJ(pcp)[ PC_INVERSEPOWERS ]; Obj exp = CONST_ADDR_OBJ(pcp)[ PC_EXPONENTS ]; - Obj wst = CFTLState()->WORD_STACK; - Obj west = CFTLState()->WORD_EXPONENT_STACK; - Obj sst = CFTLState()->SYLLABLE_STACK; - Obj est = CFTLState()->EXPONENT_STACK; + Obj wst = WORD_STACK; + Obj west = WORD_EXPONENT_STACK; + Obj sst = SYLLABLE_STACK; + Obj est = EXPONENT_STACK; Obj conj=0, iconj=0; /*QQ initialize to please compiler */ @@ -411,15 +420,15 @@ static Int InitLibrary ( static Int InitModuleState(void) { - InitGlobalBag( &CFTLState()->WORD_STACK, "WORD_STACK" ); - InitGlobalBag( &CFTLState()->WORD_EXPONENT_STACK, "WORD_EXPONENT_STACK" ); - InitGlobalBag( &CFTLState()->SYLLABLE_STACK, "SYLLABLE_STACK" ); - InitGlobalBag( &CFTLState()->EXPONENT_STACK, "EXPONENT_STACK" ); + InitGlobalBag( &WORD_STACK, "WORD_STACK" ); + InitGlobalBag( &WORD_EXPONENT_STACK, "WORD_EXPONENT_STACK" ); + InitGlobalBag( &SYLLABLE_STACK, "SYLLABLE_STACK" ); + InitGlobalBag( &EXPONENT_STACK, "EXPONENT_STACK" ); - CFTLState()->WORD_STACK = NEW_PLIST( T_PLIST, 4096 ); - CFTLState()->WORD_EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); - CFTLState()->SYLLABLE_STACK = NEW_PLIST( T_PLIST, 4096 ); - CFTLState()->EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); + WORD_STACK = NEW_PLIST( T_PLIST, 4096 ); + WORD_EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); + SYLLABLE_STACK = NEW_PLIST( T_PLIST, 4096 ); + EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); return 0; } @@ -436,8 +445,10 @@ static StructInitInfo module = { .initKernel = InitKernel, .initLibrary = InitLibrary, +#ifdef HPCGAP .moduleStateSize = sizeof(struct CFTLModuleState), .moduleStateOffsetPtr = &CFTLStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/objects.c b/src/objects.c index d76f74d6bb..8775fc0159 100644 --- a/src/objects.c +++ b/src/objects.c @@ -44,12 +44,14 @@ enum { MAXPRINTDEPTH = 64, }; +#ifdef HPCGAP static ModuleStateOffset ObjectsStateOffset = -1; typedef struct { - UInt PrintObjDepth; - Obj PrintObjThiss[MAXPRINTDEPTH]; - Int PrintObjIndices[MAXPRINTDEPTH]; +#endif + DECL_MODULE_STATE UInt PrintObjDepth; + DECL_MODULE_STATE Obj PrintObjThiss[MAXPRINTDEPTH]; + DECL_MODULE_STATE Int PrintObjIndices[MAXPRINTDEPTH]; // This variable is used to allow a ViewObj method to call PrintObj on the // same object without triggering use of '~'. It contains one of the @@ -57,10 +59,16 @@ typedef struct { // 0: there is no enclosing call to PrintObj or ViewObj still open, or // 1: the innermost such is PrintObj, or // 2: the innermost such is ViewObj. - UInt LastPV; + DECL_MODULE_STATE UInt LastPV; +#ifdef HPCGAP } ObjectsModuleState; +#define PrintObjDepth MODULE_STATE(Objects, PrintObjDepth) +#define PrintObjThiss MODULE_STATE(Objects, PrintObjThiss) +#define PrintObjIndices MODULE_STATE(Objects, PrintObjIndices) +#define LastPV MODULE_STATE(Objects, LastPV) +#endif static Int lastFreePackageTNUM = FIRST_PACKAGE_TNUM; @@ -895,13 +903,13 @@ static Obj FuncGET_TNAM_FROM_TNUM(Obj self, Obj obj) // This function is used to keep track of which objects are already // being printed or viewed to trigger the use of ~ when needed. -static inline BOOL IS_ON_PRINT_STACK(const ObjectsModuleState * os, Obj obj) +static inline BOOL IS_ON_PRINT_STACK(Obj obj) { if (!(FIRST_RECORD_TNUM <= TNUM_OBJ(obj) && TNUM_OBJ(obj) <= LAST_LIST_TNUM)) return FALSE; - for (UInt i = 0; i < os->PrintObjDepth; i++) - if (os->PrintObjThiss[i] == obj) + for (UInt i = 0; i < PrintObjDepth; i++) + if (PrintObjThiss[i] == obj) return TRUE; return FALSE; } @@ -961,46 +969,44 @@ void PrintObj(Obj obj) } #endif - ObjectsModuleState * os = &MODULE_STATE(Objects); - // First check if is actually the current object being viewed, since // ViewObj() may result in a call to PrintObj(); in that case, // we should not put on the print stack - if ((os->PrintObjDepth > 0) && (os->LastPV == 2) && - (obj == os->PrintObjThiss[os->PrintObjDepth - 1])) { - os->LastPV = 1; + if ((PrintObjDepth > 0) && (LastPV == 2) && + (obj == PrintObjThiss[PrintObjDepth - 1])) { + LastPV = 1; PRINT_OBJ(obj); - os->LastPV = 2; + LastPV = 2; } // print the path if is on the stack - else if (IS_ON_PRINT_STACK(os, obj)) { + else if (IS_ON_PRINT_STACK(obj)) { Pr("~", 0, 0); - for (int i = 0; obj != os->PrintObjThiss[i]; i++) { - PRINT_PATH(os->PrintObjThiss[i], os->PrintObjIndices[i]); + for (int i = 0; obj != PrintObjThiss[i]; i++) { + PRINT_PATH(PrintObjThiss[i], PrintObjIndices[i]); } } // dispatch to the appropriate printing function - else if (os->PrintObjDepth < MAXPRINTDEPTH) { + else if (PrintObjDepth < MAXPRINTDEPTH) { - Obj oldThis = os->PrintObjThiss[os->PrintObjDepth]; - Int oldIndx = os->PrintObjIndices[os->PrintObjDepth]; + Obj oldThis = PrintObjThiss[PrintObjDepth]; + Int oldIndx = PrintObjIndices[PrintObjDepth]; // push obj on the stack - os->PrintObjThiss[os->PrintObjDepth] = obj; - os->PrintObjIndices[os->PrintObjDepth] = 0; - os->PrintObjDepth++; + PrintObjThiss[PrintObjDepth] = obj; + PrintObjIndices[PrintObjDepth] = 0; + PrintObjDepth++; - UInt lastPV = os->LastPV; - os->LastPV = 1; + UInt lastPV = LastPV; + LastPV = 1; PRINT_OBJ(obj); - os->LastPV = lastPV; + LastPV = lastPV; // pop from the stack - os->PrintObjDepth--; - os->PrintObjThiss[os->PrintObjDepth] = oldThis; - os->PrintObjIndices[os->PrintObjDepth] = oldIndx; + PrintObjDepth--; + PrintObjThiss[PrintObjDepth] = oldThis; + PrintObjIndices[PrintObjDepth] = oldIndx; } else { Pr("\nprinting stopped, too many recursion levels!\n", 0, 0); @@ -1044,19 +1050,19 @@ static Obj FuncPRINT_OBJ(Obj self, Obj obj) UInt SetPrintObjState(UInt state) { - UInt oldDepth = MODULE_STATE(Objects).PrintObjDepth; - UInt oldLastPV = MODULE_STATE(Objects).LastPV; - MODULE_STATE(Objects).PrintObjDepth = state >> 2; - MODULE_STATE(Objects).LastPV = state & 3; + UInt oldDepth = PrintObjDepth; + UInt oldLastPV = LastPV; + PrintObjDepth = state >> 2; + LastPV = state & 3; return (oldDepth << 2) | oldLastPV; } void SetPrintObjIndex(Int index) { - UInt depth = MODULE_STATE(Objects).PrintObjDepth; + UInt depth = PrintObjDepth; if (depth == 0) ErrorQuit("SetPrintObjIndex: bad state, PrintObjDepth is 0", 0, 0); - MODULE_STATE(Objects).PrintObjIndices[depth - 1] = index; + PrintObjIndices[depth - 1] = index; } static Obj FuncSET_PRINT_OBJ_INDEX(Obj self, Obj index) @@ -1087,36 +1093,34 @@ void ViewObj(Obj obj) } #endif - ObjectsModuleState * os = &MODULE_STATE(Objects); - // print the path if is on the stack - if (IS_ON_PRINT_STACK(os, obj)) { + if (IS_ON_PRINT_STACK(obj)) { Pr("~", 0, 0); - for (int i = 0; obj != os->PrintObjThiss[i]; i++) { - PRINT_PATH(os->PrintObjThiss[i], os->PrintObjIndices[i]); + for (int i = 0; obj != PrintObjThiss[i]; i++) { + PRINT_PATH(PrintObjThiss[i], PrintObjIndices[i]); } } // dispatch to the appropriate viewing function - else if (os->PrintObjDepth < MAXPRINTDEPTH) { + else if (PrintObjDepth < MAXPRINTDEPTH) { - Obj oldThis = os->PrintObjThiss[os->PrintObjDepth]; - Int oldIndx = os->PrintObjIndices[os->PrintObjDepth]; + Obj oldThis = PrintObjThiss[PrintObjDepth]; + Int oldIndx = PrintObjIndices[PrintObjDepth]; // push obj on the stack - os->PrintObjThiss[os->PrintObjDepth] = obj; - os->PrintObjIndices[os->PrintObjDepth] = 0; - os->PrintObjDepth++; + PrintObjThiss[PrintObjDepth] = obj; + PrintObjIndices[PrintObjDepth] = 0; + PrintObjDepth++; - UInt lastPV = os->LastPV; - os->LastPV = 2; + UInt lastPV = LastPV; + LastPV = 2; DoOperation1Args(ViewObjOper, obj); - os->LastPV = lastPV; + LastPV = lastPV; // pop from the stack - os->PrintObjDepth--; - os->PrintObjThiss[os->PrintObjDepth] = oldThis; - os->PrintObjIndices[os->PrintObjDepth] = oldIndx; + PrintObjDepth--; + PrintObjThiss[PrintObjDepth] = oldThis; + PrintObjIndices[PrintObjDepth] = oldIndx; } else { Pr("\nviewing stopped, too many recursion levels!\n", 0, 0); @@ -2341,8 +2345,10 @@ static StructInitInfo module = { .initKernel = InitKernel, .initLibrary = InitLibrary, +#ifdef HPCGAP .moduleStateSize = sizeof(ObjectsModuleState), .moduleStateOffsetPtr = &ObjectsStateOffset, +#endif }; StructInitInfo * InitInfoObjects ( void ) diff --git a/src/objfgelm.cc b/src/objfgelm.cc index 48d21c52b8..633b5f970f 100644 --- a/src/objfgelm.cc +++ b/src/objfgelm.cc @@ -1596,8 +1596,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ 0, /* moduleStateOffsetPtr = */ 0, +#endif /* initModuleState = */ 0, /* destroyModuleState = */ 0, }; diff --git a/src/objpcgel.cc b/src/objpcgel.cc index ec5b0b05f8..358e59330a 100644 --- a/src/objpcgel.cc +++ b/src/objpcgel.cc @@ -381,8 +381,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ 0, /* moduleStateOffsetPtr = */ 0, +#endif /* initModuleState = */ 0, /* destroyModuleState = */ 0, }; diff --git a/src/opers.cc b/src/opers.cc index 546e08d928..ce86f7a99d 100644 --- a/src/opers.cc +++ b/src/opers.cc @@ -3903,8 +3903,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ PostRestore, +#ifdef HPCGAP /* moduleStateSize = */ 0, /* moduleStateOffsetPtr = */ 0, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/permutat.cc b/src/permutat.cc index 50a030366d..ccd5cfe976 100644 --- a/src/permutat.cc +++ b/src/permutat.cc @@ -84,9 +84,11 @@ Obj IdentityPerm; static const UInt MAX_DEG_PERM4 = ((Int)1 << (sizeof(UInt) == 8 ? 32 : 28)) - 1; +#ifdef HPCGAP static ModuleStateOffset PermutatStateOffset = -1; typedef struct { +#endif /**************************************************************************** ** @@ -102,11 +104,13 @@ typedef struct { ** costs (particularly when starting new threads). ** Use the UseTmpPerm() utility function to ensure it is constructed! */ -Obj TmpPerm; +DECL_MODULE_STATE Obj TmpPerm; +#ifdef HPCGAP } PermutatModuleState; -#define TmpPerm MODULE_STATE(Permutat).TmpPerm +#define TmpPerm MODULE_STATE(Permutat, TmpPerm) +#endif static UInt1 * UseTmpPerm(UInt size) @@ -3039,8 +3043,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ PostRestore, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(PermutatModuleState), /* moduleStateOffsetPtr = */ &PermutatStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/pperm.cc b/src/pperm.cc index 921c204d9e..af1fdcb270 100644 --- a/src/pperm.cc +++ b/src/pperm.cc @@ -120,9 +120,11 @@ static Obj EmptyPartialPerm; "must be a partial permutation") +#ifdef HPCGAP static ModuleStateOffset PPermStateOffset = -1; typedef struct { +#endif /************************************************************************** * @@ -136,12 +138,13 @@ typedef struct { * The buffer is *not* guaranteed to have any particular value, routines * that require a zero-initialization need to do this at the start. */ - Obj TmpPPerm; + DECL_MODULE_STATE Obj TmpPPerm; +#ifdef HPCGAP } PPermModuleState; - -#define TmpPPerm MODULE_STATE(PPerm).TmpPPerm +#define TmpPPerm MODULE_STATE(PPerm, TmpPPerm) +#endif static inline void ResizeTmpPPerm(UInt len) { @@ -3995,8 +3998,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(PPermModuleState), /* moduleStateOffsetPtr = */ &PPermStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/trans.cc b/src/trans.cc index 2558a37693..f50a2cfb53 100644 --- a/src/trans.cc +++ b/src/trans.cc @@ -175,21 +175,22 @@ static Int GetPositiveListEntryEx(const char * funcname, GetPositiveListEntryEx(funcname, list, idx, NICE_ARGNAME(list)) +#ifdef HPCGAP static ModuleStateOffset TransStateOffset = -1; typedef struct { +#endif // TmpTrans is essentially the same as TmpPerm - Obj TmpTrans; + DECL_MODULE_STATE Obj TmpTrans; +#ifdef HPCGAP } TransModuleState; -static inline Obj GetTmpTrans(void) -{ - return MODULE_STATE(Trans).TmpTrans; -} +#define TmpTrans MODULE_STATE(Trans, TmpTrans) +#endif static inline UInt4 * AddrTmpTrans(void) { - return ADDR_TRANS4(GetTmpTrans()); + return ADDR_TRANS4(TmpTrans); } @@ -255,9 +256,9 @@ static inline void SET_EXT_TRANS(Obj f, Obj deg) static inline void ResizeTmpTrans(UInt len) { - Obj tmpTrans = GetTmpTrans(); + Obj tmpTrans = TmpTrans; if (tmpTrans == (Obj)0) { - MODULE_STATE(Trans).TmpTrans = NewBag(T_TRANS4, len * sizeof(UInt4) + 3 * sizeof(Obj)); + TmpTrans = NewBag(T_TRANS4, len * sizeof(UInt4) + 3 * sizeof(Obj)); } else if (SIZE_OBJ(tmpTrans) < len * sizeof(UInt4) + 3 * sizeof(Obj)) { ResizeBag(tmpTrans, len * sizeof(UInt4) + 3 * sizeof(Obj)); @@ -4211,7 +4212,7 @@ static Int InitKernel(StructInitInfo * module) InitHdlrFuncsFromTable(GVarFuncs); // register global bags with the garbage collector - InitGlobalBag(&MODULE_STATE(Trans).TmpTrans, "src/trans.c:TmpTrans"); + InitGlobalBag(&TmpTrans, "src/trans.c:TmpTrans"); InitGlobalBag(&IdentityTrans, "src/trans.c:IdentityTrans"); #ifdef GAP_ENABLE_SAVELOAD @@ -4295,7 +4296,7 @@ static Int InitLibrary(StructInitInfo * module) static Int InitModuleState(void) { - MODULE_STATE(Trans).TmpTrans = 0; + TmpTrans = 0; return 0; } @@ -4317,8 +4318,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(TransModuleState), /* moduleStateOffsetPtr = */ &TransStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; From 55a5941494d23cedbecce3b370a6774528b9b044 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 May 2026 12:13:24 +0200 Subject: [PATCH 060/123] Ensure more tests pass with `gap --bare` (#6387) - remove a bunch of SmallGroup and IdGroup uses in tst files - remove tst/testbugfix/2005-05-03-t00070.tst (an equivalent test was added to the smallgrp package recently) - modify some .tst file to run parts only if certain packages are available, via `#@if IsPackageMarkedForLoading(...)` - don't load `ctbllib` (and all its dependencies) in `ctblmaps.tst` --- tst/testbugfix/00008.tst | 2 +- tst/testbugfix/2005-05-03-t00070.tst | 5 -- tst/testinstall/ctbl.tst | 6 +- tst/testinstall/ctblmaps.tst | 3 +- tst/testinstall/ctblmono.tst | 33 +++++++++++ tst/testinstall/ctblsolv.tst | 9 +-- tst/testinstall/grp/basic.tst | 10 ++-- tst/testinstall/grpfp.tst | 4 ++ tst/testinstall/grpmat.tst | 2 + tst/testinstall/grppc.tst | 4 +- tst/testinstall/interpreter.tst | 2 + tst/testinstall/mapphomo.tst | 2 +- tst/testinstall/matblock.tst | 2 +- tst/testinstall/meatauto.tst | 4 +- tst/testinstall/meataxe.tst | 10 ++-- tst/testinstall/opers/FittingSubgroup.tst | 3 +- tst/testinstall/opers/FrattiniSubgroup.tst | 9 +-- tst/testinstall/opers/HallSubgroup.tst | 9 ++- tst/testinstall/opers/IsSolvableGroup.tst | 2 + .../opers/LatticeByCyclicExtension.tst | 9 ++- .../opers/MinimalNormalSubgroups.tst | 57 ++++++++++++------- tst/testinstall/opers/NormalHallSubgroups.tst | 8 +++ tst/testinstall/opers/SimpleGroup.tst | 12 ++++ tst/testinstall/opers/Socle.tst | 51 +++++++++-------- .../opers/StructureDescription.tst | 21 +++++++ tst/testinstall/opers/SubdirectProducts.tst | 47 +++++++++------ 26 files changed, 225 insertions(+), 101 deletions(-) delete mode 100644 tst/testbugfix/2005-05-03-t00070.tst diff --git a/tst/testbugfix/00008.tst b/tst/testbugfix/00008.tst index 0488c51eca..b9860dcf8d 100644 --- a/tst/testbugfix/00008.tst +++ b/tst/testbugfix/00008.tst @@ -5,7 +5,7 @@ gap> EulerianFunction( CyclicGroup(6), 1 ); 2 gap> EulerianFunction( CyclicGroup(5), 1 ); 4 -gap> g:=SmallGroup(1,1);; +gap> g:=TrivialGroup(IsPcGroup);; gap> ConjugacyClassesSubgroups(g);; gap> g:=Group([ (3,5), (1,3,5) ]);; gap> MaximalSubgroups(g);; diff --git a/tst/testbugfix/2005-05-03-t00070.tst b/tst/testbugfix/2005-05-03-t00070.tst deleted file mode 100644 index 618574eb11..0000000000 --- a/tst/testbugfix/2005-05-03-t00070.tst +++ /dev/null @@ -1,5 +0,0 @@ -# 2005/05/03 (BE) -gap> NumberSmallGroups(5^6); -684 -gap> NumberSmallGroups(5*7*9*11*13); -22 diff --git a/tst/testinstall/ctbl.tst b/tst/testinstall/ctbl.tst index f8d23bbc13..3f5ec76722 100644 --- a/tst/testinstall/ctbl.tst +++ b/tst/testinstall/ctbl.tst @@ -443,19 +443,19 @@ gap> HasIsIrreducibleCharacter( TrivialCharacter( SymmetricGroup( 4 ) ) ); true # concurring 'Irr' methods -gap> G:= PcGroupCode( 221729, 24 );; +gap> G:= PcGroupCode( 221729, 24 );; # = SmallGroup( 24, 5 ) gap> IsSupersolvable( G ); true gap> Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Baum-Clausen Algorithm" -gap> G:= PcGroupCode( 221729, 24 );; +gap> G:= PcGroupCode( 221729, 24 );; # = SmallGroup( 24, 5 ) gap> IsSupersolvable( G ); true gap> IrrConlon( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Conlon's Algorithm" -gap> G:= PcGroupCode( 221729, 24 );; +gap> G:= PcGroupCode( 221729, 24 );; # = SmallGroup( 24, 5 ) gap> IrrDixonSchneider( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Dixon's Algorithm" diff --git a/tst/testinstall/ctblmaps.tst b/tst/testinstall/ctblmaps.tst index a40f5bb942..3d36393af9 100644 --- a/tst/testinstall/ctblmaps.tst +++ b/tst/testinstall/ctblmaps.tst @@ -3,8 +3,7 @@ gap> START_TEST( "ctblmaps.tst" ); # `ConsiderStructureConstants` can unexpectedly exclude all candidates. # (Benjamin Sambale found examples for that.) -gap> if TestPackageAvailability("ctbllib") <> fail and -> LoadPackage("ctbllib", false) <> fail then +gap> if IsPackageMarkedForLoading( "ctbllib", "" ) then > s:= CharacterTable( "2.A6" );; > t:= CharacterTable( "Co3" );; > maps:= [ [ 1, 2, 8, 4, 11, 4, 13, 18, 18, 9, 22, 9, 22 ], diff --git a/tst/testinstall/ctblmono.tst b/tst/testinstall/ctblmono.tst index 0b57b930b0..bb9c88e01e 100644 --- a/tst/testinstall/ctblmono.tst +++ b/tst/testinstall/ctblmono.tst @@ -96,6 +96,8 @@ gap> TestMonomial( irr[2] ); rec( comment := "whole group is monomial", isMonomial := true ) gap> IsMonomial( irr[2] ); true + +# gap> irr:= Irr( SL(2,3) );; gap> chi:= First( irr, x -> x[1] = 3 );; gap> TestMonomialQuick( chi ); @@ -104,6 +106,8 @@ gap> TestMonomial( chi ); rec( comment := "codegree is prime power", isMonomial := true ) gap> IsMonomial( chi ); true + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> irr:= Irr( SmallGroup( 120, 15 ) );; gap> chi:= First( irr, x -> x[1] = 3 and > Length( ClassPositionsOfKernel( x ) ) = 2 );; @@ -121,6 +125,9 @@ gap> TestMonomial( chi ); rec( comment := "induced from monomial Hall subgroup", isMonomial := true ) gap> IsMonomial( chi ); true +#@fi + +# gap> g:= DirectProduct( AlternatingGroup(5), SymmetricGroup(3), > SymmetricGroup(3) );; gap> chi:= First( Irr( g ), x -> x[1] = 2 and @@ -131,6 +138,8 @@ gap> TestMonomial( chi ); rec( comment := "kernel factor group is supersolvable", isMonomial := true ) gap> IsMonomial( chi ); true + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> irr:= Irr( SmallGroup( 144, 31 ) );; gap> chi:= First( irr, x -> x[1] = 6 );; gap> TestMonomialQuick( chi ); @@ -139,6 +148,9 @@ gap> TestMonomial( chi ); rec( comment := "kernel factor group is monomial", isMonomial := true ) gap> IsMonomial( chi ); true +#@fi + +# gap> irr:= Irr( SL(2,3) );; gap> chi:= First( irr, x -> x[1] = 2 );; gap> TestMonomialQuick( chi ); @@ -147,6 +159,8 @@ gap> TestMonomial( chi ); rec( comment := "quasiprimitive character", isMonomial := false ) gap> IsMonomial( chi ); false + +# gap> irr:= Irr( AlternatingGroup( 5 ) );; gap> chi:= First( irr, x -> x[1] = 5 );; gap> TestMonomialQuick( chi ); @@ -166,6 +180,8 @@ gap> TestMonomial( chi, true ).comment; "lattice checked" gap> IsMonomial( chi ); false + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> irr:= Irr( SmallGroup( 96, 204 ) );; gap> chi:= First( irr, x -> x[1] = 4 );; gap> TestMonomialQuick( chi ); @@ -174,6 +190,9 @@ gap> TestMonomial( chi ).comment; "induced from 'character'" gap> IsMonomial( chi ); true +#@fi + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> chi:= First( Irr( SmallGroup( 144, 31 ) ), x -> x[1] = 4 );; gap> TestMonomialQuick( chi ); rec( comment := "no decision by cheap tests", isMonomial := "?" ) @@ -183,6 +202,9 @@ gap> TestMonomial( chi, true ).comment; "induced from 'character'" gap> IsMonomial( chi ); true +#@fi + +# gap> chi:= 0 * [ 1 .. NrConjugacyClasses( S4 ) ];; gap> chi[1]:= Size( S4 );; gap> chi:= ClassFunction( S4, chi );; @@ -193,6 +215,8 @@ gap> TestMonomial( chi, true ).comment; gap> IsMonomial( chi ); true gap> TestMonomialUseLattice:= TestMonomialUseLattice_Orig;; + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> chi:= First( Irr( SmallGroup( 48, 28 ) ), x -> x[1] = 4 );; gap> TestMonomialQuick( chi ); rec( comment := "no decision by cheap tests", isMonomial := "?" ) @@ -200,6 +224,7 @@ gap> TestMonomial( chi ).comment; "induced from 'character'" gap> IsMonomial( chi ); true +#@fi ## gap> TestMonomialQuick( S4 ); @@ -214,6 +239,8 @@ gap> TestMonomial( Sl23 ); rec( comment := "list Delta( G ) contains entry > 1", isMonomial := false ) gap> IsMonomial( Sl23 ); false + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> g:= SmallGroup( 96, 204 );; gap> TestMonomialQuick( g ); rec( comment := "no decision by cheap tests", isMonomial := "?" ) @@ -239,6 +266,9 @@ gap> TestMonomial( g ); rec( comment := "was already stored", isMonomial := true ) gap> IsMonomial( g ); true +#@fi + +# gap> g:= AlternatingGroup( 5 );; gap> TestMonomialQuick( g ); rec( comment := "non-solvable group", isMonomial := false ) @@ -246,6 +276,8 @@ gap> TestMonomial( g ); rec( comment := "non-solvable group", isMonomial := false ) gap> IsMonomial( g ); false + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> g:= SmallGroup( 56, 10 );; gap> TestMonomialQuick( g ); rec( comment := "group order is monomial", isMonomial := true ) @@ -274,6 +306,7 @@ gap> TestMonomial( g ); rec( comment := "Sylow abelian by supersolvable group", isMonomial := true ) gap> IsMonomial( g ); true +#@fi ## gap> TestSubnormallyMonomial( S4 ); diff --git a/tst/testinstall/ctblsolv.tst b/tst/testinstall/ctblsolv.tst index 231e87319f..28a6955f0c 100644 --- a/tst/testinstall/ctblsolv.tst +++ b/tst/testinstall/ctblsolv.tst @@ -1,7 +1,7 @@ #@local G, pair, mth, all, rks, tbl gap> START_TEST("ctblsolv.tst"); -## +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> CharacterDegrees( SmallGroup( 256, 529 ) ); [ [ 1, 8 ], [ 2, 30 ], [ 4, 8 ] ] gap> for pair in [ [ 18, 3 ], [ 27, 3 ], [ 36, 7 ], [ 50, 3 ], [ 54, 4 ] ] do @@ -11,6 +11,7 @@ gap> for pair in [ [ 18, 3 ], [ 27, 3 ], [ 36, 7 ], [ 50, 3 ], [ 54, 4 ] ] do > Error( IdGroup( G ) ); > fi; > od; +#@fi ## gap> mth:= [];; @@ -18,11 +19,11 @@ gap> G:= AbelianGroup( [ 2, 3, 5 ] );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 30 ] ]; true -gap> G:= SmallGroup( 24, 12 );; Irr( G );; +gap> G:= SymmetricGroup(IsPcGroup, 4);; Irr( G );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 2 ], [ 2, 1 ], [ 3, 2 ] ]; true -gap> G:= SmallGroup( 24, 12 );; CharacterTable( G );; +gap> G:= SymmetricGroup(IsPcGroup, 4);; CharacterTable( G );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 2 ], [ 2, 1 ], [ 3, 2 ] ]; true @@ -34,7 +35,7 @@ gap> G:= Group( [ [ E(3) ] ], [ [ E(4) ] ] );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 12 ] ]; true -gap> G:= SmallGroup( 24, 12 );; # hier: auch überaufl.!!! +gap> G:= SymmetricGroup(IsPcGroup, 4);; # hier: auch überaufl.!!! gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 2 ], [ 2, 1 ], [ 3, 2 ] ]; true diff --git a/tst/testinstall/grp/basic.tst b/tst/testinstall/grp/basic.tst index b557cab1be..90254cc625 100644 --- a/tst/testinstall/grp/basic.tst +++ b/tst/testinstall/grp/basic.tst @@ -271,10 +271,10 @@ true # # dicyclic groups # -gap> IdGroup(DicyclicGroup(4)); -[ 4, 1 ] -gap> IdGroup(DicyclicGroup(IsFpGroup,4)); -[ 4, 1 ] +gap> StructureDescription(DicyclicGroup(4)); +"C4" +gap> StructureDescription(DicyclicGroup(IsFpGroup,4)); +"C4" gap> DicyclicGroup(8); gap> DicyclicGroup(IsPcGroup,8); @@ -340,10 +340,12 @@ gap> for n in [ 4, 12, 20, 24 ] do > Error( "gen. quat. group?" ); > fi; > od; +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> Number( AllSmallGroups( [ 1 .. 32 ], IsDicyclicGroup ) ); 8 gap> Number( AllSmallGroups( [ 1 .. 32 ], IsGeneralisedQuaternionGroup ) ); 3 +#@fi # gap> Q:= DicyclicGroup( 20 );; diff --git a/tst/testinstall/grpfp.tst b/tst/testinstall/grpfp.tst index 247402f216..0403a75baf 100644 --- a/tst/testinstall/grpfp.tst +++ b/tst/testinstall/grpfp.tst @@ -162,6 +162,7 @@ false Error, the f.p. group is not finite # RWS for G2(3) and S_6(2) +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> g:=SimpleGroup("G2(3)");; gap> hom:=IsomorphismFpGroupForRewriting(g);; gap> m:=Image(IsomorphismFpMonoid(Image(hom)));; @@ -169,6 +170,9 @@ gap> F:=m!.rewritingSystem;;; gap> ReducedForm(F,UnderlyingElement( > Product(GeneratorsOfMonoid(m){[1,3..19]}))); w1*B5*b6*b7*B8*w2*b1*B3*B4*b5*b6*b7 +#@fi + +# gap> g:=SimpleGroup("S6(2)");; gap> hom:=IsomorphismFpGroupForRewriting(g);; gap> m:=Image(IsomorphismFpMonoid(Image(hom)));; diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index 4c23741723..eea0eb9834 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -86,8 +86,10 @@ gap> TrivialSubgroup( GL(2, 2) ); # The following should take less than a second. +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> Length( LowIndexSubgroups( GL(2,5), 50 ) ) = 31; true +#@fi # 'NiceMonomorphism' behaves well w.r.t. 'ConstructingFilter' gap> G:= SP( 4, 2 );; diff --git a/tst/testinstall/grppc.tst b/tst/testinstall/grppc.tst index f526eba327..873257c589 100644 --- a/tst/testinstall/grppc.tst +++ b/tst/testinstall/grppc.tst @@ -137,7 +137,7 @@ gap> List( sys, Size ); [ 4, 7 ] gap> List(sys,i->Length(AsList(i))); [ 4, 7 ] -gap> G := SmallGroup( 144, 183 );; +gap> G := DirectProduct(SymmetricGroup(IsPcGroup, 3), SymmetricGroup(IsPcGroup, 4));; gap> F := FittingSubgroup( G );; gap> S := SylowSubgroup( F, 2 );; gap> Display(Image(IsomorphismPcGroup(S))); @@ -166,7 +166,7 @@ gap> RepresentativeAction(G,x,x^2)<>fail; true gap> RepresentativeAction(G,x,x^2); f1*f2 -gap> g := SmallGroup(243,27);; +gap> g := PcGroupCode(14055476799225975, 243);; # = SmallGroup(243,27) gap> AsSet(Omega(g,3,1)) = Set(Filtered(g, g -> IsOne(g^3))); true gap> AsSet(Omega(g,3,2)) = Set(Filtered(g, g -> IsOne(g^9))); diff --git a/tst/testinstall/interpreter.tst b/tst/testinstall/interpreter.tst index 5c758de733..e13308ab72 100644 --- a/tst/testinstall/interpreter.tst +++ b/tst/testinstall/interpreter.tst @@ -39,8 +39,10 @@ gap> QUIT; # # help system # +#@if IsPackageMarkedForLoading( "gapdoc", "" ) gap> ?qwert_asdf Help: no matching entry found +#@fi # # function call with options diff --git a/tst/testinstall/mapphomo.tst b/tst/testinstall/mapphomo.tst index 3e7a7f49ce..d6468f7834 100644 --- a/tst/testinstall/mapphomo.tst +++ b/tst/testinstall/mapphomo.tst @@ -86,7 +86,7 @@ gap> One( hom ); fail # Check that group homomorphisms created by a function can compute preimages. -gap> for G in [ SymmetricGroup(5), SmallGroup( 24, 12 ), GL(2,3) ] do +gap> for G in [ SymmetricGroup(5), DihedralGroup(8), GL(2,3) ] do > hom:= GroupHomomorphismByFunction( G, G, x -> x ); > PreImagesRepresentative( hom, G.1 ); > od; diff --git a/tst/testinstall/matblock.tst b/tst/testinstall/matblock.tst index f646628043..4043a465e8 100644 --- a/tst/testinstall/matblock.tst +++ b/tst/testinstall/matblock.tst @@ -138,7 +138,7 @@ gap> MinimalPolynomial( R, m2 ) = MinimalPolynomial( R, MatrixByBlockMatrix( m2 true # Groups that consist of block matrices -gap> G:= SmallGroup( 24, 12 );; +gap> G:= SymmetricGroup(IsPcGroup, 4);; gap> H:= SylowSubgroup( G, 2 );; gap> reps:= IrreducibleRepresentations( H );; gap> ind:= InducedRepresentation( reps[5], G );; diff --git a/tst/testinstall/meatauto.tst b/tst/testinstall/meatauto.tst index 5f7d064756..a51d6ec0f6 100644 --- a/tst/testinstall/meatauto.tst +++ b/tst/testinstall/meatauto.tst @@ -12,7 +12,7 @@ gap> SMTX_NullspaceEqns(e); # # MTX.BasisModuleEndomorphisms # -gap> G:=SmallGroup(24, 3);; +gap> G:=SL(2, 3);; gap> p:=NextPrimeInt(100);; gap> M:=RegularModule(G, GF(p))[2];; gap> MTX.BasisModuleEndomorphisms(M); @@ -44,7 +44,7 @@ gap> MTX.BasisModuleEndomorphisms(M); # # MTX.HomogeneousComponents # -gap> G:=SmallGroup(24, 3);; +gap> G:=SL(2, 3);; gap> p:=NextPrimeInt(100);; gap> M:=RegularModule(G, GF(p))[2];; gap> hc := MTX.HomogeneousComponents(M);; diff --git a/tst/testinstall/meataxe.tst b/tst/testinstall/meataxe.tst index 55dc6c66b2..7e076f17d9 100644 --- a/tst/testinstall/meataxe.tst +++ b/tst/testinstall/meataxe.tst @@ -77,8 +77,10 @@ gap> M2:=TensorProductGModule(M,M); rec( IsOverFiniteField := true, dimension := 9, field := GF(2), generators := [ , ], isMTXModule := true ) -gap> IdGroup(MTX.ModuleAutomorphisms(M2)); -[ 1344, 11301 ] +gap> G:=MTX.ModuleAutomorphisms(M2); + +gap> StructureDescription(G); +"PSL(3,2) x D8" gap> cf:=MTX.CompositionFactors(M2);; gap> ForAll(cf, MTX.IsAbsolutelyIrreducible); true @@ -138,8 +140,8 @@ false # gap> M2:=First(MTX.CompositionFactors(M), m -> m.dimension = 4);; -gap> IdGroup(MTX.ModuleAutomorphisms(M2)); -[ 48, 2 ] +gap> StructureDescription(MTX.ModuleAutomorphisms(M2)); +"C48" gap> MTX.IsIndecomposable(M2); true gap> MTX.IsAbsolutelyIrreducible(M2); diff --git a/tst/testinstall/opers/FittingSubgroup.tst b/tst/testinstall/opers/FittingSubgroup.tst index 172a085e1f..022d10290c 100644 --- a/tst/testinstall/opers/FittingSubgroup.tst +++ b/tst/testinstall/opers/FittingSubgroup.tst @@ -15,11 +15,12 @@ gap> G := CyclicGroup(IsPcGroup, 12);; gap> IsIdenticalObj(G, FittingSubgroup(G)); true -# +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> List(AllSmallGroups(60), g -> Size(FittingSubgroup(g))); [ 30, 30, 30, 60, 1, 15, 15, 15, 20, 30, 30, 30, 60 ] gap> ForAll(AllSmallGroups(60), g -> IsNormal(g, FittingSubgroup(g))); true +#@fi # gap> g := SL(2,5);; diff --git a/tst/testinstall/opers/FrattiniSubgroup.tst b/tst/testinstall/opers/FrattiniSubgroup.tst index 2646c8764c..5064529c1b 100644 --- a/tst/testinstall/opers/FrattiniSubgroup.tst +++ b/tst/testinstall/opers/FrattiniSubgroup.tst @@ -16,12 +16,12 @@ gap> HasIsAbelian(FrattiniSubgroup(G)); true gap> GeneratorsOfGroup(FrattiniSubgroup(G)); [ (x^-195*y^196)^6, (x^-1*y)^630, (x^-1*y)^840 ] -gap> G := DirectProduct(DihedralGroup(IsPcGroup,8), SmallGroup(27,4));; +gap> G := DirectProduct(DihedralGroup(8), ExtraspecialGroup(27,9));; gap> IsNilpotentGroup(G); true gap> F := FrattiniSubgroup(G);; -gap> IdGroup(F); -[ 6, 2 ] +gap> StructureDescription(F); +"C6" gap> HasIsNilpotentGroup(F); true @@ -43,11 +43,12 @@ Group([ ]) gap> AsSet( FrattiniSubgroup(CyclicGroup(IsPcGroup, 9)) ); [ of ..., f2, f2^2 ] -# +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> List(AllSmallGroups(60), g -> Size(FrattiniSubgroup(g))); [ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] gap> ForAll(AllSmallGroups(60), g -> IsNormal(g, FrattiniSubgroup(g))); true +#@fi # gap> g := SL(2,5);; diff --git a/tst/testinstall/opers/HallSubgroup.tst b/tst/testinstall/opers/HallSubgroup.tst index bf05ddecc7..7435808bbf 100644 --- a/tst/testinstall/opers/HallSubgroup.tst +++ b/tst/testinstall/opers/HallSubgroup.tst @@ -2,20 +2,25 @@ gap> START_TEST("HallSubgroup.tst"); gap> G := GL(3,4);; gap> HallSubgroup(G, [2,3]); fail + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> G := PSL(4,2);; gap> IdGroup(HallSubgroup(G, [2,3])); [ 576, 8654 ] gap> G := PSp(4,5);; gap> IdGroup(HallSubgroup(G,[2,3])); [ 576, 8277 ] +#@fi + +# gap> G := Group([ [ [ Z(2)^0, 0*Z(2), 0*Z(2) ], > [ 0*Z(2), Z(2)^0, 0*Z(2) ], > [ 0*Z(2), Z(2)^0, Z(2)^0 ] ], > [ [ 0*Z(2), Z(2)^0, 0*Z(2) ], > [ 0*Z(2), 0*Z(2), Z(2)^0 ], > [ Z(2)^0, 0*Z(2), 0*Z(2) ] ] ]);; -gap> List(HallSubgroup(G, [2,3]), IdGroup); -[ [ 24, 12 ], [ 24, 12 ] ] +gap> List(HallSubgroup(G, [2,3]), StructureDescription); +[ "S4", "S4" ] # gap> G:=PerfectGroup(IsFpGroup,60,1); diff --git a/tst/testinstall/opers/IsSolvableGroup.tst b/tst/testinstall/opers/IsSolvableGroup.tst index d06f79379f..f1e23afd9d 100644 --- a/tst/testinstall/opers/IsSolvableGroup.tst +++ b/tst/testinstall/opers/IsSolvableGroup.tst @@ -1,9 +1,11 @@ gap> START_TEST("IsSolvableGroup.tst"); +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> List(AllSmallGroups(120), IsSolvableGroup); [ true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true ] +#@fi gap> grps := [ > [ (1,2,3,4,5,6,7,8) ], [ (1,2,3,8)(4,5,6,7), (1,5)(2,6)(3,7)(4,8) ], > [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8) ], diff --git a/tst/testinstall/opers/LatticeByCyclicExtension.tst b/tst/testinstall/opers/LatticeByCyclicExtension.tst index 959f788b0c..779b6fd668 100644 --- a/tst/testinstall/opers/LatticeByCyclicExtension.tst +++ b/tst/testinstall/opers/LatticeByCyclicExtension.tst @@ -1,8 +1,13 @@ gap> START_TEST("LatticeByCyclicExtension.tst"); +# construct SmallGroup(500,1) +gap> H:=CyclicGroup(4);; +gap> N:=CyclicGroup(125);; +gap> A:=AutomorphismGroup(N);; +gap> alpha:=GroupHomomorphismByImages(H,A,[H.1],[A.1^50]);; +gap> G:=SemidirectProduct(H, alpha, N);; + # -gap> G:=SmallGroup(500,1); - gap> fun:=g->IsInt(4/Size(g));; gap> LatticeByCyclicExtension(G); , 12 classes, diff --git a/tst/testinstall/opers/MinimalNormalSubgroups.tst b/tst/testinstall/opers/MinimalNormalSubgroups.tst index f5a7ff3ce7..1983bf5b09 100644 --- a/tst/testinstall/opers/MinimalNormalSubgroups.tst +++ b/tst/testinstall/opers/MinimalNormalSubgroups.tst @@ -7,42 +7,49 @@ gap> G := Group(());; NormalSubgroups(G);; MinimalNormalSubgroups(G); gap> D := DihedralGroup(8);; gap> MinimalNormalSubgroups(D) = [ Center(D) ]; true -gap> List(MinimalNormalSubgroups(D), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(D), Size); +[ 2 ] gap> D := DihedralGroup(IsFpGroup, 8);; gap> MinimalNormalSubgroups(D) = [ Center(D) ]; true -gap> List(MinimalNormalSubgroups(D), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(D), Size); +[ 2 ] gap> D := Group((1,3),(1,2,3,4));; gap> MinimalNormalSubgroups(D) = [ Center(D) ]; true -gap> List(MinimalNormalSubgroups(D), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(D), Size); +[ 2 ] gap> DDD := DirectProduct(D, D, D);; -gap> List(MinimalNormalSubgroups(DDD), IdGroup); -[ [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(DDD), Size); +[ 2, 2, 2, 2, 2, 2, 2 ] gap> Q := QuaternionGroup(8);; gap> MinimalNormalSubgroups(Q) = [ Center(Q) ]; true -gap> List(MinimalNormalSubgroups(Q), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(Q), Size); +[ 2 ] gap> MinimalNormalSubgroups(SymmetricGroup(4)) = [ Group((1,2)(3,4),(1,3)(2,4)) ]; true -gap> List(MinimalNormalSubgroups(SymmetricGroup(5)), IdGroup); -[ [ 60, 5 ] ] -gap> List(MinimalNormalSubgroups(AlternatingGroup(5)), IdGroup); -[ [ 60, 5 ] ] +gap> MinimalNormalSubgroups(SymmetricGroup(5)) = [ AlternatingGroup(5) ]; +true +gap> MinimalNormalSubgroups(AlternatingGroup(5)) = [ AlternatingGroup(5) ]; +true + +# gap> G := Group((1,2),(3,4),(5,6),(7,8));; gap> IsElementaryAbelian(G); true gap> Size(MinimalNormalSubgroups(G)); 15 -gap> MinimalNormalSubgroups(PrimitiveGroup(8,3)) = [ Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]) ]; + +# +gap> G := Group((2,7,4,8,6,5,3), (2,3)(6,7), (1,2)(3,4)(5,6)(7,8));; # = PrimitiveGroup(8,3) +gap> MinimalNormalSubgroups(G) = [ Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]) ]; true gap> k := 5;; P := SylowSubgroup(SymmetricGroup(4*k), 2);; A := Group((4*k+1, 4*k+2, 4*k+3));; G := ClosureGroup(P, A);; IsNilpotentGroup(G);; gap> Set(MinimalNormalSubgroups(G)) = Set([ Group([ (1,2)(3,4)(5,6)(7,8)(9,10)(11,12)(13,14)(15,16) ]), Group([ (17,18)(19,20) ]), Group([ (1,2)(3,4)(5,6)(7,8)(9,10)(11,12)(13,14)(15,16)(17,18)(19,20) ]), Group([ (21,22,23) ]) ]); true + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> G := SmallGroup(24,12);; gap> SortedList(List(MinimalNormalSubgroups(G), IdGroup)); [ [ 4, 2 ] ] @@ -50,13 +57,12 @@ gap> A := DihedralGroup(16);; gap> B := SmallGroup(27, 3);; gap> C := SmallGroup(125, 4);; gap> D := DirectProduct(A, B, C, SmallGroup(1536, 2));; -gap> SortedList(List(MinimalNormalSubgroups(D), IdGroup)); -[ [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 3, 1 ], [ 3, 1 ], [ 3, 1 ], [ 3, 1 ], - [ 5, 1 ] ] +gap> SortedList(List(MinimalNormalSubgroups(D), Size)); +[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 5 ] +#@fi + +# gap> G := Group([ (4,8)(6,10), (4,6,10,8,12), (2,4,12)(6,10,8), (3,9)(4,6,10,8,12)(7,11), (3,5)(4,6,10,8,12)(9,11), (1,3,11,9,5)(4,6,10,8,12) ]);; gap> Set(MinimalNormalSubgroups(G)) = Set([ Group([ (6,12)(8,10), (2,10)(4,12), (2,12)(6,10) ]), Group([ (5,11)(7,9), (3,9)(7,11), (1,9,5,11,7) ]) ]); true @@ -69,6 +75,8 @@ gap> G := F/[x^2, y^2, x^(-1)*y^(-1)*x*y, z];; gap> IsFinite(G);; gap> Size(MinimalNormalSubgroups(G)); 3 + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> for G in AllSmallGroups(60) do NormalSubgroups(G);; Print(Collected(List(Set(MinimalNormalSubgroups(G)), IdGroup)), "\n"); od; [ [ [ 2, 1 ], 1 ], [ [ 3, 1 ], 1 ], [ [ 5, 1 ], 1 ] ] [ [ [ 2, 1 ], 1 ], [ [ 3, 1 ], 1 ], [ [ 5, 1 ], 1 ] ] @@ -105,6 +113,9 @@ gap> for G in AllSmallGroups(360) do if not IsSolvable(G) then NormalSubgroups(G [ [ 3, 1 ], [ 60, 5 ] ] [ [ 3, 1 ], [ 60, 5 ] ] [ [ 2, 1 ], [ 3, 1 ], [ 60, 5 ] ] +#@fi + +# gap> G := AbelianGroup([2, 3, 4, 5, 6, 7, 8, 9, 10]);; gap> Collected(List(Set(MinimalNormalSubgroups(G)), Size)); [ [ 2, 31 ], [ 3, 13 ], [ 5, 6 ], [ 7, 1 ] ] @@ -114,4 +125,6 @@ gap> Collected(List(Set(MinimalNormalSubgroups(G)), Size)); gap> G := ElementaryAbelianGroup(7^4);; gap> Collected(List(Set(MinimalNormalSubgroups(G)), Size)); [ [ 7, 400 ] ] + +# gap> STOP_TEST("Socle.tst"); diff --git a/tst/testinstall/opers/NormalHallSubgroups.tst b/tst/testinstall/opers/NormalHallSubgroups.tst index 2278d619dc..63dcf7af29 100644 --- a/tst/testinstall/opers/NormalHallSubgroups.tst +++ b/tst/testinstall/opers/NormalHallSubgroups.tst @@ -1,4 +1,5 @@ gap> START_TEST("NormalHallSubgroups.tst"); +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> for G in AllSmallGroups(60) do Print(List(NormalHallSubgroups(G), IdGroup), "\n"); od; [ [ 1, 1 ], [ 5, 1 ], [ 3, 1 ], [ 15, 1 ], [ 12, 1 ], [ 60, 1 ] ] [ [ 1, 1 ], [ 3, 1 ], [ 5, 1 ], [ 15, 1 ], [ 20, 1 ], [ 60, 2 ] ] @@ -40,11 +41,18 @@ gap> List(AllSmallGroups(168), G -> List(NormalHallSubgroups(G), Size)); [ 1, 8, 7, 56, 168 ], [ 1, 3, 7, 56, 21, 168 ], [ 1, 7, 3, 24, 21, 168 ], [ 1, 3, 7, 21, 168 ], [ 1, 8, 3, 24, 7, 56, 21, 168 ] ] gap> for G in AllSmallGroups(168) do primes := PrimeDivisors(Size(G)); l := []; for pi in IteratorOfCombinations(primes) do N := HallSubgroup(G, pi); if N<>fail and IsGroup(N) and IsNormal(G, N) then AddSet(l, N); fi; od; if l <> NormalHallSubgroups(G) then Print(IdGroup(G), "\n"); fi; od; +#@fi + +# +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> List(AllPrimitiveGroups(DegreeAction, 8), G -> List(NormalHallSubgroups(G), Size)); [ [ 1, 56, 8 ], [ 1, 168, 56, 8 ], [ 1, 1344 ], [ 1, 168 ], [ 1, 336 ], [ 1, 20160 ], [ 1, 40320 ] ] gap> List(NormalHallSubgroups(PrimitiveGroup(8,2)), Size); [ 1, 168, 56, 8 ] +#@fi + +# gap> grps := [ [ (1,2,3,4,5,6) ], [ (1,3,5)(2,4,6), (1,4)(2,3)(5,6) ], > [ (1,2,3,4,5,6), (1,4)(2,3)(5,6) ], [ (1,4)(2,5), (1,3,5)(2,4,6) ], > [ (2,4,6), (1,4)(2,5)(3,6) ], [ (3,6), (1,3,5)(2,4,6) ], diff --git a/tst/testinstall/opers/SimpleGroup.tst b/tst/testinstall/opers/SimpleGroup.tst index cd2940f33d..72494f41d4 100644 --- a/tst/testinstall/opers/SimpleGroup.tst +++ b/tst/testinstall/opers/SimpleGroup.tst @@ -31,6 +31,7 @@ M11 rec( name := "M(11)", series := "Spor", shortname := "M11" ) # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("J1"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); J_1 175560 @@ -39,10 +40,12 @@ gap> SimpleGroup("J_2"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2) J_2 604800 rec( name := "HJ = J(2) = F(5-)", series := "Spor", shortname := "J2" ) +#@fi gap> SimpleGroup("J5"); Error, illegal parameter for Janko groups # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("CO3"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); Co_3 495766656000 @@ -51,6 +54,7 @@ gap> SimpleGroup("CO(2)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last Co(2) 42305421312000 rec( name := "Co(2)", series := "Spor", shortname := "Co2" ) +#@fi gap> SimpleGroup("CO4"); Error, illegal parameter for Conway groups @@ -59,6 +63,7 @@ gap> SimpleGroup("Fi20"); Error, illegal parameter for Fischer groups # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("SuZ"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); Suz 448345497600 @@ -78,6 +83,7 @@ Sz(8) 29120 rec( name := "2B(2,8) = 2C(2,8) = Sz(8)", parameter := 8, series := "2B", shortname := "Sz(8)" ) +#@fi gap> SimpleGroup("Sz(9)"); Error, illegal parameter for Suzuki groups gap> SimpleGroup("Suz(16)"); @@ -105,6 +111,7 @@ gap> SimpleGroup("Ree(16)"); Error, illegal parameter for Ree groups # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("HE"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); He 4030387200 @@ -122,6 +129,7 @@ gap> SimpleGroup("T"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); 17971200 rec( name := "2F(4,2)' = Ree(2)' = Tits", parameter := 2, series := "2F", shortname := "2F4(2)'" ) +#@fi # # linear groups @@ -263,6 +271,7 @@ Error, Can't do yet # gap> SimpleGroup("G3(3)"); Error, G(n,q) needs n=2 +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("G2(2)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); PSU(3,3) 6048 @@ -280,15 +289,18 @@ gap> SimpleGroup("G2(5)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last G_2(5) 5859000000 rec( name := "G(2,5)", parameter := 5, series := "G", shortname := "G2(5)" ) +#@fi # gap> SimpleGroup("3D(3,4)"); Error, 3D(n,q) needs n=4 +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("3D(4,2)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); 3D(4, 2) 211341312 rec( name := "3D(4,2)", parameter := 2, series := "3D", shortname := "3D4(2)" ) +#@fi gap> g:=SimpleGroup("3D(4,169)"); 3D4(169) gap> Size(g); diff --git a/tst/testinstall/opers/Socle.tst b/tst/testinstall/opers/Socle.tst index af4b16c56c..13d482d33a 100644 --- a/tst/testinstall/opers/Socle.tst +++ b/tst/testinstall/opers/Socle.tst @@ -4,34 +4,34 @@ Group(()) gap> D := DihedralGroup(8);; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> D := DihedralGroup(IsFpGroup, 8);; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> D := DihedralGroup(IsPermGroup, 8);; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> D := Group((1,3),(1,2,3,4));; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> DDD := DirectProduct(D, D, D);; -gap> IdGroup(Socle(DDD)); -[ 8, 5 ] +gap> StructureDescription(Socle(DDD)); +"C2 x C2 x C2" gap> Socle(DDD) = ClosureSubgroup(TrivialSubgroup(DDD), Union(Set(MinimalNormalSubgroups(DDD), GeneratorsOfGroup))); true gap> Socle(DDD) = Center(DDD); @@ -39,22 +39,23 @@ true gap> Q := QuaternionGroup(8);; gap> Socle(Q) = ClosureSubgroup(TrivialSubgroup(Q), Union(Set(MinimalNormalSubgroups(Q), GeneratorsOfGroup))); true -gap> IdGroup(Socle(Q)); -[ 2, 1 ] +gap> Size(Socle(Q)); +2 gap> Socle(Q) = Center(Q); true gap> Socle(SymmetricGroup(4)) = Group((1,2)(3,4),(1,3)(2,4)); true -gap> IdGroup(Socle(SymmetricGroup(5))); -[ 60, 5 ] -gap> IdGroup(Socle(AlternatingGroup(5))); -[ 60, 5 ] +gap> AlternatingGroup(5) = Socle(SymmetricGroup(5)); +true +gap> AlternatingGroup(5) = Socle(AlternatingGroup(5)); +true gap> G := Group((1,2),(3,4),(5,6),(7,8));; gap> IsElementaryAbelian(G); true gap> Socle(G)=G; true -gap> Socle(PrimitiveGroup(8,3)) = Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]); +gap> G:=Group([ (2,7,4,8,6,5,3), (2,3)(6,7), (1,2)(3,4)(5,6)(7,8) ]);; # = PrimitiveGroup(8,3) +gap> Socle(G) = Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]); true gap> k := 5;; P := SylowSubgroup(SymmetricGroup(4*k), 2);; A := Group((4*k+1, 4*k+2, 4*k+3));; G := ClosureGroup(P, A);; gap> Socle(G) = Group([ (21,22,23), (1,2)(3,4)(5,6)(7,8)(9,10)(11,12)(13,14)(15,16), (17,18)(19,20) ]); @@ -62,17 +63,19 @@ true gap> G := Group([ (1,2,3,5,4), (1,3)(2,4)(6,7) ]);; gap> Socle(G) = Group((1,2,3),(3,4,5),(6,7)); true -gap> G := SmallGroup(24,12);; -gap> IdGroup(Socle(G)); -[ 4, 2 ] +gap> G := SymmetricGroup(IsPcGroup, 4);; +gap> StructureDescription(Socle(G)); +"C2 x C2" +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> A := DihedralGroup(16);; -gap> B := SmallGroup(27, 3);; -gap> C := SmallGroup(125, 4);; +gap> B := ExtraspecialGroup( 27, 3 );; +gap> C := ExtraspecialGroup( 125, 25 );; gap> D := DirectProduct(A, B, C, SmallGroup(1536, 2));; -gap> IdGroup(Socle(D)); -[ 1440, 5958 ] +gap> StructureDescription(Socle(D)); +"C30 x C6 x C2 x C2 x C2" gap> Socle(D) = Center(D); true +#@fi gap> Socle(FittingSubgroup(SymmetricGroup(4))) = Group([ (1,4)(2,3), (1,3)(2,4) ]); true gap> G := Group([ (4,8)(6,10), (4,6,10,8,12), (2,4,12)(6,10,8), (3,9)(4,6,10,8,12) diff --git a/tst/testinstall/opers/StructureDescription.tst b/tst/testinstall/opers/StructureDescription.tst index 204f6a4b91..ceb2bd0e7c 100644 --- a/tst/testinstall/opers/StructureDescription.tst +++ b/tst/testinstall/opers/StructureDescription.tst @@ -1,6 +1,7 @@ gap> START_TEST("StructureDescription.tst"); ## Examples from manual +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> l := AllSmallGroups(12);; gap> List(l, StructureDescription);; l; [ C3 : C4, C12, A4, D12, C6 x C2 ] @@ -42,9 +43,15 @@ gap> List(AllSmallGroups(60), G -> StructureDescription(G:recompute)); [ "C5 x (C3 : C4)", "C3 x (C5 : C4)", "C3 : (C5 : C4)", "C60", "A5", "C3 x (C5 : C4)", "C3 : (C5 : C4)", "S3 x D10", "C5 x A4", "C6 x D10", "C10 x S3", "D60", "C30 x C2" ] +#@fi + +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> List(AllPrimitiveGroups(DegreeAction, 8), StructureDescription); [ "(C2 x C2 x C2) : C7", "(C2 x C2 x C2) : (C7 : C3)", "(C2 x C2 x C2) : PSL(3,2)", "PSL(3,2)", "PSL(3,2) : C2", "A8", "S8" ] +#@fi + +# gap> StructureDescription(AbelianGroup([0,0,0,2,3,6]):short); "Z^3x6^2" gap> G := Group([ (4,8)(6,10), (4,6,10,8,12), (2,4,12)(6,10,8), (3,9)(4,6,10,8,12)(7,11), (3,5)(4,6,10,8,12)(9,11), (1,3,11,9,5)(4,6,10,8,12) ]);; @@ -71,6 +78,7 @@ gap> G := PerfectGroup(IsPermGroup,1344,1);; StructureDescription(G); "(C2 x C2 x C2) : PSL(3,2)" gap> G := PerfectGroup(IsPermGroup,1344,2);; StructureDescription(G); "(C2 x C2 x C2) . PSL(3,2)" +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> StructureDescription(SmallGroup(32,15):recompute); "C4 . D8 = C4 . (C4 x C2)" gap> List(AllSmallNonabelianSimpleGroups([1..1000000]), StructureDescription); @@ -84,6 +92,9 @@ gap> List(AllSmallNonabelianSimpleGroups([1..1000000]), StructureDescription); "PSL(2,89)", "PSL(3,5)", "M22", "PSL(2,97)", "PSL(2,101)", "PSL(2,103)", "HJ", "PSL(2,107)", "PSL(2,109)", "PSL(2,113)", "PSL(2,121)", "PSL(2,125)", "O(5,4)" ] +#@fi + +# gap> G := FactorGroup(Sp(6,3), Center(Sp(6,3)));; gap> StructureDescription(G); "PSp(6,3)" @@ -91,8 +102,13 @@ gap> StructureDescription(Omega(1,8,2)); "O+(8,2)" gap> StructureDescription(Omega(-1,8,2)); "O-(8,2)" + +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> List(AllPrimitiveGroups(DegreeAction, 819, Size, 211341312, IsSimple, true), StructureDescription); [ "3D(4,2)" ] +#@fi + +# gap> G := Ree(27);; gap> HasIsFinite(G) and IsFinite(G) and HasIsSimpleGroup(G) and IsSimple(G); true @@ -102,6 +118,8 @@ gap> StructureDescription(AbelianGroup([0,0,0,2,3,4,5,6,7,8,9,10])); "Z x Z x Z x C2520 x C60 x C6 x C2 x C2" gap> StructureDescription(AbelianGroup([0,0,0,2,3,4,5,6,7,8,9,10]):short); "Z^3x2520x60x6x2^2" + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> infolevel:=InfoLevel(InfoWarning);; SetInfoLevel(InfoWarning,2); gap> StructureDescription(SmallGroup(48,16):recompute,nice); #I Warning! Non-unique semidirect product: @@ -112,6 +130,9 @@ gap> StructureDescription(SmallGroup(64,17):recompute,nice); #I [ [ "C4 x C2", "C8" ], [ "C8 x C2", "C4" ] ] "(C4 x C2) : C8" gap> SetInfoLevel(InfoWarning,infolevel); +#@fi + +# gap> F := FreeGroup("r", "s");; r := F.1;; s := F.2;; gap> G := F/[s^2, r^3, s*r*s*r];; gap> StructureDescription(G); diff --git a/tst/testinstall/opers/SubdirectProducts.tst b/tst/testinstall/opers/SubdirectProducts.tst index b44c999c4c..98e23013fa 100644 --- a/tst/testinstall/opers/SubdirectProducts.tst +++ b/tst/testinstall/opers/SubdirectProducts.tst @@ -4,30 +4,43 @@ gap> H := SymmetricGroup(4);; gap> A := CyclicGroup(6);; # -gap> Set(SubdirectProducts(G, G), IdGroup); -[ [ 6, 1 ], [ 18, 4 ], [ 36, 10 ] ] -gap> Set(SubdirectProducts(H, H), IdGroup); -[ [ 24, 12 ], [ 96, 227 ], [ 288, 1026 ], [ 576, 8653 ] ] -gap> Set(SubdirectProducts(A, A), IdGroup); -[ [ 6, 2 ], [ 12, 5 ], [ 18, 5 ], [ 36, 14 ] ] +gap> SortedList(List(SubdirectProducts(G, G), StructureDescription)); +[ "(C3 x C3) : C2", "S3", "S3 x S3" ] +gap> SortedList(List(SubdirectProducts(A, A), StructureDescription)); +[ "C6", "C6", "C6 x C2", "C6 x C2", "C6 x C3", "C6 x C6" ] -# -gap> Set(SubdirectProducts(G, H), IdGroup); +# for the next couple tests, StructureDescription gives different outputs +# depending on which packages are loaded; e.g. for SubdirectProducts(H, H): +# [ "((C2 x C2 x C2 x C2) : C3) : C2", "(A4 x A4) : C2", "S4", "S4 x S4" ] +# [ "(C2 x C2) : ((C3 x A4) : C2)", "(C2 x C2) : S4", "S4", "S4 x S4" ] +# thus we use IdGroup if available, and else fall back to a weaker size test. +#@if IsPackageMarkedForLoading( "smallgrp", "" ) +gap> SortedList(List(SubdirectProducts(H, H), IdGroup)); +[ [ 24, 12 ], [ 96, 227 ], [ 288, 1026 ], [ 576, 8653 ] ] +gap> SortedList(List(SubdirectProducts(G, H), IdGroup)); [ [ 24, 12 ], [ 72, 43 ], [ 144, 183 ] ] -gap> Set(SubdirectProducts(H, G), IdGroup); +gap> SortedList(List(SubdirectProducts(H, G), IdGroup)); [ [ 24, 12 ], [ 72, 43 ], [ 144, 183 ] ] +#@else +gap> SortedList(List(SubdirectProducts(H, H), Size)); +[ 24, 96, 288, 576 ] +gap> SortedList(List(SubdirectProducts(G, H), Size)); +[ 24, 72, 144 ] +gap> SortedList(List(SubdirectProducts(H, G), Size)); +[ 24, 72, 144 ] +#@fi # -gap> Set(SubdirectProducts(G, A), IdGroup); -[ [ 18, 3 ], [ 36, 12 ] ] -gap> Set(SubdirectProducts(A, G), IdGroup); -[ [ 18, 3 ], [ 36, 12 ] ] +gap> SortedList(List(SubdirectProducts(G, A), StructureDescription)); +[ "C3 x S3", "C6 x S3" ] +gap> SortedList(List(SubdirectProducts(A, G), StructureDescription)); +[ "C3 x S3", "C6 x S3" ] # -gap> Set(SubdirectProducts(H, A), IdGroup); -[ [ 72, 42 ], [ 144, 188 ] ] -gap> Set(SubdirectProducts(A, H), IdGroup); -[ [ 72, 42 ], [ 144, 188 ] ] +gap> SortedList(List(SubdirectProducts(H, A), StructureDescription)); +[ "C3 x S4", "C6 x S4" ] +gap> SortedList(List(SubdirectProducts(A, H), StructureDescription)); +[ "C3 x S4", "C6 x S4" ] # gap> STOP_TEST("SubdirectProducts.tst"); From ca14e459321509c450ff0d6425c365264a7e5e30 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 11 May 2026 13:19:48 +0200 Subject: [PATCH 061/123] Miscellaneous fixes concerning vector and matrix objects (#6369) * add checks to `NewVector`, `NewMatrix` for the GF(2) and 8 bit repres. in order to catch `fail` results * add a `String` method for rings `Integers mod n` * fix the default `OneMutable` method for `IsMatrixObj` Test that the input is square, as for list-of-lists matrices. * minor fixes for `IsPlistVectorRep` - check the input list for `IsPlistRep` in `MakeIsPlistVectorRep`, let `NewVector` turn the input to `IsPlistRep` if necessary - forbid assignments into a `IsPlistVectorRep` vector beyond its length * fix `SolutionMatDestructive` Conceptually, the solution must be in the same representation as the given vector. (Let us see which other bugs will come to the surface now.) * fix `TestPositionNonZeroInRow` --- hpcgap/lib/vec8bit.gi | 14 +++++++++++--- hpcgap/lib/vecmat.gi | 11 +++++++++-- lib/matobj.gi | 9 ++++++++- lib/matobjplist.gi | 9 +++++++-- lib/matrix.gi | 3 +-- lib/vec8bit.gi | 14 +++++++++++--- lib/vecmat.gi | 11 +++++++++-- lib/zmodnz.gi | 6 ++++++ tst/testinstall/MatrixObj/ListOp.tst | 3 +++ tst/testinstall/MatrixObj/matobjplist.tst | 2 ++ tst/testinstall/MatrixObj/testmatobj.g | 5 +++-- 11 files changed, 70 insertions(+), 17 deletions(-) diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index 31af64cad8..00d34ac9d1 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -1133,10 +1133,16 @@ InstallMethod( BaseField, "for a compressed 8bit vector", InstallTagBasedMethod( NewVector, Is8BitVectorRep, function( filter, f, l ) - if ValueOption( "check" ) <> false and not Size(f) in [3..256] then + local check, res; + check:= ValueOption( "check" ) <> false; + if check and not Size(f) in [3..256] then Error("Is8BitVectorRep only supports base fields with 3 to 256 elements"); fi; - return CopyToVectorRep(l,Size(f)); + res:= CopyToVectorRep( l, Size( f ) ); + if check and res = fail then + Error( "cannot copy to 'Is8BitVectorRep'" ); + fi; + return res; end ); # This is faster than the default method. @@ -1170,7 +1176,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,Size(f)); + if ConvertToMatrixRep( m, Size( f ) ) = fail then + Error( "cannot convert to 'Is8BitMatrixRep'" ); + fi; return m; end ); diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index e582db8b0f..8291757030 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -2555,8 +2555,13 @@ InstallMethod( BaseField, "for a compressed gf2 vector", InstallTagBasedMethod( NewVector, IsGF2VectorRep, function( filter, f, l ) + local res; if Size(f) <> 2 then Error("IsGF2VectorRep only supported over GF(2)"); fi; - return CopyToVectorRep(l,2); + res:= CopyToVectorRep( l, 2 ); + if res = fail then + Error( "cannot copy to 'IsGF2VectorRep'" ); + fi; + return res; end ); InstallTagBasedMethod( NewZeroVector, @@ -2583,7 +2588,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,2); + if ConvertToMatrixRep( m, 2 ) = fail then + Error( "cannot convert to 'IsGF2MatrixRep'" ); + fi; return m; end ); diff --git a/lib/matobj.gi b/lib/matobj.gi index 58e4184e6d..83807f6fb5 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1513,7 +1513,14 @@ InstallMethod( ZeroSameMutability, InstallMethod( OneMutable, [ IsMatrixObj ], - M -> IdentityMatrix( NumberRows( M ), M ) ); + function( M ) + local nrows; + nrows:= NrRows( M ); + if nrows <> NrCols( M ) then + Error( " must be square (not ", nrows, " by ", NrCols( M ), ")" ); + fi; + return IdentityMatrix( nrows, M ); + end ); InstallMethod( OneSameMutability, [ IsMatrixOrMatrixObj ], diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index c9af75c590..2ec8c4f723 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -88,6 +88,8 @@ BindGlobal( "MakeIsPlistVectorRep", if check and ValueOption( "check" ) <> false then if not IsSubset( basedomain, list ) then Error( "the elements in must lie in " ); + elif not IsPlistRep( list ) then + Error( " must be in 'IsPlistRep'" ); fi; fi; @@ -177,7 +179,7 @@ BindGlobal( "MakeIsPlistMatrixRep", InstallTagBasedMethod( NewVector, IsPlistVectorRep, function( filter, basedomain, list ) - return MakeIsPlistVectorRep(basedomain, ShallowCopy(list), true); + return MakeIsPlistVectorRep(basedomain, PlainListCopy( list ), true); end ); InstallTagBasedMethod( NewZeroVector, @@ -354,6 +356,9 @@ InstallMethod( \[\], InstallMethod( \[\]\:\=, [ "IsPlistVectorRep", "IsPosInt", "IsObject" ], function( v, p, ob ) + if ValueOption( "check" ) <> false and Length( v![ELSPOS] ) < p then + Error( "

is out of bounds" ); + fi; v![ELSPOS][p] := ob; end ); @@ -710,7 +715,7 @@ InstallMethod( Matrix, else l := []; fi; - # The result shall be mutable iff 'rows' is mutable. + # The result shall be mutable iff 'list' is mutable. if not IsMutable( list ) then MakeImmutable( l ); fi; diff --git a/lib/matrix.gi b/lib/matrix.gi index b5780f80f4..8deda4ee65 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -3040,8 +3040,7 @@ InstallOtherMethod( SolutionMatDestructive, local i,ncols,sem, vno, z,x, sol; ncols := Length(vec); z := ZeroOfBaseDomain(mat); - sol := ListWithIdenticalEntries(NrRows(mat),z); - ConvertToVectorRepNC(sol); + sol:= ZeroVector( NrRows( mat ), vec ); if ncols <> NrCols(mat) then Error("SolutionMat: matrix and vector incompatible"); fi; diff --git a/lib/vec8bit.gi b/lib/vec8bit.gi index 1602a4ca36..5c491f4320 100644 --- a/lib/vec8bit.gi +++ b/lib/vec8bit.gi @@ -1088,10 +1088,16 @@ InstallMethod( BaseField, "for a compressed 8bit vector", InstallTagBasedMethod( NewVector, Is8BitVectorRep, function( filter, f, l ) - if ValueOption( "check" ) <> false and not Size(f) in [3..256] then + local check, res; + check:= ValueOption( "check" ) <> false; + if check and not Size(f) in [3..256] then Error("Is8BitVectorRep only supports base fields with 3 to 256 elements"); fi; - return CopyToVectorRep(l,Size(f)); + res:= CopyToVectorRep( l, Size( f ) ); + if check and res = fail then + Error( "cannot copy to 'Is8BitVectorRep'" ); + fi; + return res; end ); # This is faster than the default method. @@ -1125,7 +1131,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,Size(f)); + if ConvertToMatrixRep( m, Size( f ) ) = fail then + Error( "cannot convert to 'Is8BitMatrixRep'" ); + fi; return m; end ); diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 8e319696b3..1c83a13c01 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -2553,8 +2553,13 @@ InstallMethod( BaseField, "for a compressed gf2 vector", InstallTagBasedMethod( NewVector, IsGF2VectorRep, function( filter, f, l ) + local res; if Size(f) <> 2 then Error("IsGF2VectorRep only supported over GF(2)"); fi; - return CopyToVectorRep(l,2); + res:= CopyToVectorRep( l, 2 ); + if res = fail then + Error( "cannot copy to 'IsGF2VectorRep'" ); + fi; + return res; end ); InstallTagBasedMethod( NewZeroVector, @@ -2581,7 +2586,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,2); + if ConvertToMatrixRep( m, 2 ) = fail then + Error( "cannot convert to 'IsGF2MatrixRep'" ); + fi; return m; end ); diff --git a/lib/zmodnz.gi b/lib/zmodnz.gi index 980652b8f1..2a352eccf0 100644 --- a/lib/zmodnz.gi +++ b/lib/zmodnz.gi @@ -869,6 +869,7 @@ InstallMethod( TriangulizeMat, ## #M ViewObj( ) . . . . . . . . . . . . . . . . method for full ring Z/nZ #M PrintObj( ) . . . . . . . . . . . . . . . . method for full ring Z/nZ +#M String( ) . . . . . . . . . . . . . . . . . method for full ring Z/nZ ## InstallMethod( ViewObj, "for full ring Z/nZ", @@ -884,6 +885,11 @@ InstallMethod( PrintObj, Print( "(Integers mod ", Size( obj ), ")" ); end ); +InstallMethod( String, + "for full ring Z/nZ", + [ IsZmodnZObjNonprimeCollection and IsWholeFamily ], SUM_FLAGS, + obj -> Concatenation( "(Integers mod ", String( Size( obj ) ), ")" ) ); + ############################################################################# ## diff --git a/tst/testinstall/MatrixObj/ListOp.tst b/tst/testinstall/MatrixObj/ListOp.tst index 0c394900f8..e8a6580c23 100644 --- a/tst/testinstall/MatrixObj/ListOp.tst +++ b/tst/testinstall/MatrixObj/ListOp.tst @@ -23,4 +23,7 @@ gap> List( v ); [ ] gap> List( v, DegreeFFE ); [ ] +gap> v1:= Vector( IsPlistVectorRep, Rationals, [] );; +gap> v1[1]:= 0; +Error,

is out of bounds gap> STOP_TEST("ListOp.tst"); diff --git a/tst/testinstall/MatrixObj/matobjplist.tst b/tst/testinstall/MatrixObj/matobjplist.tst index f1099217d9..584ec3da07 100644 --- a/tst/testinstall/MatrixObj/matobjplist.tst +++ b/tst/testinstall/MatrixObj/matobjplist.tst @@ -3,6 +3,8 @@ gap> START_TEST( "matobjplist.tst" ); # gap> e:= MakeIsPlistVectorRep( Integers, [], true );; +gap> MakeIsPlistVectorRep( Integers, [ 1 .. 4 ], true );; +Error, must be in 'IsPlistRep' gap> v:= MakeIsPlistVectorRep( Integers, [ 1 ], true );; gap> MakeIsPlistVectorRep( Integers, [ 1/2 ], true );; Error, the elements in must lie in diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index bca02e4c1c..1f5a21ebc2 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -257,8 +257,9 @@ end; TestPositionNonZeroInRow := function(mat) local ncols; - # Make a matrix with specific patter of the same kind as mat - mat := Matrix([ [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 1, 0 ] ], mat); + # Make a matrix with specific pattern of the same kind as mat + mat := Matrix([ [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 1, 0 ] ] + * One( BaseDomain( mat ) ), mat); ncols := NrCols(mat); if PositionNonZeroInRow(mat, 1) <> 2 then From 8b171580f7be265e091b064ceb4dc1cfa7bdcf0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 11 May 2026 18:12:21 +0200 Subject: [PATCH 062/123] Increase kernel major version (#6390) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6d1531a3ca..1c313ffb8a 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ dnl 2. Otherwise (i.e., if no interfaces have been removed or changed), dnl if any interfaces have been added since the last public release, then dnl increment minor. dnl -m4_define([kernel_major_version], [10]) +m4_define([kernel_major_version], [11]) m4_define([kernel_minor_version], [0]) m4_define([GAP_DEFINE], [GAP_DEFINES="$GAP_DEFINES -D$1"]) From e835aa98f9fd8c985e5cbdba1d326765338f5199 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 May 2026 18:55:53 +0200 Subject: [PATCH 063/123] CI: don't rely on primary GNU file server (#6388) Use a mirror is more resilient and often faster, as one close to you is selected. --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 997d172106..36867a212c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -94,7 +94,7 @@ jobs: - name: "Install autoconf 2.72" # for compatibility with GCC 14 & clang versions run: | - wget https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.xz + wget https://ftpmirror.gnu.org/gnu/autoconf/autoconf-2.72.tar.xz tar xvf autoconf-2.72.tar.xz cd autoconf-2.72 ./configure From 794e4c7ef0103e65e351822097737153e0d52113 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 12 May 2026 00:36:05 +0200 Subject: [PATCH 064/123] Avoid IdGroup in IsGL and IsPSL (#6391) In each case, the new code is in fact slightly faster, unless of course IdGroup already happens to be set for the input group. --- lib/grpnames.gi | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/grpnames.gi b/lib/grpnames.gi index 6accd41db1..8220d79e88 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1490,10 +1490,13 @@ InstallMethod( IsPSL, if Size(DerivedSubgroup(G)) <> 4 then return false; fi; SetParametersOfGroupViewedAsPSL(G,npe); return true; - # PSL(3, 4) / PSL(4, 2) + # PSL(3, 4) / PSL(4, 2) \cong A_8 elif npes = [ [ 4, 2, 1 ], [ 3, 2, 2 ] ] then - if IdGroup(SylowSubgroup(G,2)) = [64,138] then npe := npes[1]; - elif IdGroup(SylowSubgroup(G,2)) = [64,242] then npe := npes[2]; fi; + if IsAlternatingGroup(G) then + npe := npes[1]; + else + npe := npes[2]; + fi; SetParametersOfGroupViewedAsPSL(G,npe); return true; # other cases @@ -1650,7 +1653,21 @@ InstallMethod( IsGL, # GL(2, 3) elif npes = [2, 3, 1] then - if IdGroup(G) <> [48,29] then return false; fi; + # necessary condition: must have derived subgroup of index 2 (i.e., SL(2,3)) + if AbelianInvariants(G) <> [2] then return false; fi; + + # there are two groups order 48 with derived subgroup of index 2: + # - SmallGroup(48,28) is C2 . S4 = SL(2,3) . C2 + # - SmallGroup(48,29) is GL(2,3) + # These two groups are quite similar: they have + # - isomorphic centers (C2), + # - isomorphic derived subgroups (SL(2,3)), + # - same number of conjugacy classes (8), + # - same conjugacy class sizes ([ 1, 12, 8, 6, 1, 6, 8, 6 ]) + # One difference is that the conjugacy class of size 12 consists of + # elements of order 4 in one case, and 2 in the other; this is also + # how e.g. IdGroup distinguishes them + if Number(G, g -> Order(g) = 2) < 13 then return false; fi; SetParametersOfGroupViewedAsGL(G,npes); return true; # other cases, in which contained PSL is simple From 813c1853d62debe8e881d70b89bb0a49ec50144b Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Thu, 14 May 2026 00:25:36 +0200 Subject: [PATCH 065/123] fix `ConvertToMatrixRep`, fix some `Matrix` calls (#6396) * fix some `Matrix` calls * be careful when calling `BaseDomain` For a matrix or matrix object, it is safe to call `BaseDomain` if `HasBaseDomain` is set. For matrices in `Is8BitMatrixRep`, it may happen that `BaseDomain` for the matrix and some of its rows differ. Thus try to avoid computing `BaseDomain`. * make `ConvertToMatrixRep` work in more situations Up to now, we ran into an error if some rows of the matrix were already compressed w.r.t. an unwanted `q`. --- lib/mat8bit.gi | 33 ++++++++++++++++++-------- lib/oprt.gi | 47 +++++++++++++++++++++++++++---------- tst/testinstall/mat8bit.tst | 25 +++++++++++++++++++- 3 files changed, 82 insertions(+), 23 deletions(-) diff --git a/lib/mat8bit.gi b/lib/mat8bit.gi index 34ad8180a9..591b28951f 100644 --- a/lib/mat8bit.gi +++ b/lib/mat8bit.gi @@ -269,7 +269,7 @@ InstallMethod( \-, "for two 8 bit matrices in same characteristic", InstallGlobalFunction(ConvertToMatrixRep, function( arg ) - local m,qs, v, q, givenq, q1, LeastCommonPower, lens; + local m,qs, v, q, givenq, q1, LeastCommonPower, lens, d; LeastCommonPower := function(qs) local p, d, x, i; @@ -389,19 +389,32 @@ InstallGlobalFunction(ConvertToMatrixRep, fi; if givenq and q1 <> q then - Error("ConvertToMatrixRep( , ): not all entries of written over "); - fi; - - # - # Now try and rewrite all the rows over this field - # this may fail if some rows are locked over a smaller field - # + # It may be possible to write the matrix over the field + # with 'q1' elements. + # We are not allowed to call 'ConvertToVectorRep( v, q1 )' + # in order to *test* whether the row 'v' lives over the desired + # field, but we may call it once we *know* that this is the case. + d:= Length( Factors( q1 ) ); + for v in m do + if d mod DegreeFFE( v ) <> 0 then + Error("ConvertToMatrixRep( , ): not all entries of written over "); + elif q1 <> ConvertToVectorRep( v, q1 ) then + return fail; + fi; + od; + q:= q1; + else + # + # Now try and rewrite all the rows over this field + # this may fail if some rows are locked over a smaller field + # - for v in m do + for v in m do if q <> ConvertToVectorRepNC(v,q) then return fail; fi; - od; + od; + fi; fi; if q <= 256 then diff --git a/lib/oprt.gi b/lib/oprt.gi index 9710eac495..a7b758b73f 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -3379,7 +3379,7 @@ end ); InstallMethod( PreImagesRepresentative,"IsLinearActionHomomorphism", FamRangeEqFamElm, [ IsLinearActionHomomorphism, IsPerm ], 0, function( hom, elm ) - local V, G, Grep, xset,lab,f; + local V, G, Grep, filt, R, xset,lab,f; # is this method applicable? Test whether the domain contains a vector # space basis (respectively just get this basis). @@ -3394,19 +3394,26 @@ function( hom, elm ) V := HomeEnumerator(xset); G:= Source( hom ); Grep:= Representative( G ); + filt:= ConstructingFilter( Grep ); f:=DefaultFieldOfMatrixGroup(G); - + if HasBaseDomain( Grep ) then + R:= BaseDomain( Grep ); + else + R:= f; + fi; +#TODO: Here `BaseDomain( G )` should be used, once it is implemented. if not IsBound(hom!.linActBasisPositions) then hom!.linActBasisPositions:=List(lab,i->PositionCanonical(V,i)); fi; if not IsBound(hom!.linActInverse) then - lab:=ImmutableMatrix(f, Matrix( lab, Grep )); + # Create a matrix whose `BaseDomain` is the same as that of the group. + lab:=ImmutableMatrix(f, Matrix( filt, R, lab )); hom!.linActInverse:=Inverse(lab); fi; elm:=OnTuples(hom!.linActBasisPositions,elm); # image points elm:=V{elm}; # the corresponding vectors - elm:=ImmutableMatrix(f, Matrix( elm, Grep )); + elm:=ImmutableMatrix(f, Matrix( filt, R, elm )); return hom!.linActInverse*elm; end ); @@ -3437,7 +3444,7 @@ end ); InstallMethod( PreImagesRepresentative,"IsProjectiveActionHomomorphism", FamRangeEqFamElm, [ IsProjectiveActionHomomorphism, IsPerm ], 0, function( hom, elm ) - local V, G, Grep, mat, xset,lab,dim,sol,i; + local V, G, Grep, filt, R, mat, xset,lab,dim,sol,i; # is this method applicable? Test whether field # finite, that the domain contains a vector @@ -3456,12 +3463,18 @@ function( hom, elm ) V := HomeEnumerator(xset); G:= Source( hom ); Grep:= Representative( G ); + filt:= ConstructingFilter( Grep ); + if HasBaseDomain( Grep ) then + R:= BaseDomain( Grep ); + else + R:= DefaultFieldOfMatrixGroup(G); + fi; dim:=DimensionOfMatrixGroup(G); elm:=OnTuples(hom!.projActBasisPositions,elm); # image points elm:=V{elm}; # the corresponding vectors - mat:= Matrix( List( elm{ [ 1 .. dim ] }, ShallowCopy ), Grep ); + mat:= Matrix( filt, R, List( elm{ [ 1 .. dim ] }, ShallowCopy ) ); sol:=SolutionMat(mat,elm[dim+1]); for i in [1..dim] do MultMatrixRow( mat, i, sol[i] ); @@ -3487,7 +3500,7 @@ end); InstallMethod(LinearActionBasis,"find basis in domain",true, [IsLinearActionHomomorphism],0, function(hom) -local xset, base, M, D, b, t, i, r, pos, v; +local xset, base, M, filt, R, D, b, t, i, r, pos, v; xset:=UnderlyingExternalSet(hom); if Size(xset)=0 then return fail; @@ -3497,8 +3510,13 @@ local xset, base, M, D, b, t, i, r, pos, v; base:= BaseOfGroup(xset); if IsMatrix( base ) then M:= base; - elif ForAll( base, IsVectorObj ) then - M:= Matrix( BaseOfGroup( xset ), One( ActingDomain( xset ) ) ); + elif ForAll( base, IsVectorObj and HasBaseDomain ) then + # All entries of 'base' have the same 'BaseDomain'. + filt:= ConstructingFilter( Representative( ActingDomain( xset ) ) ); + R:= BaseDomain( base[1] ); + M:= Matrix( filt, R, base ); + else + Error( "unsupported 'BaseOfGroup' value for " ); fi; if RankMat( M ) = NrCols( M ) then # this implies injectivity @@ -3561,7 +3579,7 @@ end); InstallOtherMethod(LinearActionBasis,"projective with extra vector",true, [IsProjectiveActionHomomorphism],0, function(hom) -local xset,G,Grep,D,b,t,i,r,binv,pos,dets,roots,dim,f,v; +local xset,G,Grep,filt,R,D,b,t,i,r,binv,pos,dets,roots,dim,f,v; xset:=UnderlyingExternalSet(hom); if Size(xset)=0 then return fail; @@ -3570,9 +3588,14 @@ local xset,G,Grep,D,b,t,i,r,binv,pos,dets,roots,dim,f,v; # will the determinants suffice to get suitable scalars? G:= Source(hom); Grep:= Representative( G ); + filt:= ConstructingFilter( Grep ); dim:=DimensionOfMatrixGroup(G); f:=DefaultFieldOfMatrixGroup(G); - + if HasBaseDomain( Grep ) then + R:= BaseDomain( Grep ); + else + R:= f; + fi; roots:=Set(RootsOfUPol(f,X(f)^dim-1)); D:=List(GeneratorsOfGroup(G),DeterminantMat); @@ -3621,7 +3644,7 @@ local xset,G,Grep,D,b,t,i,r,binv,pos,dets,roots,dim,f,v; fi; # try to find a vector that has nonzero coefficients for all b - binv:= Inverse( ImmutableMatrix( f, Matrix( b, Grep ) ) ); + binv:= Inverse( ImmutableMatrix( f, Matrix( filt, R, b ) ) ); while i<=Length(D) do if ForAll( Unpack( D[i] * binv ), x -> not IsZero(x) ) then #TODO: get rid of 'Unpack'? diff --git a/tst/testinstall/mat8bit.tst b/tst/testinstall/mat8bit.tst index 18e97658d4..db1316d4bd 100644 --- a/tst/testinstall/mat8bit.tst +++ b/tst/testinstall/mat8bit.tst @@ -564,9 +564,32 @@ gap> m := [m[1], mm[1], m[2], mm[2],[]]; , , [ ] ] gap> ConvertToMatrixRep(m); fail +gap> m:= [ [ Z(3) ] ];; +gap> ConvertToVectorRep( m[1], 9 ) = 9; +true +gap> ConvertToMatrixRep( m, 3 ) = 3; +true +gap> m:= [ [ Z(3) ] ];; +gap> ConvertToVectorRep( m[1], 27 ) = 27; +true +gap> ConvertToMatrixRep( m, 9 ) = 9; +true +gap> m:= [ [ Z(3) ] ];; +gap> ConvertToVectorRep( m[1], 9 ) = 9; +true +gap> ConvertToMatrixRep( m, 27 ) = 27; +true +gap> m:= [ [ Z(9) ] ];; +gap> ConvertToVectorRep( m[1], 3 ) = 9; +Error, ConvertToVectorRepNC: Vector cannot be written over GF(3) +gap> ConvertToVectorRep( m[1], 9 ); +9 +gap> ConvertToMatrixRep( m, 3 ); +Error, ConvertToMatrixRep( , ): not all entries of written over\ + # ConvertToMatrixRepNC -gap> ConvertToMatrixRepNC([], 3); +gap> ConvertToMatrixRepNC([], 3); # What is this test supposed to show? 3 # DefaultFieldOfMatrix From d930595827c6e0dbff53bbf57c4ba0a383b22fb9 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 17 May 2026 00:19:00 +0200 Subject: [PATCH 066/123] Store dense matrices as plain row lists for faster entry access. (#6322) Some microbenchmarks show the benefit, namely that performance for basic arithmetic in many cases matches that of list-of-list matrices, while IsPlistMatrixRep is basically always slower, sometimes quite substantially so. Setup: R:=GF(257);;n:=20;; M1:=IdentityMat(n,R);; M2:=IdentityMatrix(IsPlistMatrixRep,R,n);; M3:=IdentityMatrix(IsGenericMatrixRep,R,n);; Addition: gap> for i in [1..1000] do x:=M1+M1; od; time; 7 gap> for i in [1..1000] do x:=M2+M2; od; time; 14 gap> for i in [1..1000] do x:=M3+M3; od; time; 5 gap> for i in [1..1000] do x:=M1*M1; od; time; 57 gap> for i in [1..1000] do x:=M2*M2; od; time; 1099 gap> for i in [1..1000] do x:=M3*M3; od; time; 47 Inversion: gap> for i in [1..1000] do x:=Inverse(M1); od; time; 4 gap> for i in [1..1000] do x:=Inverse(M2); od; time; 66 gap> for i in [1..1000] do x:=Inverse(M3); od; time; 4 Powers: gap> for i in [1..1000] do x:=M1^5; od; time; 162 gap> for i in [1..1000] do x:=M2^5; od; time; 3371 gap> for i in [1..1000] do x:=M3^5; od; time; 142 Element access (plist-of-plist benefits from a direct kernel implementation; we could add that for both IsPlistMatrixRep and IsGenericMatrixRep, if so desired) gap> for i in [1..1000000] do x:=M1[1,1]; od; time; 26 gap> for i in [1..1000000] do x:=M2[1,1]; od; time; 62 gap> for i in [1..1000000] do x:=M3[1,1]; od; time; 50 Example of a typical matrix property: IsDiagonalMat gap> for i in [1..10000] do x:=IsDiagonalMat(M1); od; time; 103 gap> for i in [1..10000] do x:=IsDiagonalMat(M2); od; time; 142 gap> for i in [1..10000] do x:=IsDiagonalMat(M3); od; time; 115 IsOne (surprisingly is slower for IsGenericMatrixRep, I do not yet know why) gap> for i in [1..10000] do x:=IsOne(M1); od; time; 115 gap> for i in [1..10000] do x:=IsOne(M2); od; time; 111 gap> for i in [1..10000] do x:=IsOne(M3); od; time; 132 PositionNonZeroInRow is among the core functionality for row reduction: gap> for i in [1..1000000] do x:=PositionNonZeroInRow(M1,1); od; time; 234 gap> for i in [1..1000000] do x:=PositionNonZeroInRow(M2,1); od; time; 370 gap> for i in [1..1000000] do x:=PositionNonZeroInRow(M3,1); od; time; 273 AI-assisted with Codex for writing large parts of the code and documentation. Human input was used to steer everything, request changes, etc., and I also made a bunch of small changes manually. Co-authored-by: Codex --- benchmark/matobj/bench-matelm-access.g | 18 +- benchmark/matobj/bench-matobj-creation.g | 13 +- doc/ref/makedocreldata.g | 1 + doc/ref/matobj.xml | 1 + lib/matobjgeneric.gd | 55 ++ lib/matobjgeneric.gi | 480 ++++++++++++++++++ lib/matobjplist.gd | 11 +- lib/matobjplist.gi | 114 ++--- lib/read3.g | 1 + lib/read5.g | 1 + tst/testinstall/MatrixObj/CompanionMatrix.tst | 16 + .../MatrixObj/ElementaryMatrices.tst | 8 + tst/testinstall/MatrixObj/IdentityMatrix.tst | 18 + tst/testinstall/MatrixObj/Matrix.tst | 11 + tst/testinstall/MatrixObj/ZeroMatrix.tst | 18 + tst/testinstall/MatrixObj/matobjgeneric.tst | 465 +++++++++++++++++ tst/testinstall/MatrixObj/matobjplist.tst | 74 ++- tst/testinstall/MatrixObj/testmatobj.g | 2 + tst/testspecial/method-not-found-where.g | 2 +- tst/testspecial/method-not-found-where.g.out | 12 +- 20 files changed, 1228 insertions(+), 93 deletions(-) create mode 100644 lib/matobjgeneric.gd create mode 100644 lib/matobjgeneric.gi create mode 100644 tst/testinstall/MatrixObj/matobjgeneric.tst diff --git a/benchmark/matobj/bench-matelm-access.g b/benchmark/matobj/bench-matelm-access.g index 889ba71801..f58d365830 100644 --- a/benchmark/matobj/bench-matelm-access.g +++ b/benchmark/matobj/bench-matelm-access.g @@ -136,17 +136,23 @@ RunMatTest := function(desc, m) TestWritingMatrix(m); end; -m:=IdentityMat(10);; -RunMatTest("integer matrix", m); +m:=IdentityMat(10,GF(257));; # plain list of plain lists +RunMatTest("GF(257) plist-of-plist matrix", m); -m:=IdentityMat(10,GF(2));; +m:=IdentityMatrix(GF(257), 10); # IsPlistMatrixRep +RunMatTest("GF(257) IsPlistMatrixRep", m); + +m:=IdentityMatrix(GF(257), 10); # IsGenericMatrixRep +RunMatTest("GF(257) IsGenericMatrixRep", m); + +m:=IdentityMat(10,GF(2));; # plain list of IsGF2VectorRep RunMatTest("GF(2) rowlist", m); -m:=IdentityMat(10,GF(2));; ConvertToMatrixRep(m);; +m:=IdentityMatrix(GF(2), 10); # IsGF2MatrixRep RunMatTest("GF(2) compressed matrix", m); -m:=IdentityMat(10,GF(7));; +m:=IdentityMat(10,GF(7));; # plain list of Is8BitVectorRep RunMatTest("GF(7) rowlist", m); -m:=IdentityMat(10,GF(7));; ConvertToMatrixRep(m);; +m:=IdentityMatrix(GF(7), 10); # Is8BitMatrixRep RunMatTest("GF(7) compressed matrix", m); diff --git a/benchmark/matobj/bench-matobj-creation.g b/benchmark/matobj/bench-matobj-creation.g index d74e5f040e..fdf568d716 100644 --- a/benchmark/matobj/bench-matobj-creation.g +++ b/benchmark/matobj/bench-matobj-creation.g @@ -91,18 +91,23 @@ RunMatTest := function(desc, ring) TestCreatingMatrix(ring); end; -RunMatTest("GF(2)", GF(2)); -RunMatTest("Rationals", Rationals); - RunMatObjTest := function(desc, filter, ring) Print("\n"); PrintBoxed(Concatenation("Testing ", desc)); TestCreatingMatrixObj(filter, ring); end; -RunMatObjTest("GF(2) IsPlistMatrixRep", IsPlistMatrixRep, GF(2)); +RunMatTest("GF(257)", GF(257)); +RunMatObjTest("GF(257) IsPlistMatrixRep", IsPlistMatrixRep, GF(257)); +RunMatObjTest("GF(257) IsGenericMatrixRep", IsGenericMatrixRep, GF(257)); + +RunMatTest("Integers", Integers); RunMatObjTest("integer IsPlistMatrixRep", IsPlistMatrixRep, Integers); +RunMatObjTest("integer IsGenericMatrixRep", IsGenericMatrixRep, Integers); + +RunMatTest("Rationals", Rationals); RunMatObjTest("rational IsPlistMatrixRep", IsPlistMatrixRep, Rationals); +RunMatObjTest("rational IsGenericMatrixRep", IsGenericMatrixRep, Rationals); # TODO: other reps # TODO: other compare with creating plist-of-plist diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g index f2f1697bed..22993e3497 100644 --- a/doc/ref/makedocreldata.g +++ b/doc/ref/makedocreldata.g @@ -119,6 +119,7 @@ GAPInfo.ManualDataRef:= rec( "../../lib/matobj2.gd", "../../lib/matobjnz.gd", "../../lib/matobjplist.gd", + "../../lib/matobjgeneric.gd", "../../lib/matrix.gd", "../../lib/meataxe.gi", "../../lib/memory.gd", diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 27fdfc1310..d07e883708 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -431,6 +431,7 @@ described in this chapter is supported. <#Include Label="IsGF2MatrixRep"> <#Include Label="Is8BitMatrixRep"> <#Include Label="IsPlistMatrixRep"> +<#Include Label="IsGenericMatrixRep"> <#Include Label="IsZmodnZMatrixRep"> diff --git a/lib/matobjgeneric.gd b/lib/matobjgeneric.gd new file mode 100644 index 0000000000..d82837e91e --- /dev/null +++ b/lib/matobjgeneric.gd @@ -0,0 +1,55 @@ +############################################################################# +## +## This file is part of GAP, a system for computational discrete algebra. +## +## SPDX-License-Identifier: GPL-2.0-or-later +## +## Copyright of GAP belongs to its developers, whose names are too numerous +## to list here. Please refer to the COPYRIGHT file for details. +## + +############################################################################ +# +# Dense matrix objects backed by plain lists of plain row lists. +# + +############################################################################# +## +## <#GAPDoc Label="IsGenericMatrixRep"> +## +## +## +## +## An object obj in describes +## a matrix object (see ) whose entries are stored +## as a dense plain list of dense plain row lists. +##

+## Unlike , this representation is not a row +## list matrix, so direct row access via M[i] is not supported. +## Instead, it is intended as the general-purpose representation for +## matrix objects. +##

+## This representation supports the usual matrix operations and is often more +## efficient than . If existing code uses row +## access, it is often possible to replace this by the operations from +## Section . +##

+## Use instead if you need the rows to be +## available as vector objects in . +## +## +## <#/GAPDoc> +## +DeclareRepresentation( "IsGenericMatrixRep", + IsMatrixObj and IsPositionalObjectRep + and IsCopyable + and IsNoImmediateMethodsObject + and HasNumberRows and HasNumberColumns + and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain, + [] ); + + +# Internal positions for IsGenericMatrixRep: +BindConstant( "GEN_MAT_REP_BASEDOMAIN_POS", 1 ); # BaseDomain +BindConstant( "GEN_MAT_REP_NCOLS_POS", 2 ); # number of columns (needed to represent 0 x m matrices) +BindConstant( "GEN_MAT_REP_ROWS_POS", 3 ); # "rows" as a plist-of-plists diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi new file mode 100644 index 0000000000..c2aab52999 --- /dev/null +++ b/lib/matobjgeneric.gi @@ -0,0 +1,480 @@ +############################################################################# +## +## This file is part of GAP, a system for computational discrete algebra. +## +## SPDX-License-Identifier: GPL-2.0-or-later +## +## Copyright of GAP belongs to its developers, whose names are too numerous +## to list here. Please refer to the COPYRIGHT file for details. +## + +############################################################################ +# +# Dense matrix objects backed by plain lists of plain row lists. +# + +BindGlobal( "MakeIsGenericMatrixRep", + function( basedomain, ncols, list, check ) + local efam, fam, filter, typ, row; + efam := ElementsFamily( FamilyObj( basedomain ) ); + fam := CollectionsFamily( FamilyObj( basedomain ) ); + + # Currently there is no special handling depending on 'basedomain', + # the types are always cached in 'fam'. + if not IsBound( fam!.GenericMatrixRepTypes ) then + # initialize type cache + # TODO: make this thread safe for HPC-GAP + filter := IsGenericMatrixRep; + if CanEasilyCompareElementsFamily( efam ) then + filter := filter and CanEasilyCompareElements; + fi; + fam!.GenericMatrixRepTypes := [ + NewType( fam, filter ), + NewType( fam, filter and IsMutable ), + ]; + fi; + if IsMutable( list ) then + typ := fam!.GenericMatrixRepTypes[2]; + else + typ := fam!.GenericMatrixRepTypes[1]; + fi; + + if check and ValueOption( "check" ) <> false then + Assert( 0, IsPlistRep( list ) ); + for row in list do + if not IsPlistRep( row ) then + Error( "the entries of must be plain lists" ); + elif Length( row ) <> ncols then + Error( "the entries of must have length " ); + elif not IsSubset( basedomain, row ) then + Error( "the elements in must lie in " ); + fi; + od; + fi; + + return Objectify( typ, [ basedomain, ncols, list ] ); + end ); + + +InstallTagBasedMethod( NewMatrix, + IsGenericMatrixRep, + function( filter, basedomain, ncols, list ) + local nd, rows, i, row; + + if Length( list ) > 0 and not IsVectorObj( list[1] ) then + nd := NestingDepthA( list ); + if nd < 2 or nd mod 2 = 1 then + if Length( list ) mod ncols <> 0 then + Error( "NewMatrix: Length of is not a multiple of " ); + fi; + list := List( [ 0, ncols .. Length( list ) - ncols ], + i -> list{ [ i + 1 .. i + ncols ] } ); + fi; + fi; + + rows := EmptyPlist( Length( list ) ); + for i in [ 1 .. Length( list ) ] do + row := list[i]; + if IsVectorObj( row ) then + rows[i] := Unpack( row ); + else + rows[i] := PlainListCopy( row ); + fi; + od; + return MakeIsGenericMatrixRep( basedomain, ncols, rows, true ); + end ); + + +InstallTagBasedMethod( NewZeroMatrix, + IsGenericMatrixRep, + function( filter, basedomain, rows, cols ) + local list, row, i, z; + list := EmptyPlist( rows ); + z := Zero( basedomain ); + for i in [ 1 .. rows ] do + row := ListWithIdenticalEntries( cols, z ); + list[i] := row; + od; + return MakeIsGenericMatrixRep( basedomain, cols, list, false ); + end ); + + +InstallMethod( ConstructingFilter, + [ "IsGenericMatrixRep" ], + M -> IsGenericMatrixRep ); + +InstallMethod( CompatibleVectorFilter, + [ "IsGenericMatrixRep" ], + M -> IsPlistVectorRep ); + + +InstallMethod( BaseDomain, + [ "IsGenericMatrixRep" ], + M -> M![GEN_MAT_REP_BASEDOMAIN_POS] ); + +InstallMethod( NumberRows, + [ "IsGenericMatrixRep" ], + M -> Length( M![GEN_MAT_REP_ROWS_POS] ) ); + +InstallMethod( NumberColumns, + [ "IsGenericMatrixRep" ], + M -> M![GEN_MAT_REP_NCOLS_POS] ); + +InstallMethod( \[\], + [ "IsGenericMatrixRep", "IsPosInt" ], + function( M, pos ) + ErrorNoReturn( "row access unsupported; use M[i,j] or RowsOfMatrix(M)" ); + end ); + +InstallMethod( MatElm, + [ "IsGenericMatrixRep", "IsPosInt", "IsPosInt" ], + { M, row, col } -> M![GEN_MAT_REP_ROWS_POS][row,col] ); + +InstallMethod( SetMatElm, + [ "IsGenericMatrixRep and IsMutable", "IsPosInt", "IsPosInt", "IsObject" ], + function( M, row, col, val ) + if ValueOption( "check" ) <> false then + if not val in BaseDomain( M ) then + Error( " must lie in the base domain of " ); + elif not row in [ 1 .. NrRows( M ) ] then + Error( " is out of bounds" ); + elif not col in [ 1 .. NrCols( M ) ] then + Error( " is out of bounds" ); + fi; + fi; + M![GEN_MAT_REP_ROWS_POS][row,col] := val; + end ); + + +InstallMethod( Unpack, + [ "IsGenericMatrixRep" ], + M -> List( M![GEN_MAT_REP_ROWS_POS], ShallowCopy ) ); + +InstallMethod( ShallowCopy, + [ "IsGenericMatrixRep" ], + M -> MakeIsGenericMatrixRep( BaseDomain(M), NrCols(M), + List( M![GEN_MAT_REP_ROWS_POS], ShallowCopy ), false ) ); + +InstallMethod( MutableCopyMatrix, + [ "IsGenericMatrixRep" ], + M -> MakeIsGenericMatrixRep( BaseDomain(M), NrCols(M), + List( M![GEN_MAT_REP_ROWS_POS], ShallowCopy ), false ) ); + +InstallMethod( ExtractSubMatrix, + [ "IsGenericMatrixRep", "IsList", "IsList" ], + function( M, rowspos, colspos ) + local list; + list := M![GEN_MAT_REP_ROWS_POS]{ rowspos }{ colspos }; + return MakeIsGenericMatrixRep( BaseDomain(M), Length( colspos ), list, false ); + end ); + +InstallMethod( CopySubMatrix, + [ "IsGenericMatrixRep", "IsGenericMatrixRep and IsMutable", + "IsList", "IsList", "IsList", "IsList" ], + function( M, N, srcrows, dstrows, srccols, dstcols ) + if ValueOption( "check" ) <> false and + not IsIdenticalObj( BaseDomain(M), BaseDomain(N) ) then + Error( " and are not compatible" ); + fi; + N![GEN_MAT_REP_ROWS_POS]{dstrows}{dstcols} := M![GEN_MAT_REP_ROWS_POS]{srcrows}{srccols}; + end ); + +InstallMethod( TransposedMatMutable, + [ "IsGenericMatrixRep" ], + function( M ) + local list; + list := TransposedMatMutable(M![GEN_MAT_REP_ROWS_POS]); + return MakeIsGenericMatrixRep( BaseDomain(M), NrRows(M), list, false ); + end ); + +InstallMethod( \+, + [ "IsGenericMatrixRep", "IsGenericMatrixRep" ], + function( a, b ) + if ValueOption( "check" ) <> false and + ( not IsIdenticalObj( BaseDomain( a ), BaseDomain( b ) ) or + NrRows( a ) <> NrRows( b ) or + NrCols( a ) <> NrCols( b ) ) then + Error( " and are not compatible" ); + fi; + return MakeIsGenericMatrixRep( BaseDomain( a ), NrCols( a ), + a![GEN_MAT_REP_ROWS_POS] + b![GEN_MAT_REP_ROWS_POS], false ); + end ); + +InstallMethod( \-, + [ "IsGenericMatrixRep", "IsGenericMatrixRep" ], + function( a, b ) + if ValueOption( "check" ) <> false and + ( not IsIdenticalObj( BaseDomain( a ), BaseDomain( b ) ) or + NrRows( a ) <> NrRows( b ) or + NrCols( a ) <> NrCols( b ) ) then + Error( " and are not compatible" ); + fi; + return MakeIsGenericMatrixRep( BaseDomain( a ), NrCols( a ), + a![GEN_MAT_REP_ROWS_POS] - b![GEN_MAT_REP_ROWS_POS], false ); + end ); + +InstallMethod( AdditiveInverseMutable, + [ "IsGenericMatrixRep" ], + M -> MakeIsGenericMatrixRep( BaseDomain( M ), NrCols( M ), + AdditiveInverseMutable( M![GEN_MAT_REP_ROWS_POS] ), false ) ); + +InstallMethod( ZeroMutable, + [ "IsGenericMatrixRep" ], + function( M ) + local z; + z := MakeIsGenericMatrixRep( BaseDomain( M ), NrCols( M ), + ZeroMutable( M![GEN_MAT_REP_ROWS_POS] ), false ); + return z; + end ); + +InstallMethod( InverseMutable, + [ "IsGenericMatrixRep" ], + function( M ) + local bd, rows; + + bd := BaseDomain( M ); + if NrRows( M ) <> NrCols( M ) then + ErrorNoReturn( "InverseMutable: matrix must be square" ); + elif NrRows( M ) = 0 then + rows := []; + elif IsFinite( bd ) and IsField( bd ) then + rows := INV_MAT_DEFAULT_MUTABLE( M![GEN_MAT_REP_ROWS_POS] ); + else + rows := INV_MATRIX_MUTABLE( M![GEN_MAT_REP_ROWS_POS] ); + fi; + if rows = fail then + return fail; + fi; + return MakeIsGenericMatrixRep( bd, NrCols( M ), rows, false ); + end ); + +InstallMethod( \*, + [ "IsGenericMatrixRep", "IsGenericMatrixRep" ], + function( a, b ) + local rowsA, colsA, rowsB, colsB, bd, list, i; + + rowsA := NumberRows( a ); + colsA := NumberColumns( a ); + rowsB := NumberRows( b ); + colsB := NumberColumns( b ); + bd := BaseDomain( a ); + + if ValueOption( "check" ) <> false then + if colsA <> rowsB then + ErrorNoReturn( "\\*: Matrices do not fit together" ); + elif not IsIdenticalObj( bd, BaseDomain( b ) ) then + ErrorNoReturn( "\\*: Matrices not over same base domain" ); + fi; + fi; + + if rowsA = 0 or colsB = 0 then + list := []; + elif colsA = 0 then # colsA = rowsB + list := EmptyPlist( rowsA ); + for i in [ 1 .. rowsA ] do + list[i] := ListWithIdenticalEntries( colsB, Zero( bd ) ); + od; + else + list := a![GEN_MAT_REP_ROWS_POS] * b![GEN_MAT_REP_ROWS_POS]; + fi; + return MakeIsGenericMatrixRep( bd, colsB, list, false ); + end ); + +InstallOtherMethod( \*, + [ "IsGenericMatrixRep", "IsRowVectorOrVectorObj" ], + {} -> RankFilter(IsPlistVectorRep), # rank above method for [IsScalar, IsPlistVectorRep] + function( M, v ) + local rows, cols, bd, res; + + rows := NumberRows( M ); + cols := NumberColumns( M ); + bd := BaseDomain( M ); + + if ValueOption( "check" ) <> false then + if cols <> Length( v ) then + Error( " and are not compatible" ); + elif not IsIdenticalObj( bd, BaseDomain( v ) ) then + Error( " and are not compatible" ); + fi; + fi; + + # special case for empty matrices + if rows = 0 or cols = 0 then + return ZeroVector( rows, v ); + fi; + + # "unpack" cheaply and then delegate to kernel implementation + if IsPlistVectorRep(v) then + res := v![ELSPOS]; + elif IsList(v) then + res := v; + else + res := Unpack(v); + fi; + res := M![GEN_MAT_REP_ROWS_POS] * res; + return Vector( res, v ); + end ); + +InstallOtherMethod( \*, + [ "IsRowVectorOrVectorObj", "IsGenericMatrixRep" ], + {} -> RankFilter(IsPlistVectorRep), # rank above method for [IsPlistVectorRep, IsScalar] + function( v, M ) + local rows, cols, bd, res; + + rows := NumberRows( M ); + cols := NumberColumns( M ); + bd := BaseDomain( M ); + + if ValueOption( "check" ) <> false then + if Length( v ) <> rows then + Error( " and are not compatible" ); + elif not IsIdenticalObj( BaseDomain( v ), bd ) then + Error( " and are not compatible" ); + fi; + fi; + + # special case for empty matrices + if rows = 0 or cols = 0 then + return ZeroVector( cols, v ); + fi; + + # "unpack" cheaply and then delegate to kernel implementation + if IsPlistVectorRep(v) then + res := v![ELSPOS]; + elif IsList(v) then + res := v; + else + res := Unpack(v); + fi; + res := res * M![GEN_MAT_REP_ROWS_POS]; + return Vector( res, v ); + end ); + +InstallMethod( ChangedBaseDomain, + [ "IsGenericMatrixRep", "IsRing" ], + function( M, r ) + local A; + A := NewMatrix( IsGenericMatrixRep, r, NrCols(M), M![GEN_MAT_REP_ROWS_POS] ); + if not IsMutable( M ) then + MakeImmutable(A); + fi; + return A; + end ); + + +InstallMethod( MultMatrixRowLeft, + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsObject" ], + function( mat, row, scalar ) + MultMatrixRowLeft(mat![GEN_MAT_REP_ROWS_POS], row, scalar); + end ); + +InstallMethod( MultMatrixRowRight, + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsObject" ], + function( mat, row, scalar ) + MultMatrixRowRight(mat![GEN_MAT_REP_ROWS_POS], row, scalar); + end ); + +InstallMethod( AddMatrixRowsLeft, + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + function( mat, row1, row2, scalar ) + AddMatrixRowsLeft( mat![GEN_MAT_REP_ROWS_POS], row1, row2, scalar ); + end ); + +InstallMethod( AddMatrixRowsRight, + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + function( mat, row1, row2, scalar ) + AddMatrixRowsRight( mat![GEN_MAT_REP_ROWS_POS], row1, row2, scalar ); + end ); + +InstallMethod( PositionNonZeroInRow, + [ "IsGenericMatrixRep", "IsPosInt" ], + function( mat, row ) + return PositionNonZero( mat![GEN_MAT_REP_ROWS_POS][row] ); + end ); + +InstallMethod( PositionNonZeroInRow, + [ "IsGenericMatrixRep", "IsPosInt", "IsInt" ], + function( mat, row, from ) + return PositionNonZero( mat![GEN_MAT_REP_ROWS_POS][row], from ); + end ); + +InstallMethod( SwapMatrixRows, + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt" ], + function( mat, row1, row2 ) + SwapMatrixRows(mat![GEN_MAT_REP_ROWS_POS], row1, row2); + end ); + +InstallMethod( SwapMatrixColumns, + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt" ], + function( mat, col1, col2 ) + SwapMatrixColumns(mat![GEN_MAT_REP_ROWS_POS], col1, col2); + end ); + + +InstallMethod( PostMakeImmutable, + [ "IsGenericMatrixRep" ], + function( M ) + MakeImmutable( M![GEN_MAT_REP_ROWS_POS] ); + end ); + + +InstallMethod( ViewObj, [ "IsGenericMatrixRep" ], + function( M ) + Print( "<" ); + if not IsMutable( M ) then + Print( "immutable " ); + fi; + Print( NrRows(M), "x", NrCols(M), + "-matrix over ", BaseDomain(M), ">" ); + end ); + +InstallMethod( PrintObj, [ "IsGenericMatrixRep" ], + function( M ) + Print( "NewMatrix(IsGenericMatrixRep" ); + if IsFinite( BaseDomain(M) ) and IsField( BaseDomain(M) ) then + Print( ",GF(", Size( BaseDomain(M) ), ")," ); + else + Print( ",", String( BaseDomain(M) ), "," ); + fi; + Print( NumberColumns( M ), ",", Unpack( M ), ")" ); + end ); + +InstallMethod( Display, [ "IsGenericMatrixRep" ], + function( M ) + local i; + Print( "<" ); + if not IsMutable( M ) then + Print( "immutable " ); + fi; + Print( NrRows(M), "x", NrCols(M), + "-matrix over ", BaseDomain(M), ":\n" ); + for i in [ 1 .. NrRows(M) ] do + if i = 1 then + Print( "[" ); + else + Print( " " ); + fi; + Print( M![GEN_MAT_REP_ROWS_POS][i], "\n" ); + od; + Print( "]>\n" ); + end ); + +InstallMethod( String, [ "IsGenericMatrixRep" ], + function( M ) + local st; + st := "NewMatrix(IsGenericMatrixRep"; + Add( st, ',' ); + if IsFinite( BaseDomain(M) ) and IsField( BaseDomain(M) ) then + Append( st, "GF(" ); + Append( st, String( Size( BaseDomain(M) ) ) ); + Append( st, ")," ); + else + Append( st, String( BaseDomain(M) ) ); + Append( st, "," ); + fi; + Append( st, String( NumberColumns( M ) ) ); + Add( st, ',' ); + Append( st, String( Unpack( M ) ) ); + Add( st, ')' ); + return st; + end ); diff --git a/lib/matobjplist.gd b/lib/matobjplist.gd index 087d5b0330..93bf879dd1 100644 --- a/lib/matobjplist.gd +++ b/lib/matobjplist.gd @@ -71,6 +71,16 @@ DeclareRepresentation( "IsPlistVectorRep", ## a matrix object (see ) that behaves similar to ## a list of its rows, in the sense of . ##

+## In particular, the rows can be accessed via M[i], +## and they are vector objects in . +## This representation is useful if one wants to work explicitly with +## such row objects. +##

+## For most purposes, is the better choice. +## Unlike , it does not support direct row +## access, but it is intended as the general-purpose representation for +## matrix objects. +##

## implies , ## thus matrix objects in this representation can be mutable. ## @@ -126,4 +136,3 @@ BindConstant( "ELSPOS", 2 ); # Two filters to speed up some methods: DeclareFilter( "IsIntVector" ); DeclareFilter( "IsFFEVector" ); - diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index 2ec8c4f723..138d6ebfc0 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -34,55 +34,43 @@ ## BindGlobal( "MakeIsPlistVectorRep", function( basedomain, list, check ) - local fam, types, typ; - fam := FamilyObj(basedomain); - #types := _PlistVectorRepTypeCache(basedomain); - - # special case: integers - if IsIntegers(basedomain) then - if not IsBound(basedomain!.PlistVectorRepTypes) then - # initialize type cache - # TODO: make this thread safe for HPC-GAP - basedomain!.PlistVectorRepTypes := [ - NewType(fam, IsPlistVectorRep and IsIntVector and CanEasilyCompareElements), - NewType(fam, IsPlistVectorRep and IsIntVector and CanEasilyCompareElements and IsMutable), - ]; - fi; - types := basedomain!.PlistVectorRepTypes; - elif IsFFECollection(basedomain) then - if not IsBound(basedomain!.PlistVectorRepTypes) then - # initialize type cache - # TODO: make this thread safe for HPC-GAP - basedomain!.PlistVectorRepTypes := [ - NewType(fam, IsPlistVectorRep and IsFFEVector and CanEasilyCompareElements), - NewType(fam, IsPlistVectorRep and IsFFEVector and CanEasilyCompareElements and IsMutable), - ]; - fi; - types := basedomain!.PlistVectorRepTypes; + local efam, fam, filter, types, typ; + + efam := ElementsFamily( FamilyObj( basedomain ) ); + fam := FamilyObj( basedomain ); + + # we store the types in the base domain if the filter carries + # information specific to it + if IsBound( basedomain!.PlistVectorRepTypes ) then + types := basedomain!.PlistVectorRepTypes; + elif IsBound( fam!.PlistVectorRepTypes ) and not IsIntegers(basedomain) then + types := fam!.PlistVectorRepTypes; else - if not IsBound(fam!.PlistVectorRepTypes) then - # initialize type cache - # TODO: make this thread safe for HPC-GAP - fam!.PlistVectorRepTypes := [ - NewType(fam, IsPlistVectorRep), - NewType(fam, IsPlistVectorRep and IsMutable), - ]; - fam!.PlistVectorRepTypesEasyCompare := [ - NewType(fam, IsPlistVectorRep and CanEasilyCompareElements), - NewType(fam, IsPlistVectorRep and CanEasilyCompareElements and IsMutable), - ]; - fi; - if HasCanEasilyCompareElements(Representative(basedomain)) and - CanEasilyCompareElements(Representative(basedomain)) then - types := fam!.PlistVectorRepTypesEasyCompare; - else - types := fam!.PlistVectorRepTypes; - fi; + # initialize type cache + # TODO: make this thread safe for HPC-GAP + filter := IsPlistVectorRep; + if CanEasilyCompareElementsFamily( efam ) then + filter := filter and CanEasilyCompareElements; + fi; + if IsIntegers(basedomain) then + filter := filter and IsIntVector; + elif IsFFECollection(basedomain) then + filter := filter and IsFFEVector; + fi; + types := [ + NewType( fam, filter ), + NewType( fam, filter and IsMutable ), + ]; + if IsIntegers(basedomain) then + basedomain!.PlistVectorRepTypes := types; + else + fam!.PlistVectorRepTypes := types; + fi; fi; - if IsMutable(list) then - typ := types[2]; + if IsMutable( list ) then + typ := types[2]; else - typ := types[1]; + typ := types[1]; fi; if check and ValueOption( "check" ) <> false then @@ -122,33 +110,29 @@ BindGlobal( "MakeIsPlistVectorRep", ## BindGlobal( "MakeIsPlistMatrixRep", function( basedomain, emptyvector, ncols, list, check ) - local fam, types, typ, row; - fam:= CollectionsFamily( FamilyObj( basedomain ) ); + local efam, fam, filter, typ, row; + + efam := ElementsFamily( FamilyObj( basedomain ) ); + fam := CollectionsFamily( FamilyObj( basedomain ) ); # Currently there is no special handling depending on 'basedomain', # the types are always cached in 'fam'. if not IsBound( fam!.PlistMatrixRepTypes ) then # initialize type cache # TODO: make this thread safe for HPC-GAP - fam!.PlistMatrixRepTypes:= [ - NewType( fam, IsPlistMatrixRep ), - NewType( fam, IsPlistMatrixRep and IsMutable ), - ]; - fam!.PlistMatrixRepTypesEasyCompare:= [ - NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements ), - NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements and IsMutable ), + filter := IsPlistMatrixRep; + if CanEasilyCompareElementsFamily( efam ) then + filter := filter and CanEasilyCompareElements; + fi; + fam!.PlistMatrixRepTypes := [ + NewType( fam, filter ), + NewType( fam, filter and IsMutable ), ]; fi; - if HasCanEasilyCompareElements( Representative( basedomain ) ) and - CanEasilyCompareElements( Representative( basedomain ) ) then - types:= fam!.PlistMatrixRepTypesEasyCompare; - else - types:= fam!.PlistMatrixRepTypes; - fi; if IsMutable( list ) then - typ:= types[2]; + typ := fam!.PlistMatrixRepTypes[2]; else - typ:= types[1]; + typ := fam!.PlistMatrixRepTypes[1]; fi; if check and ValueOption( "check" ) <> false then @@ -160,10 +144,10 @@ BindGlobal( "MakeIsPlistMatrixRep", for row in list do if not IsPlistVectorRep( row ) then Error( "the entries of must be in 'IsPlistVectorRep'" ); - elif not IsIdenticalObj( basedomain, row![BDPOS] ) then - Error( "the entries of must have the given base domain" ); elif Length( row![ELSPOS] ) <> ncols then Error( "the entries of must have length " ); + elif not IsIdenticalObj( basedomain, row![BDPOS] ) then + Error( "the entries of must have the given base domain" ); fi; od; fi; diff --git a/lib/read3.g b/lib/read3.g index baf3cf714c..b3fdbbc96a 100644 --- a/lib/read3.g +++ b/lib/read3.g @@ -107,6 +107,7 @@ ReadLib( "wordass.gd" ); ReadLib( "matobj2.gd" ); ReadLib( "matobjplist.gd" ); +ReadLib( "matobjgeneric.gd" ); ReadLib( "matobjnz.gd" ); # files dealing with rewriting systems diff --git a/lib/read5.g b/lib/read5.g index e0042c6bf4..cb4a8365b1 100644 --- a/lib/read5.g +++ b/lib/read5.g @@ -114,6 +114,7 @@ ReadLib( "vecmat.gi" ); ReadLib( "vec8bit.gi" ); ReadLib( "mat8bit.gi" ); ReadLib( "matobjplist.gi" ); +ReadLib( "matobjgeneric.gi" ); ReadLib( "matobjnz.gi" ); ReadLib( "meataxe.gi" ); ReadLib( "meatauto.gi" ); diff --git a/tst/testinstall/MatrixObj/CompanionMatrix.tst b/tst/testinstall/MatrixObj/CompanionMatrix.tst index b5e27bbb2c..a2b1330b57 100644 --- a/tst/testinstall/MatrixObj/CompanionMatrix.tst +++ b/tst/testinstall/MatrixObj/CompanionMatrix.tst @@ -67,6 +67,22 @@ gap> TestCompanionMatrix(IsPlistMatrixRep, x+1, F); gap> TestCompanionMatrix(IsPlistMatrixRep, x^2+x+1, F); <2x2-matrix over Rationals> +# +# IsGenericMatrixRep +# +gap> F:= GF(251);; x:= X(F);; +gap> TestCompanionMatrix(IsGenericMatrixRep, x+1, F); +<1x1-matrix over GF(251)> +gap> TestCompanionMatrix(IsGenericMatrixRep, x^2+x+1, F); +<2x2-matrix over GF(251)> + +# +gap> F:= Integers;; x:= X(F);; +gap> TestCompanionMatrix(IsGenericMatrixRep, x+1, F); +<1x1-matrix over Integers> +gap> TestCompanionMatrix(IsGenericMatrixRep, x^2+x+1, F); +<2x2-matrix over Integers> + # # IsPlistRep # diff --git a/tst/testinstall/MatrixObj/ElementaryMatrices.tst b/tst/testinstall/MatrixObj/ElementaryMatrices.tst index e2080c550a..2204e66d9c 100644 --- a/tst/testinstall/MatrixObj/ElementaryMatrices.tst +++ b/tst/testinstall/MatrixObj/ElementaryMatrices.tst @@ -67,6 +67,14 @@ true gap> TestElementaryTransforms( mat, -1 ); gap> TestWholeMatrixTransforms( mat, -1 ); +# +gap> mat := NewMatrix(IsGenericMatrixRep, Integers, 3, +> [ [ 2, 4, 5 ], [ 7, 11, -4 ], [ -3, 20, 0 ] ] );; +gap> IsGenericMatrixRep(mat); +true +gap> TestElementaryTransforms( mat, -1 ); +gap> TestWholeMatrixTransforms( mat, -1 ); + # gap> TestPositionNonZeroInRow([ [ 1 ] ]); gap> TestPositionNonZeroInRow(Matrix([ [ 1 ] ])); diff --git a/tst/testinstall/MatrixObj/IdentityMatrix.tst b/tst/testinstall/MatrixObj/IdentityMatrix.tst index 1cabf541aa..74f429b3f2 100644 --- a/tst/testinstall/MatrixObj/IdentityMatrix.tst +++ b/tst/testinstall/MatrixObj/IdentityMatrix.tst @@ -73,6 +73,24 @@ gap> TestIdentityMatrix(IsPlistMatrixRep, Integers mod 4, 0); gap> TestIdentityMatrix(IsPlistMatrixRep, Integers mod 4, -1); Error, IdentityMatrix: the dimension must be non-negative +# +# IsGenericMatrixRep +# +gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), 2); +<2x2-matrix over GF(2)> +gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), 0); +<0x0-matrix over GF(2)> +gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), -1); +Error, IdentityMatrix: the dimension must be non-negative + +# +gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, 2); +<2x2-matrix over Integers> +gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, 0); +<0x0-matrix over Integers> +gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, -1); +Error, IdentityMatrix: the dimension must be non-negative + # # Test IdentityMatrix variant which "guesses" a suitable representation, i.e.: # IdentityMatrix( , , ) diff --git a/tst/testinstall/MatrixObj/Matrix.tst b/tst/testinstall/MatrixObj/Matrix.tst index 85d6c9d80f..bc07b33465 100644 --- a/tst/testinstall/MatrixObj/Matrix.tst +++ b/tst/testinstall/MatrixObj/Matrix.tst @@ -45,5 +45,16 @@ gap> Display(m); gap> m = Matrix( IsPlistMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 ); true +# +gap> m := Matrix( IsGenericMatrixRep, GF(2), [[1,2],[3,4]] * Z(2) ); +<2x2-matrix over GF(2)> +gap> Display(m); +<2x2-matrix over GF(2): +[[ Z(2)^0, 0*Z(2) ] + [ Z(2)^0, 0*Z(2) ] +]> +gap> m = Matrix( IsGenericMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 ); +true + # gap> STOP_TEST("Matrix.tst"); diff --git a/tst/testinstall/MatrixObj/ZeroMatrix.tst b/tst/testinstall/MatrixObj/ZeroMatrix.tst index 2affaa554b..a21962bfcf 100644 --- a/tst/testinstall/MatrixObj/ZeroMatrix.tst +++ b/tst/testinstall/MatrixObj/ZeroMatrix.tst @@ -79,6 +79,24 @@ gap> TestZeroMatrix(IsPlistMatrixRep, Integers mod 4, 2, 0); gap> TestZeroMatrix(IsPlistMatrixRep, Integers mod 4, 0, 3); <0x3-matrix over (Integers mod 4)> +# +# IsGenericMatrixRep +# +gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 2, 3); +<2x3-matrix over GF(2)> +gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 2, 0); +<2x0-matrix over GF(2)> +gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 0, 3); +<0x3-matrix over GF(2)> + +# +gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 2, 3); +<2x3-matrix over Integers> +gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 2, 0); +<2x0-matrix over Integers> +gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 0, 3); +<0x3-matrix over Integers> + # # Test ZeroMatrix variant which "guesses" a suitable representation, i.e.: # ZeroMatrix( , , ) diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst new file mode 100644 index 0000000000..e1bc6c3ca1 --- /dev/null +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -0,0 +1,465 @@ +#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs, N, T, R +gap> START_TEST( "matobjgeneric.tst" ); + +# +# MakeIsPlistVectorRep: test input validation +# +gap> e:= MakeIsPlistVectorRep( Integers, [], true ); + +gap> v:= MakeIsPlistVectorRep( Integers, [ 1 ], true ); + +gap> v2:= NewVector( IsPlistVectorRep, Integers, [ 1, 0 ] ); + +gap> w:= MakeIsPlistVectorRep( Rationals, [ 1 ], true ); + + +# +gap> MakeIsGenericMatrixRep( Integers, 2, [ v ], true ); +Error, the entries of must be plain lists +gap> M:= MakeIsGenericMatrixRep( Integers, 2, [], true ); +<0x2-matrix over Integers> +gap> MakeIsGenericMatrixRep( Integers, 1, [ [ 1 ] ], true ); +<1x1-matrix over Integers> +gap> MakeIsGenericMatrixRep( Integers, 2, [ [ 1 ] ], true ); +Error, the entries of must have length +gap> MakeIsGenericMatrixRep( Integers, 1, [ [ 1/2 ] ], true ); +Error, the elements in must lie in +gap> MakeIsGenericMatrixRep( GF(2), 1, [ [ Z(2) ] ], true ); +<1x1-matrix over GF(2)> +gap> MakeIsGenericMatrixRep( GF(2), 1, [ [ Z(4) ] ], true ); +Error, the elements in must lie in + +# +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [] ); +<0x2-matrix over Integers> +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ 1 ] ); +Error, NewMatrix: Length of is not a multiple of +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1 ] ] ); +Error, the entries of must have length +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1, 2 ] ] ); +<1x2-matrix over Integers> +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ v ] ); +Error, the entries of must have length +gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1, 2 ], [ 3, 4 ] ] ); +<2x2-matrix over Integers> +gap> IsMutable( M ); +true +gap> Unpack( M ); +[ [ 1, 2 ], [ 3, 4 ] ] +gap> M[2,1]; +3 +gap> M[1]; +Error, row access unsupported; use M[i,j] or RowsOfMatrix(M) +gap> M[2,2] := 5;; +gap> Unpack( M ); +[ [ 1, 2 ], [ 3, 5 ] ] + +# +gap> rows:= RowsOfMatrix( M ); +[ , + ] +gap> Length( rows ); +2 +gap> IsPlistVectorRep( rows[1] ); +true +gap> Unpack( rows[1] ); +[ 1, 2 ] +gap> M[1,1] := 77;; +gap> rows[1][1]; +1 + +# +gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 2, [ v2, v2 ] );; +gap> Unpack( M ); +[ [ 1, 0 ], [ 1, 0 ] ] + +# +# Empty matrices and empty vectors +# +# +gap> a:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 ); +<2x0-matrix over Integers> +gap> b:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 ); +<0x3-matrix over Integers> +gap> c:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 0 ); +<0x0-matrix over Integers> +gap> d:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 2 ); +<0x2-matrix over Integers> +gap> z:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 ); +<2x3-matrix over Integers> +gap> IsMutable( z ); +true +gap> Unpack( z ); +[ [ 0, 0, 0 ], [ 0, 0, 0 ] ] + +# +gap> M:= NewIdentityMatrix( IsGenericMatrixRep, Integers, 2 );; +gap> Unpack( M ); +[ [ 1, 0 ], [ 0, 1 ] ] + +# +gap> a = NewMatrix( IsGenericMatrixRep, Integers, 0, [ [], [] ] ); +true +gap> b = NewMatrix( IsGenericMatrixRep, Integers, 3, [] ); +true +gap> c = NewMatrix( IsGenericMatrixRep, Integers, 0, [] ); +true +gap> d = NewMatrix( IsGenericMatrixRep, Integers, 2, [] ); +true + +# +gap> p:= a * b; +<2x3-matrix over Integers> +gap> Unpack( p ); +[ [ 0, 0, 0 ], [ 0, 0, 0 ] ] +gap> p:= d * a; +<0x0-matrix over Integers> +gap> Unpack( p ); +[ ] +gap> p:= c * b; +<0x3-matrix over Integers> +gap> Unpack( p ); +[ ] + +# empty vector times (necessarily also empty) matrix +gap> ev:= NewVector( IsPlistVectorRep, Integers, [] ); + +gap> a * ev; + +gap> Unpack( last ); +[ 0, 0 ] +gap> ev * b; + +gap> Unpack( last ); +[ 0, 0, 0 ] + +# non-empty vector times empty matrix +gap> v2:= NewVector( IsPlistVectorRep, Integers, [ 1, 2 ] ); + +gap> d * v2; + +gap> Unpack( last ); +[ ] +gap> Unpack( v2 * a ); +[ ] + +# +gap> b + b; +<0x3-matrix over Integers> +gap> b - b; +<0x3-matrix over Integers> +gap> -b; +<0x3-matrix over Integers> +gap> ZeroMutable( b ); +<0x3-matrix over Integers> + +# +gap> InverseMutable( c ); +<0x0-matrix over Integers> +gap> InverseSameMutability( c ); +<0x0-matrix over Integers> + +# +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 0, 0, 2 ], [ 0, 0, 0 ] ] );; +gap> PositionNonZeroInRow( M, 1 ); +3 +gap> PositionNonZeroInRow( M, 1, 2 ); +3 +gap> PositionNonZeroInRow( M, 2 ); +4 + +# +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] );; +gap> MultMatrixRowLeft( M, 1, -1 );; +gap> Unpack( M ); +[ [ -1, -2, -3 ], [ 4, 5, 6 ] ] +gap> MultMatrixRowRight( M, 2, 2 );; +gap> Unpack( M ); +[ [ -1, -2, -3 ], [ 8, 10, 12 ] ] +gap> AddMatrixRowsLeft( M, 1, 2, 3 );; +gap> Unpack( M ); +[ [ 23, 28, 33 ], [ 8, 10, 12 ] ] +gap> AddMatrixRowsRight( M, 2, 1, 2 );; +gap> Unpack( M ); +[ [ 23, 28, 33 ], [ 54, 66, 78 ] ] +gap> SwapMatrixRows( M, 1, 2 );; +gap> Unpack( M ); +[ [ 54, 66, 78 ], [ 23, 28, 33 ] ] + +# +# Test Inverse / InverseMutable +# +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ] );; +gap> InverseMutable( M ); +Error, InverseMutable: matrix must be square + +# +gap> M:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 2 );; +gap> InverseMutable( M ); +fail + +# +gap> M:= Matrix( IsGenericMatrixRep, GF(2), [ [ Z(2)^0, Z(2)^0 ], [ Z(2)^0, 0*Z(2) ] ] );; +gap> N:= InverseMutable( M );; +gap> Display( N ); +<2x2-matrix over GF(2): +[[ 0*Z(2), Z(2)^0 ] + [ Z(2)^0, Z(2)^0 ] +]> +gap> IsOne( N * M ); +true +gap> IsOne( M * N ); +true + +# +gap> M:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ], [ 3, 5 ] ] );; +gap> N:= InverseMutable( M );; +gap> Display( N ); +<2x2-matrix over Rationals: +[[ -5, 2 ] + [ 3, -1 ] +]> + +# +# mutability after operations +# +gap> M:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ], [ 3, 5 ] ] );; +gap> IsMutable(M); +true +gap> N:= InverseSameMutability( M );; +gap> IsMutable(N); +true +gap> IsMutable( M * N ); +true +gap> IsMutable( M + N ); +true +gap> IsMutable( M - N ); +true +gap> IsMutable( -M ); +true +gap> MakeImmutable(M);; +gap> IsMutable( M * N ); +true +gap> IsMutable( M + N ); +true +gap> IsMutable( M - N ); +true +gap> N:= InverseSameMutability( M );; +gap> IsMutable(N); +false +gap> IsMutable( M * N ); +false +gap> IsMutable( M + N ); +false +gap> IsMutable( M - N ); +false +gap> IsMutable( -M ); +false + +# +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );; +gap> M[1,1] := 1/2; +Error, must lie in the base domain of +gap> M[3,1] := 1; +Error, is out of bounds +gap> M[1,3] := 1; +Error, is out of bounds + +# +gap> a:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ] ] );; +gap> b:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ] ] );; +gap> a + b; +Error, and are not compatible +gap> a - b; +Error, and are not compatible +gap> c:= Matrix( IsGenericMatrixRep, Integers, [ [ 1 ], [ 2 ] ] );; +gap> c * c; +Error, \*: Matrices do not fit together +gap> d:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1 ], [ 2 ] ] );; +gap> a * d; +Error, \*: Matrices not over same base domain + +# +# ShallowCopy, MutableCopyMatrix +# +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );; +gap> N:= ShallowCopy( M );; +gap> N[1,1] := 99;; +gap> Unpack( M ); +[ [ 1, 2 ], [ 3, 4 ] ] +gap> Unpack( N ); +[ [ 99, 2 ], [ 3, 4 ] ] +gap> N:= MutableCopyMatrix( M );; +gap> N[1,2] := 77;; +gap> Unpack( M ); +[ [ 1, 2 ], [ 3, 4 ] ] +gap> Unpack( N ); +[ [ 1, 77 ], [ 3, 4 ] ] + +# +# ExtractSubMatrix, CopySubMatrix +# +gap> Unpack( ExtractSubMatrix( M, [ 2, 1 ], [ 2 ] ) ); +[ [ 4 ], [ 2 ] ] +gap> T:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 );; +gap> CopySubMatrix( M, T, [ 2, 1 ], [ 1, 2 ], [ 2 ], [ 3 ] );; +gap> Unpack( T ); +[ [ 0, 0, 4 ], [ 0, 0, 2 ] ] +gap> CopySubMatrix( Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ] ] ), +> T, [ 1 ], [ 1 ], [ 1 ], [ 1 ] ); +Error, and are not compatible + +# +# TransposedMatMutable +# +gap> Unpack( TransposedMatMutable( M ) ); +[ [ 1, 3 ], [ 2, 4 ] ] + +# +# ChangedBaseDomain +# +gap> N:= ChangedBaseDomain( M, Rationals );; +gap> BaseDomain( N ); +Rationals +gap> Unpack( N ); +[ [ 1, 2 ], [ 3, 4 ] ] +gap> IsMutable( N ); +true +gap> MakeImmutable( M );; +gap> N:= ChangedBaseDomain( M, Rationals );; +gap> IsMutable( N ); +false + +# +# ViewObj, PrintObj, Display, String +# +gap> M := Matrix( IsGenericMatrixRep, GF(2), [ [ Z(2)^0, 0*Z(2) ] ] ); +<1x2-matrix over GF(2)> +gap> Print(M, "\n"); +NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ]) +gap> Display(M); +<1x2-matrix over GF(2): +[[ Z(2)^0, 0*Z(2) ] +]> +gap> String(M); +"NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ])" + +# +gap> MakeImmutable( M ); + +gap> Print(M, "\n"); +NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ]) +gap> Display(M); + +gap> String(M); +"NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ])" + +# +gap> M :=Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] ); +<2x2-matrix over Integers> +gap> Print(M, "\n"); +NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ]) +gap> Display(M); +<2x2-matrix over Integers: +[[ 1, 2 ] + [ 3, 4 ] +]> +gap> String(M); +"NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ])" + +# +gap> MakeImmutable( M ); + +gap> Print(M, "\n"); +NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ]) +gap> Display(M); + +gap> String(M); +"NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ])" + +# +# vec * mat, mat * vec +# +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );; +gap> v:= Vector( Integers, [ 1, 2 ] ); + +gap> Display( M * v ); + +gap> Display( v * M ); + + +# +gap> M * [ 1, 2 ]; +[ 5, 11 ] +gap> [ 1, 2 ] * M; +[ 7, 10 ] + +# +gap> R:= Integers mod 6;; +gap> M:= Matrix( IsGenericMatrixRep, R, One(R) * [ [ 1, 2 ], [ 3, 4 ] ] );; +gap> v:= NewVector( IsZmodnZVectorRep, R, One(R) * [ 1, 2 ] ); + +gap> Display( M * v ); + +gap> Display( v * M ); + + +# error handling +gap> M * [ 1, 2, 3 ]; +Error, and are not compatible +gap> [ 1, 2, 3 ] * M; +Error, and are not compatible +gap> M * [ Z(2), Z(2) ]; +Error, and are not compatible +gap> [ Z(2), Z(2) ] * M; +Error, and are not compatible + +# multiplication with empty list is not well-defined: we don't know if +# is meant to be a vector of length 0, or something else; so rather +# error out +gap> a:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 );; +gap> b:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 );; +gap> a * []; +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `BaseDomain' on 1 arguments +gap> [] * b; +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `BaseDomain' on 1 arguments + +# +# families +# +gap> M:= NewZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 ); +<2x3-matrix over Integers> +gap> IsMutable( M ); +true +gap> IsCyclotomicCollColl( M ); +true +gap> IsFFECollColl( M ); +false + +# +gap> M:= NewZeroMatrix( IsGenericMatrixRep, GF(257), 2, 3 ); +<2x3-matrix over GF(257)> +gap> IsMutable( M ); +true +gap> IsCyclotomicCollColl( M ); +false +gap> IsFFECollColl( M ); +true + +# +gap> STOP_TEST( "matobjgeneric.tst" ); diff --git a/tst/testinstall/MatrixObj/matobjplist.tst b/tst/testinstall/MatrixObj/matobjplist.tst index 584ec3da07..5a609ef25e 100644 --- a/tst/testinstall/MatrixObj/matobjplist.tst +++ b/tst/testinstall/MatrixObj/matobjplist.tst @@ -39,10 +39,8 @@ gap> NewVector( IsPlistVectorRep, Integers, [ 1/2 ] );; Error, the elements in must lie in # -gap> NewZeroVector( IsPlistVectorRep, Integers, 0 );; -gap> z:= NewZeroVector( IsPlistVectorRep, Integers, 1 );; -gap> IsMutable( z ); -true +gap> NewZeroVector( IsPlistVectorRep, Integers, 0 ); + # gap> NewMatrix( IsPlistMatrixRep, Integers, 2, [] );; @@ -58,18 +56,74 @@ gap> IsMutable( M ) and ForAll( [ 1 .. Length( M ) ], i -> IsMutable( M[i] ) ); true # -gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 0 );; -gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 0 );; -gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 3 );; -gap> M:= NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 3 );; +gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 0 ); +<0x0-matrix over Integers> +gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 0 ); +<2x0-matrix over Integers> +gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 3 ); +<0x3-matrix over Integers> +gap> M:= NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 3 ); +<2x3-matrix over Integers> gap> IsMutable( M ) and ForAll( [ 1 .. Length( M ) ], i -> IsMutable( M[i] ) ); true # -gap> NewIdentityMatrix( IsPlistMatrixRep, Integers, 0 );; -gap> M:= NewIdentityMatrix( IsPlistMatrixRep, Integers, 2 );; +gap> NewIdentityMatrix( IsPlistMatrixRep, Integers, 0 ); +<0x0-matrix over Integers> +gap> M:= NewIdentityMatrix( IsPlistMatrixRep, Integers, 2 ); +<2x2-matrix over Integers> gap> IsMutable( M ) and ForAll( [ 1 .. Length( M ) ], i -> IsMutable( M[i] ) ); true +# +# special filters and families +# +gap> v:= NewVector( IsPlistVectorRep, Integers, [ 1, 2, 0 ] ); + +gap> IsMutable( v ); +true +gap> IsIntVector( v ); +true +gap> IsFFEVector( v ); +false +gap> IsCyclotomicCollection( v ); +true +gap> IsFFECollection( v ); +false + +# +gap> v:= NewVector( IsPlistVectorRep, GF(257), Z(257)^0 * [ 1, 2, 0 ] ); + +gap> IsMutable( v ); +true +gap> IsIntVector( v ); +false +gap> IsFFEVector( v ); +true +gap> IsCyclotomicCollection( v ); +false +gap> IsFFECollection( v ); +true + +# +gap> M:= NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 3 ); +<2x3-matrix over Integers> +gap> IsMutable( M ); +true +gap> IsCyclotomicCollColl( M ); +true +gap> IsFFECollColl( M ); +false + +# +gap> M:= NewZeroMatrix( IsPlistMatrixRep, GF(257), 2, 3 ); +<2x3-matrix over GF(257)> +gap> IsMutable( M ); +true +gap> IsCyclotomicCollColl( M ); +false +gap> IsFFECollColl( M ); +true + # gap> STOP_TEST( "matobjplist.tst" ); diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index 1f5a21ebc2..5d1ac8de44 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -211,6 +211,8 @@ TestWholeMatrixTransforms := function(mat, scalar) basedomain := BaseDomain(mat); if IsPlistMatrixRep(mat) then src := NewMatrix(IsPlistMatrixRep, basedomain, NrCols(mat), src); + elif IsGenericMatrixRep(mat) then + src := NewMatrix(IsGenericMatrixRep, basedomain, NrCols(mat), src); elif Is8BitMatrixRep(mat) then ConvertToMatrixRep(src, basedomain); fi; diff --git a/tst/testspecial/method-not-found-where.g b/tst/testspecial/method-not-found-where.g index 16ce4149c4..49079f4b75 100644 --- a/tst/testspecial/method-not-found-where.g +++ b/tst/testspecial/method-not-found-where.g @@ -1,5 +1,5 @@ # test method-not-found traceback rendering while preserving helper access -f := a -> a + a;; +f := a -> IsDiagonalMat(a);; f(()); ShowMethods(1); Where(5); diff --git a/tst/testspecial/method-not-found-where.g.out b/tst/testspecial/method-not-found-where.g.out index c7496f32b2..30601cd166 100644 --- a/tst/testspecial/method-not-found-where.g.out +++ b/tst/testspecial/method-not-found-where.g.out @@ -1,19 +1,19 @@ gap> # test method-not-found traceback rendering while preserving helper access -gap> f := a -> a + a;; +gap> f := a -> IsDiagonalMat(a);; gap> f(()); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `+' on 2 arguments +Error, no 1st choice method found for `IsDiagonalMatrix' on 1 arguments Stack trace: -*[1] a + a +*[1] IsDiagonalMat( a ) @ *stdin*:3 ( ) called from read-eval loop at *stdin*:4 type 'quit;' to quit to outer loop brk> ShowMethods(1); -#I Searching Method for + with 2 arguments: -#I Total: 138 entries +#I Searching Method for IsDiagonalMatrix with 1 argument: +#I Total: 3 entries brk> Where(5); -*[1] a + a +*[1] IsDiagonalMat( a ) @ *stdin*:3 ( ) called from read-eval loop at *errin*:2 From 6ec087a25728a65246595246f9d6078a8bea0536 Mon Sep 17 00:00:00 2001 From: Reinis Cirpons <43414125+reiniscirpons@users.noreply.github.com> Date: Sun, 17 May 2026 01:48:38 +0200 Subject: [PATCH 067/123] Add `EnumeratorOfPartitionsSet` enumerator (#6384) --- lib/combinat.gd | 31 +++++- lib/combinat.gi | 185 +++++++++++++++++++++++++++++++++++ tst/testinstall/combinat.tst | 139 +++++++++++++++++++++++++- 3 files changed, 350 insertions(+), 5 deletions(-) diff --git a/lib/combinat.gd b/lib/combinat.gd index f89bbc550a..38a2abfaf8 100644 --- a/lib/combinat.gd +++ b/lib/combinat.gd @@ -1169,14 +1169,16 @@ DeclareGlobalFunction("NrRestrictedPartitions"); ## DeclareGlobalFunction( "IteratorOfPartitions" ); - ############################################################################# ## -#F IteratorOfPartitionsSet( [, [ ] ] ) +#F IteratorOfPartitionsSet( [, [, ] ] ) +#F EnumeratorOfPartitionsSet( [, [, ] ] ) ## ## <#GAPDoc Label="IteratorOfPartitionsSet"> ## -## +## Iterator and enumerator of unordered set partitions +## +## ## ## ## returns an iterator @@ -1187,12 +1189,33 @@ DeclareGlobalFunction( "IteratorOfPartitions" ); ## then only partitions of size k are computed. ## If k is given and flag is equal to true, ## then only partitions of size at most k are computed. +##

+## returns an enumerator +## (see ) for all unordered partitions of the +## set set. The arguments k and flag function in the +## same manner as for the iterator. +##

+## The ordering of the partitions from these functions can be different and +## also different from the list returned by . +##

+## +## gap> m:=[1..9];; +## gap> Bell(9); +## 21147 +## gap> Length(PartitionsSet(m)); +## 21147 +## gap> cm := EnumeratorOfPartitionsSet(m);; +## gap> cm[1000]; +## [ [ 1, 2, 4, 9 ], [ 3, 6, 8 ], [ 5, 7 ] ] +## gap> Position(cm, last); +## 1000 +## ## ## ## <#/GAPDoc> ## DeclareGlobalFunction( "IteratorOfPartitionsSet" ); - +DeclareGlobalFunction( "EnumeratorOfPartitionsSet" ); ############################################################################# ## diff --git a/lib/combinat.gi b/lib/combinat.gi index 672992d0d5..0dad5dcfe5 100644 --- a/lib/combinat.gi +++ b/lib/combinat.gi @@ -2429,6 +2429,191 @@ InstallGlobalFunction( "IteratorOfPartitions", function( n ) next := 0 * [ 1 .. n ] + 1 ) ); end ); +############################################################################# +## +#F EnumeratorOfPartitionsSet( [, [, ] ] ) +## + + +InstallGlobalFunction(EnumeratorOfPartitionsSet , function(s, arg...) + local k, r, l, j, cumulative_stirling, ElementNumber, NumberElement; + + if not IsSet(s) then + Error( "EnumeratorOfPartitionsSet: must be a set" ); + fi; + + l := Length(s); + + # Method for finding n-th k-partition of s, does not + # do argument checking, this is done further down when + # instantiating the enumerators. + ElementNumber := function(enu, n, k) + local res, j, kp, np, t, i; + if l = 0 and n = 0 and k = 0 then + return []; + fi; + + res := List([1 .. k], x -> []); + # kp is the largest index of still active parts. + # Every time kp is decremented, we guarantee that + # res[kp + 1] will not be changed anymore. + kp := k; + # np keeps track of the part of n that we still need + # to process. Use it to avoid recursive calls. + np := n; + for j in [l, l - 1 .. 1] do + # Intuitively, we use identity + # Stirling2(j, k') = Stirling2(j-1, k'-1) + k' * Stirling2(j-1, k') + # to recursively encode partitions in the following manner: + # If n < Stirling2(j-1, k'-1), then we recursively construct + # the (k'-1)-partition corresponding to n and add a new singleton part + # consisting solely of s[j] to it. + # Otherwise, we can write n = Stirling2(j-1, k'-1) + i * Stirling(j-1, k') + n' + # for some numbers i and n' such that + # i < k' and n' < Stirling2(j-1, k'). + # We then recursively construct the k'-partition corresponding to n' and + # add s[j] to the i-th part. + t := Stirling2(j - 1, kp - 1); + if np <= t then + # Add last element to part kp, and + # decrement kp to mark res[kp] as complete. + Add(res[kp], s[j]); + kp := kp - 1; + else + # np and i are the numbers n' and i described above. + np := np - t; + t := Stirling2(j - 1, kp); + i := QuoInt(np - 1, t) + 1; + Add(res[i], s[j]); + np := ((np - 1) mod t) + 1; + fi; + od; + return List(res, Reversed); + end; + + NumberElement := function(enu, p, k) + local res, kp, ks, sp, perm, i, j, jp; + + if not IsSet(p) or Length(p) <> k then + return fail; + fi; + + if Length(p) = 0 then + if l = 0 and k = 0 then + return 1; + fi; + return fail; + fi; + + # ks[i] is the index corresponding to the + # end of the i-th part of p in the flattened + # version of p (stored as sp) + ks := []; + sp := []; + for kp in [1 .. k] do + if not IsSet(p[kp]) then + return fail; + fi; + if kp = 1 then + Add(ks, Length(p[kp])); + else + Add(ks, ks[Length(ks)] + Length(p[kp])); + fi; + Append(sp, p[kp]); + od; + + # Every partition of s must store all of the same elements as s. + perm := PermListList(sp, s); + if perm = fail then + return fail; + fi; + + res := 1; + kp := k; + for j in [l, l - 1 .. 1] do + jp := j^perm; + # i is the part of p that s[j] is in + i := PositionSorted(ks, jp); + + # Check passes if and only if s[j] is the first element of the i-th + # part of p. According to our encoding convention in ElementNumber, + # this means that the remaining partition is a (kp-1)-partition. + if jp = 1 or (i > 1 and ks[i - 1] + 1 = jp) then + kp := kp - 1; + else + # Otherwise, we perform the reverse manipulation to the one + # modifying np in ElementNumber + res := res + (i-1) * Stirling2(j-1, kp) + Stirling2(j-1, kp-1); + fi; + od; + + return res; + end; + + r := rec(s := s, l := l); + if Length(arg) = 1 or Length(arg) = 2 then + k := arg[1]; + if not IsInt(k) then + Error("EnumeratorOfPartitionsSet: must be an integer"); + fi; + fi; + + if (Length(arg) = 2 and arg[2] = true) or (Length(arg) = 0) then + # k parts or less, also handles all partition case. + if Length(arg) = 0 then + k := l; + else + k := Minimum(k, l); + fi; + + cumulative_stirling := [Stirling2(l, 0)]; + for j in [1 .. k] do + Add(cumulative_stirling, cumulative_stirling[j] + Stirling2(l, j)); + od; + r.cumulative_stirling := cumulative_stirling; + r.ElementNumber := function(enu, n) + local kp; + if n > cumulative_stirling[k + 1] then + Error("Index ", n, " not bound."); + fi; + kp := PositionSorted(cumulative_stirling, n) - 1; + if kp = 0 then + return ElementNumber(enu, n, kp); + fi; + return ElementNumber(enu, n - cumulative_stirling[kp], kp); + end; + r.NumberElement := function(enu, p) + local t; + if not IsSet(p) or Length(p) > k then + return fail; + fi; + t := NumberElement(enu, p, Length(p)); + if t = fail then + return fail; + fi; + return cumulative_stirling[Length(p)] + t; + end; + r.Length := x -> cumulative_stirling[k + 1]; + elif (Length(arg) = 2 and arg[2] = false) or (Length(arg) = 1) then + r.ElementNumber := function(enu, n) + if n > Stirling2(l, k) then + Error("Index ", n, " not bound."); + fi; + return ElementNumber(enu, n, k); + end; + r.NumberElement := function(enu, p) + return NumberElement(enu, p, k); + end; + r.Length := x -> Stirling2(l, k); + elif Length(arg) = 2 then + Error("EnumeratorOfPartitionsSet: must be true or false"); + else + Error( "usage: EnumeratorOfPartitionsSet( [, [, ] ] )" ); + fi; + + r.k := k; + return EnumeratorByFunctions(ListsFamily, r); +end); ############################################################################# ## diff --git a/tst/testinstall/combinat.tst b/tst/testinstall/combinat.tst index f1bf71034f..5b027dac88 100644 --- a/tst/testinstall/combinat.tst +++ b/tst/testinstall/combinat.tst @@ -2,7 +2,7 @@ ## ## This file tests the functions that mainly deal with combinatorics. ## -#@local n,mset,comb1,comb2,comb3,it,pn1,pn2,s,k,x +#@local n,mset,comb1,comb2,comb3,it,pn1,pn2,s,k,x,y gap> START_TEST("combinat.tst"); @@ -549,6 +549,143 @@ gap> for s in [[], [5], [1,2,3,4], [2,5,7], ["a","b","c","d","e"], [3..9]] do > od; > od; +#F EnumeratorOfPartitionsSet( [, [, ] ] ) +gap> EnumeratorOfPartitionsSet(); +Error, Function: number of arguments must be at least 1 (not 0) +gap> EnumeratorOfPartitionsSet(fail); +Error, EnumeratorOfPartitionsSet: must be a set +gap> EnumeratorOfPartitionsSet([],fail); +Error, EnumeratorOfPartitionsSet: must be an integer +gap> EnumeratorOfPartitionsSet([1],1,fail); +Error, EnumeratorOfPartitionsSet: must be true or false +gap> EnumeratorOfPartitionsSet([1],1,true,"too many"); +Error, usage: EnumeratorOfPartitionsSet( [, [, ] ] ) +gap> for s in [ +> [], [5], [1, 2, 3, 4], [2, 5, 7], ["a", "b", "c", "d", "e"], [3 .. 9], +> [[1], [1, 2], [2, 3], [4]], ["a", "ab", "c"], "abcd" +> ] do +> pn1 := PartitionsSet(s); +> pn2 := List(EnumeratorOfPartitionsSet(s)); +> if Length(pn1) <> Length(pn2) then +> Error("wrong number of elements for s = ", s); +> elif Set(pn1) <> Set(pn2) then +> Error("different elements for s = ", s); +> fi; +> for y in pn1 do +> if Position(pn2, y) = fail then +> Error("did not find position of element y = ", y, " when s = ", s); +> fi; +> if pn2[Position(pn2, y)] <> y then +> Error("position does not cancel for y = ", y, " when s = ", s); +> fi; +> od; +> for k in [0 .. Size(s) + 1] do +> pn1 := PartitionsSet(s, k); +> pn2 := List(EnumeratorOfPartitionsSet(s, k)); +> if Length(pn1) <> Length(pn2) then +> Error("wrong number of elements for s = ", s, ", k = ", k); +> elif Set(pn1) <> Set(pn2) then +> Error("different elements for s = ", s, ", k = ", k); +> fi; +> for y in pn1 do +> if Position(pn2, y) = fail then +> Error("did not find position of element y = ", y, " when s = ", s); +> fi; +> if pn2[Position(pn2, y)] <> y then +> Error("position does not cancel for y = ", y, " when s = ", s); +> fi; +> od; +> od; +> for k in [0 .. Size(s) + 1] do +> pn1:= []; +> for x in [0 .. k] do +> Append(pn1, PartitionsSet(s, x)); +> od; +> pn2:= List(IteratorOfPartitionsSet(s, k, true)); +> if Length(pn1) <> Length(pn2) then +> Error("wrong number of elements for s = ", s, ", k <= ", k); +> elif Set(pn1) <> Set(pn2) then +> Error("different elements for s = ", s, ", k <= ", k); +> fi; +> for y in pn1 do +> if Position(pn2, y) = fail then +> Error("did not find position of element y = ", y, " when s = ", s); +> fi; +> if pn2[Position(pn2, y)] <> y then +> Error("position does not cancel for y = ", y, " when s = ", s); +> fi; +> od; +> od; +> od; +gap> pn2 := EnumeratorOfPartitionsSet(["a", "ab", "c", "cd"]);; +gap> Position(pn2, [["a", "ab", "c"], ["cd"]]); +2 +gap> Position(pn2, [["a", "ab"], ["c"], ["cd"]]); +9 +gap> Position(pn2, [["cd"], ["a", "ab", "c"]]); +fail +gap> Position(pn2, [["a", "c", "ab"], ["cd"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], ["d"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], "cd"]); +fail +gap> Position(pn2, [1, 2]); +fail +gap> Position(pn2, 1); +fail +gap> pn2 := EnumeratorOfPartitionsSet(["a", "ab", "c", "cd"], 2);; +gap> Position(pn2, [["a", "ab", "c"], ["cd"]]); +1 +gap> Position(pn2, [["a", "ab"], ["c"], ["cd"]]); +fail +gap> Position(pn2, [["cd"], ["a", "ab", "c"]]); +fail +gap> Position(pn2, [["a", "c", "ab"], ["cd"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], ["d"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], "cd"]); +fail +gap> Position(pn2, [1, 2]); +fail +gap> Position(pn2, 1); +fail +gap> pn2 := EnumeratorOfPartitionsSet(["a", "ab", "c", "cd"], 2, false);; +gap> Position(pn2, [["a", "ab", "c"], ["cd"]]); +1 +gap> Position(pn2, [["a", "ab"], ["c"], ["cd"]]); +fail +gap> Position(pn2, [["cd"], ["a", "ab", "c"]]); +fail +gap> Position(pn2, [["a", "c", "ab"], ["cd"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], ["d"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], "cd"]); +fail +gap> Position(pn2, [1, 2]); +fail +gap> Position(pn2, 1); +fail +gap> pn2 := EnumeratorOfPartitionsSet(["a", "ab", "c", "cd"], 2, true);; +gap> Position(pn2, [["a", "ab", "c"], ["cd"]]); +2 +gap> Position(pn2, [["a", "ab"], ["c"], ["cd"]]); +fail +gap> Position(pn2, [["cd"], ["a", "ab", "c"]]); +fail +gap> Position(pn2, [["a", "c", "ab"], ["cd"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], ["d"]]); +fail +gap> Position(pn2, [["a", "ab", "c"], "cd"]); +fail +gap> Position(pn2, [1, 2]); +fail +gap> Position(pn2, 1); +fail + #F Lucas(

,,) . . . . . . . . . . . . . . value of a lucas sequence gap> Print(List( [0..10], i->Lucas(1,-2,i)[1] ),"\n"); [ 0, 1, 1, 3, 5, 11, 21, 43, 85, 171, 341 ] From 5df0292fe384fcee73b165af9e2fe233e43435af Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 18 May 2026 09:10:42 +0200 Subject: [PATCH 068/123] Miscellaneous changes (#6392) * Remove trailing whitespace * kernel: change "Obj Func" to "Obj Func" * tweak coder & interpreter tests The removed tests for quit and QUIT were redundant, similar ones are in `tst/testinstall/break.tst.` * Remove some unused code * kernel: tweak some comments --- benchmark/transgrp/examine4 | 142 +++++++++++++++---------------- dev/gapmacro2gapdoc.g | 34 ++++---- dev/manualutils.g | 14 ++-- hpcgap/lib/helpbase.gi | 4 +- hpcgap/lib/primality.gi | 65 -------------- lib/helpbase.gi | 4 +- lib/primality.gd | 2 - lib/primality.gi | 65 -------------- src/boehm_gc.c | 7 +- src/listoper.c | 16 ++-- src/trans.cc | 14 ++-- tst/testinstall/coder.tst | 144 +++++++++++++------------------- tst/testinstall/interpreter.tst | 15 +--- 13 files changed, 175 insertions(+), 351 deletions(-) diff --git a/benchmark/transgrp/examine4 b/benchmark/transgrp/examine4 index d1f4d7258d..808ce0eb63 100755 --- a/benchmark/transgrp/examine4 +++ b/benchmark/transgrp/examine4 @@ -39,15 +39,15 @@ WR_POOL:=[[4,3,2,2],[6,11,2,3],[6,13,3,2],[8,44,2,4], [14,57,2,7],[14,61,7,2],[15,93,3,5],[15,102,5,3], [ 16, 1948, 2, 8 ], [ 16, 1947, 4, 4 ], [ 16, 1952, 8, 2 ], [ 18, 968, 2, 9 ], [ 18, 962, 3, 6 ], [ 18, 977, 6, 3 ], -[ 18, 981, 9, 2 ], [ 20, 1110, 2, 10 ], [ 20, 1101, 4, 5 ], -[ 20, 1111, 5, 4 ], [ 20, 1115, 10, 2 ], [ 21, 152, 3, 7 ], -[ 21, 162, 7, 3 ], [ 22, 53, 2, 11 ], [ 22, 57, 11, 2 ], -[ 24, 24979, 2, 12 ], [ 24, 24932, 3, 8 ], [ 24, 24944, 4, 6 ], -[ 24, 24984, 6, 4 ], [ 24, 24994, 8, 3 ], [ 24, 24998, 12, 2 ], +[ 18, 981, 9, 2 ], [ 20, 1110, 2, 10 ], [ 20, 1101, 4, 5 ], +[ 20, 1111, 5, 4 ], [ 20, 1115, 10, 2 ], [ 21, 152, 3, 7 ], +[ 21, 162, 7, 3 ], [ 22, 53, 2, 11 ], [ 22, 57, 11, 2 ], +[ 24, 24979, 2, 12 ], [ 24, 24932, 3, 8 ], [ 24, 24944, 4, 6 ], +[ 24, 24984, 6, 4 ], [ 24, 24994, 8, 3 ], [ 24, 24998, 12, 2 ], [ 25, 209, 5, 5 ], [ 26, 90, 2, 13 ], [ 26, 94, 13, 2 ], [ 27, 2380, 3, 9 ], -[ 27, 2390, 9, 3 ], [ 28, 1834, 2, 14 ], [ 28, 1798, 4, 7 ], -[ 28, 1848, 7, 4 ], [ 28, 1852, 14, 2 ], [ 30, 5696, 2, 15 ], -[ 30, 5666, 3, 10 ], [ 30, 5685, 5, 6 ], [ 30, 5695, 6, 5 ], +[ 27, 2390, 9, 3 ], [ 28, 1834, 2, 14 ], [ 28, 1798, 4, 7 ], +[ 28, 1848, 7, 4 ], [ 28, 1852, 14, 2 ], [ 30, 5696, 2, 15 ], +[ 30, 5666, 3, 10 ], [ 30, 5685, 5, 6 ], [ 30, 5695, 6, 5 ], [ 30, 5706, 10, 3 ], [ 30, 5710, 15, 2 ] ]; @@ -79,7 +79,7 @@ local m,o,i,s,no,te; if Number(l{[2..Length(l)]},i->Size(i)=s)>0 then no:=Normalizer(G,l[1]); if Index(G,no)>500 then - o:=GroupOnSubgroupsOrbit(G,l[1]); + o:=GroupOnSubgroupsOrbit(G,l[1]); else o:=List(RightTransversal(G,no),i->ConjugateGroup(l[1],i)); #o:=[]; @@ -165,7 +165,7 @@ local fun; if IsInt(gens) then return gens; fi; - + pnt:=[1..Minimum(Length(gens),Length(gl))]; if gl{pnt}<>gens then # then we have a difference @@ -361,7 +361,7 @@ Signatures:=function(sys,grp) local l,m,mm,i; m:=ShallowCopy(UnorderedSignatures(sys,grp)); l:=[1..Length(m)]; - for i in l do + for i in l do mm:=m[i]; mm:=mm{Difference(l,[i])}; Sort(mm); @@ -435,7 +435,7 @@ local mm,sign,z,p,m,l,d,i,s,r,j,k,freedom,f,b,Setze,Close; f:=Position(p,f[1]); flag:=false; # we know how to fill - for j in [1..d] do + for j in [1..d] do if m[j][i]=0 then Setze(i,j,f); fi; @@ -475,7 +475,7 @@ local mm,sign,z,p,m,l,d,i,s,r,j,k,freedom,f,b,Setze,Close; # if we force further entries if Length(arg)>2 then for i in arg[3] do - Setze(i[1],i[2],Position(z,i[3])); + Setze(i[1],i[2],Position(z,i[3])); od; fi; @@ -488,7 +488,7 @@ local mm,sign,z,p,m,l,d,i,s,r,j,k,freedom,f,b,Setze,Close; # fix numbers as long as this serves to select the additional rows/columns freedom:=l+1; - + while freedom1 and IsBound(sys.noouts) and sys.noouts and Size(g)=Size(anfst) then - p:=DiagonalGroup(sys,g,step); + p:=DiagonalGroup(sys,g,step); min:=First([1..Length(conj)],i->ConjugateGroup(anfst,conj[i])=p); min:=[min,p]; else @@ -943,7 +943,7 @@ local cand,ncand, # candidates in orbit fmin:=ClosureGroup(fmin,ConjugateGroup(Mno,rt)); #Print("|fg|=",Size(fg)," ind:",Index(cno,fmin),"\n"); - + conj:=Concatenation(conj,List( RightTransversalOp(cno,fmin),i->rt*i)); @@ -966,7 +966,7 @@ local cand,ncand, # candidates in orbit Info(InfoAli,3,Length(cand),"->",Length(ncand)); - Assert(1,not (typ=1 and not repres in ncand)); + Assert(1,not (typ=1 and not repres in ncand)); cand:=ncand; #"andere auf Set? #disabled duplicate removal -- too expensive @@ -1021,7 +1021,7 @@ local cand,ncand, # candidates in orbit if typ=1 then return true; else - #return MinGrpInd(sys.parent,cand,false)[2][1]; + #return MinGrpInd(sys.parent,cand,false)[2][1]; return Minimum(cand); fi; end; @@ -1200,16 +1200,16 @@ local asys,bsys,n,nest,i,l,z,u; fi; if typ=1 and Length(nest[2][1])Concatenation(asys.blocks{j})), - bsys,asys); + bsys,asys); u:=ker^z; u:=Canonize(u,bsys,bsys.wrg,bsys.b,allsdps[nest[1]],2); Add(l,u); @@ -1294,7 +1294,7 @@ local anz,g,d,no,s,o, Print("Warning: Bad luck\n"); fi; - else + else eastep:=false; dag:=false; isopc:=false; @@ -1407,12 +1407,12 @@ local anz,g,d,no,s,o, # At the moment we just recognize an outer group of size 2 if the # whole group is large - if Size(i)=1 and istrans and Size(fa)>20000 and Size(s)=Size(fa) + if Size(i)=1 and istrans and Size(fa)>20000 and Size(s)=Size(fa) and Length(out)=1 and ForAll(GeneratorsOfGroup(s), i->RepresentativeAction(fa,GeneratorsOfGroup(fa), List(GeneratorsOfGroup(fa),j->j^i),OnTuples)<>false) then - + out:=out[1]; # find the power of out that is inner aut:=2; @@ -1642,7 +1642,7 @@ local anz,g,d,no,s,o, for k in fid do fhom:=IsomorphismGroups(Image(j),f[k]); if fhom<>fail then - Add(l,[k,fhom]); + Add(l,[k,fhom]); fi; od; if Length(l)>0 then @@ -1662,7 +1662,7 @@ local anz,g,d,no,s,o, # all possible correspondents for k in faid[j] do - # we will need a further loop for automorphisms + # we will need a further loop for automorphisms for l in fsg[k[1]] do # the glueing homomorphism hom:=k[2]*l; @@ -1690,7 +1690,7 @@ fi; # check, whether necessary properties are fulfilled (if we want # this) if transflag=false - or (NewTransKgVLength(sys,gens,ntsiz,anz)<=anz + or (NewTransKgVLength(sys,gens,ntsiz,anz)<=anz and (levfalse then @@ -1736,7 +1736,7 @@ fi; if levLength(i)>=sys.globalsys.a) and @@ -1763,16 +1763,16 @@ fi; fi; - if - # we take it if: lower level + if + # we take it if: lower level levfalse and Set(MovedPoints(gens))<>[1..sys.a*lev] then Error("unmoved3!"); fi; - od; + od; od; Info(InfoAli,2,"|prae|=",Length(prae)); od; @@ -2032,7 +2032,7 @@ local g,b,i,bs,op,s,x,y,sx,sy,p,g2,xt,yt,t,bp,dom,r,u,v,pairs; if Length(arg)<3 then if x<15 then xt:=TransitiveGroup(x,TransitiveIdentification(t)); - else + else xt:=t; fi; if y<15 then @@ -2108,7 +2108,7 @@ local b,x,y,sx,sy,w,l,hom1,hom2,p,p1,q,m,r,ce,cx,cy,id,ie,u,v,op, l:=Length(GeneratorsOfGroup(sx)); for i in [1..y] do hom2:=GroupHomomorphismByImagesNC(sx,w,GeneratorsOfGroup(sx), - GeneratorsOfGroup(w){[l*(i-1)+1..l*i]}); + GeneratorsOfGroup(w){[l*(i-1)+1..l*i]}); Add(hom1,hom2); od; hom2:=GroupHomomorphismByImagesNC(sy,w,GeneratorsOfGroup(sy), @@ -2159,7 +2159,7 @@ local b,x,y,sx,sy,w,l,hom1,hom2,p,p1,q,m,r,ce,cx,cy,id,ie,u,v,op, # now get the classes of subgroups of w t:=TransitiveSubgroupsWreathProductSymm(w,x,y); - + l:=[]; for i in t do @@ -2173,7 +2173,7 @@ local b,x,y,sx,sy,w,l,hom1,hom2,p,p1,q,m,r,ce,cx,cy,id,ie,u,v,op, pq:=Filtered([1..Length(ie)],x->ie[x]=tx); if Length(pq)>0 then for p in pp do - for q in pq do + for q in pq do # it might embed, so take the 'clean' version r:=KuK(i,b,v[q],u[p]); r:=Subgroup(w,List(GeneratorsOfGroup(i),j->j^r)); @@ -2190,7 +2190,7 @@ local b,x,y,sx,sy,w,l,hom1,hom2,p,p1,q,m,r,ce,cx,cy,id,ie,u,v,op, else ce:=[()]; fi; - + if Length(cy[p])>0 then ce:=List(Cartesian(ce,cy[p]),i->i[1]*Image(hom2,i[2])); fi; @@ -2205,7 +2205,7 @@ local b,x,y,sx,sy,w,l,hom1,hom2,p,p1,q,m,r,ce,cx,cy,id,ie,u,v,op, fi; od; fi; - + m:=List(m,i->ConjugacyClassSubgroups(g,i)); r:=[]; for j in m do @@ -2274,7 +2274,7 @@ local pmp,b,s,u,w,n,g,op,oh,hom,omp,k,f,v,co,i,j,jj,new,cl,sug,nsug,fg,pi, Info(InfoAli,3,"reducing normalizer generators"); fi; g:=Group(op); #always make a new group to permit throwing away all permrep. - # information + # information oh:=ActionHomomorphism(g,b,OnSets,"surjective"); op:=Image(oh); @@ -2327,9 +2327,9 @@ local pmp,b,s,u,w,n,g,op,oh,hom,omp,k,f,v,co,i,j,jj,new,cl,sug,nsug,fg,pi, # A_n Error("A_n"); # special case: full wreath products - elif ForAny(WR_POOL,i->i[1]=dop and + elif ForAny(WR_POOL,i->i[1]=dop and i[2]=TransitiveIdentification(op)) then - u:=First(WR_POOL,i->i[1]=dop and + u:=First(WR_POOL,i->i[1]=dop and i[2]=TransitiveIdentification(op)); Info(InfoAli,2,"transitive subgroups of S(",u[3],") wr S(",u[4],")"); u:=TransitiveSubgroupsWreathProductSymm(op,u[3],u[4]); @@ -2351,7 +2351,7 @@ local pmp,b,s,u,w,n,g,op,oh,hom,omp,k,f,v,co,i,j,jj,new,cl,sug,nsug,fg,pi, #pi:=AsSubgroup(MySymmetricGroup(dop),op); pi:=op; v:=Normalizer(MySymmetricGroup(dop),pi); - if Index(v,pi)=2 and ForAny(WR_POOL,i->i[1]=dop and + if Index(v,pi)=2 and ForAny(WR_POOL,i->i[1]=dop and i[2]=TransitiveIdentification(v)) then u:=First(WR_POOL,i->i[1]=dop and i[2]=TransitiveIdentification(v)); Info(InfoAli,2,"transitive subgroups of NT of S(",u[3],") wr S(", @@ -2420,7 +2420,7 @@ local pmp,b,s,u,w,n,g,op,oh,hom,omp,k,f,v,co,i,j,jj,new,cl,sug,nsug,fg,pi, ino:=Normalizer(ino,co[j]); j:=j-1; od; - + else ino:=Normalizer(op,i); fi; @@ -2508,14 +2508,14 @@ local pmp,b,s,u,w,n,g,op,oh,hom,omp,k,f,v,co,i,j,jj,new,cl,sug,nsug,fg,pi, # # fusion only takes place in the normalizer (as k\lhd f) -# +# # if IsPcGroup(ino) then # # elif largedeg=true then # # else -# +# # else # for j in co do # cl:=ConjugacyClassSubgroups(ino,j); @@ -2610,7 +2610,7 @@ local el,oldnorm,cen,to,erg,Recurse; # now collect fusion classes orcl:=[]; while Length(o)>0 do - if true or Size(cen)/Size(o[1][1])<30000 + if true or Size(cen)/Size(o[1][1])<30000 or Index(cen,Centralizer(cen,o[1][1]))<30000 then bahn:=Orbit(cen,o[1][1]); cen2:=Filtered([2..Length(o)],i->ForAny(o[i],j->j in bahn)); @@ -2714,7 +2714,7 @@ local el,oldnorm,cen,to,erg,Recurse; Recurse(no,cen,to,el,oldnorm); - if Length(erg)>1 then + if Length(erg)>1 then erg:=[Minimum(erg)]; fi; return erg[1];; @@ -2769,7 +2769,7 @@ local no,grp,sys,v,nopa; # it's cheaper to take the transversal return MinimumGroupOnSubgroupsOrbit(grp,v,no); else - nopa:=SmallSubgroupCanonizer(sys,no,v); + nopa:=SmallSubgroupCanonizer(sys,no,v); if nopa=fail then if ForAny(AllBlocks(no),i->Length(i)RepresentativeAction(sys.kr,i,a)=fail) then @@ -3127,7 +3127,7 @@ local d,u,i,ii,homs,v,o,j,sz,a,sym,dd,prms,p,weg,itra,abi,jind,abig,ag; fi; od; - + #Exec("cp sdpstmp1 sdpstmp1.bak"); #PrintTo("sdpstmp1",u,"\n",weg,"\n"); @@ -3202,7 +3202,7 @@ local n,o,bl,i,b,flag,nt,op,fil,z,id,bo; #nt:=Subgroup(sys.parent,List(GeneratorsOfGroup(nt),i->i^z)); nt:=ConjugateGroup(nt,z); - + # and canonize Info(InfoAli,2,"Block canonizing"); TIMING.canon:=Runtime()-TIMING.canon; @@ -3228,7 +3228,7 @@ local n,o,bl,i,b,flag,nt,op,fil,z,id,bo; nt:=Subgroup(sys.parent,List(GeneratorsOfGroup(grp),i->i^z)); TIMING.ctest:=Runtime()-TIMING.ctest; Info(InfoAli,2,"Conj. test, "); - + # special case: regular groups (for which the conj. test # is extremely expensive) if IsRegular(nt,[1..sys.a*sys.b]) then @@ -3395,7 +3395,7 @@ local i,j,l,p,sup,dom,use,lcl; od; p:=List(p,i->TransitiveIdentification(Representative(lcl[i]))); - return p; + return p; end; # get the minimal transitive groups whose point stabilizer is divides by siz @@ -3483,12 +3483,12 @@ local bls, # block size for i in p do Add(n,TransitiveGroup(bls,TransitiveIdentification(i))); if Size(i)IsTransitive(j,[1..bls]) and not IsPrimitive(j,[1..bls])); for j in nt do id:=TransitiveIdentification(j); - if not id in nids and + if not id in nids and # index divides one stab size ForAny(indices,x->x mod Index(i,j)=0) then Add(nids,id); @@ -3532,7 +3532,7 @@ local bls, # block size Info(InfoAli,1,"not primitive, actions changed from ",MINTRANSIND[bla], " to ",minops); minops:=List(minops,i->TransitiveGroup(bla,i)); - + else # test, whether it is sufficient to use for invariants: minops:=trueminops; @@ -3596,7 +3596,7 @@ local bls, # block size # get all characteristic subgroups which are transitive and index # coprime to sizes of minimal transitive factor groups nt:=NormalSubgroups(i); - nt:=Filtered(nt,j->IsAbelian(j) and Index(i,j)>1 + nt:=Filtered(nt,j->IsAbelian(j) and Index(i,j)>1 and IsTransitive(j,MovedPoints(i)) and ForAll(minops,k->Gcd(Index(i,j),Size(k))=1)); nt:=Filtered(nt,j->IsCharacteristicSubgroup(i,j)); @@ -3612,7 +3612,7 @@ local bls, # block size Info(InfoAli,1,"Get actgroups bottom"); nt:=nt[1]; # will give the smallest number of sdps # construct the sdp's for nt - actgroups:=TGInvariantSubgroups(sys,GeneratorsOfGroup(nt),trueminops); + actgroups:=TGInvariantSubgroups(sys,GeneratorsOfGroup(nt),trueminops); Info(InfoAli,1,"Get actgroups top"); # get the groups which act on them, select those whose block # action is small @@ -3694,7 +3694,7 @@ TIMING.sdp:=Runtime()-TIMING.sdp; #Auskommentiert, da: tests already for no smaller local operation !!!! #Print("TRANSFLAG!\n"); #gsys.transflag:=true; - neu:=ConstructSubdirectProducts(gsys,lplbs[j]); + neu:=ConstructSubdirectProducts(gsys,lplbs[j]); Info(InfoAli,3,"supos=",neu); # remember all for future tests @@ -3827,7 +3827,7 @@ TIMING.cheat:=Runtime()-TIMING.cheat; # test, whether we might need automorphism fuse if ForAny(blopid,i->i=j) then flag:=1; - fi; + fi; else Info(InfoAli,2,"inappropriate operation"); fi; @@ -3853,7 +3853,7 @@ TIMING.cheat:=Runtime()-TIMING.cheat; # we have to test g^(an)=u, i.e. a has to be determined only up to # right multiplication by the normalizer -- that is left coset # representatives of the normalizer - l:=RightTransversal(au,l); + l:=RightTransversal(au,l); l:=List(l,Inverse); s:=[]; @@ -3867,7 +3867,7 @@ TIMING.cheat:=Runtime()-TIMING.cheat; Info(InfoAli,1,"old 'cheating' group"); fi; od; - else + else if Length(r)=0 then Info(InfoAli,1,"no blow-ups"); elif Length(r)=1 then diff --git a/dev/gapmacro2gapdoc.g b/dev/gapmacro2gapdoc.g index 512d15d091..3219338205 100755 --- a/dev/gapmacro2gapdoc.g +++ b/dev/gapmacro2gapdoc.g @@ -65,13 +65,13 @@ ## (:digraph in vi). ## ## These are the proposed steps for translating a manual. -## +## ## 1. By hand: ## Copy the old style `doc/manual.six' file to `doc/manual.six.old' ## (Note that processing the GAPDoc format manual will create ## `doc/manual.six' but in GAPDoc format, which is not supported by ## the functions for switching to GAPDoc.) -## +## ## 2. By hand: ## Create a new main file `main.xml' that will replace ## the old main file `manual.tex'. @@ -81,16 +81,16 @@ ## \FrontMatter -> ## for chapters: \Input -> <#Include> ## etc.) -## +## ## 3. By hand: ## Create `makedocrel.g' that will replace `buildman.config'. ## (Copy it from an existing package that uses GAPDoc; ## the call to `MakeGAPDocDoc' is the main ingredient.) -## +## ## 4. Semi-automatically: ## Create `doc/*.xml' files from the corresponding `doc/*.msk' files, ## by calling the function `TranslateMSK2XML' for each `doc/*.msk' file. -## +## ## 5. Semi-automatically: ## Create `lib/*.g*.new' files corresponding to `lib/*.g*' files, ## by calling the function `TranslateLib2XML' for each relevant @@ -99,13 +99,13 @@ ## The code in the old and the new file should be unchanged, ## just the documentation is rewritten. ## (Test this!) -## +## ## 6. Read the file `makedocrel.g', in order to process the documentation ## with GAPDoc, and correct the errors reported by GAPDoc. ## (Since the main manuals were translated, GAPDoc was improved a lot ## w.r.t. debugging, so this should be much easier than it was at the ## beginning of 2007.) -## +## ## 7. By hand: ## Edit the new files, in order to ## - improve formulations around @@ -114,7 +114,7 @@ ## - reformat the paragraphs, ## - fix places that were not handled optimally. ## Check for `???' in html files, which indicate broken references. -## +## ## 8. By hand: ## Start using GAPDoc's facilities: ## - insert "Where" in , @@ -123,7 +123,7 @@ ## - change the bibliography to the XML based format, ## - introduce subsections (beyond ) for structuring purposes, ## - ... -## +## ## 9. By hand: ## - Convince yourself that GAP code was not changed by the conversions. ## - Convince yourself that nothing from the old version of the manual @@ -340,7 +340,7 @@ RewriteText:= function( str ) [ [ "\\Declaration{", "}" ], [ "<#Include Label=", ">" ] ], [ [ "\\Mailto{", "}" ], [ "", "" ] ], [ [ "\n#T", "\n" ], [ "\n\n" ] ], - ]; + ]; for pair in replacementpairs do newstr:= ""; @@ -413,7 +413,7 @@ RewriteText:= function( str ) [ "for", "for" ], [ "while", "while" ], # [ "%\n", "\n" ], - ]; + ]; for pair in replacements do str:= ReplacedString( str, pair[1], pair[2] ); @@ -531,7 +531,7 @@ SplitLibFile:= function( filename ) code:= not code; else Add( partlines, line ); - fi; + fi; od; return parts; end; @@ -554,10 +554,10 @@ TranslatedIndentedText:= function( str ) Append( newstr, pair[2][1] ); for i in [ 2 .. Length( pair[2] ) ] do Append( newstr, cand[3] ); - Append( newstr, pair[2][i] ); + Append( newstr, pair[2][i] ); od; str:= Concatenation( newstr, cand[4] ); - fi; + fi; until cand = fail; od; @@ -565,7 +565,7 @@ TranslatedIndentedText:= function( str ) str:= ReplacedString( str, "\n## ", "\n" ); str:= ReplacedString( str, "\n## \n", "\n\n" ); str:= ReplacedString( str, "\n##\n", "\n\n" ); - + # translate str:= str{ [ 2 .. Length( str )-1 ] }; str:= Concatenation( "\n", TranslateText( str ), "\n" ); @@ -638,7 +638,7 @@ RewriteNonCodePart:= function( str, filename ) "\n##\n", "## <#GAPDoc Label=\"", name, "\">\n", "## \n" ); - fi; + fi; Append( declstr, Concatenation( "## \n" ) ); startpos:= pos2-1; @@ -922,7 +922,7 @@ end; TranslateLib2XML:= function( filename ) local str, entry, size, target; - + str:= ""; for entry in SplitLibFile( filename ) do if str <> "" then diff --git a/dev/manualutils.g b/dev/manualutils.g index 04d034f1d3..5a76c830f8 100644 --- a/dev/manualutils.g +++ b/dev/manualutils.g @@ -181,7 +181,7 @@ PrintInfoAboutManualChapters:= function( pathtodoc, main, files, chapnrs ) ", line ", pos[2], "\n" ); od; fi; - + # Compute the subset of elements whose contents are keywords, # and which should probably (but not necessarily!) be replaced by # the corresponding elements. @@ -197,7 +197,7 @@ PrintInfoAboutManualChapters:= function( pathtodoc, main, files, chapnrs ) ", line ", pos[2], "\n" ); od; fi; - + od; #T perhaps return all the computed information? end; @@ -219,7 +219,7 @@ OverviewOfChaptersForProofreadingForm:= function( pathtodoc, main, files ) str:= ComposedDocument( "GAPDoc", Directory( pathtodoc ), main, files, true ); xmltree:= ParseTreeXMLString( str[1], str[2] ); - elms:= List( XMLElements( xmltree, "Chapter" ), + elms:= List( XMLElements( xmltree, "Chapter" ), x -> XMLElements( x, [ "Heading" ] )[1] ); filecontents:= ""; @@ -299,7 +299,7 @@ ChainedExamples:= function( pathtodoc, main, files ) end; # finds the following occurrences in the ref. manual: -# +# # [ [ "\n

\n", [ "./mloop.xml", 231 ] ], # done # [ "\n

\n", [ "./streams.xml", 131 ] ], # done # [ "\n

\n", [ "./word.xml", 117 ] ], # done @@ -321,9 +321,9 @@ end; # [ "\n

\n", [ "./algebra.xml", 331 ] ], # done # [ "\n

\n", [ "./ctbl.xml", 1241 ] ], # done # [ "\n

\n", [ "./ctbl.xml", 1275 ] ], # done -# [ "\n

\n", [ "./mloop.xml", 423 ] ], -# [ "\n

\n", [ "./lists.xml", 708 ] ], -# [ "\n

\n", [ "./grplib.xml", 673 ] ], +# [ "\n

\n", [ "./mloop.xml", 423 ] ], +# [ "\n

\n", [ "./lists.xml", 708 ] ], +# [ "\n

\n", [ "./grplib.xml", 673 ] ], # [ "\n

\n", [ "./../../lib/process.gd", 82 ] ], # done # [ "\n

\n", [ "./../../lib/process.gd", 89 ] ] ] # done diff --git a/hpcgap/lib/helpbase.gi b/hpcgap/lib/helpbase.gi index 921d65a236..2599559156 100644 --- a/hpcgap/lib/helpbase.gi +++ b/hpcgap/lib/helpbase.gi @@ -752,9 +752,9 @@ end); ############################################################################# ## -#F HELP_SHOW_BOOKS( ignored... ) . . . . . . . . . . . show available books +#F HELP_SHOW_BOOKS() . . . . . . . . . . . . . . . . . show available books ## -InstallGlobalFunction(HELP_SHOW_BOOKS, function( arg ) +InstallGlobalFunction(HELP_SHOW_BOOKS, function() local books; atomic readonly HELP_REGION do diff --git a/hpcgap/lib/primality.gi b/hpcgap/lib/primality.gi index f7ee40ad25..16294ad5ee 100644 --- a/hpcgap/lib/primality.gi +++ b/hpcgap/lib/primality.gi @@ -347,71 +347,6 @@ end); # while Jacobi( P^2-4, N ) <> -1 do P:=(P+1) mod N; if P = 2 then return fail; fi; od; # return [ (P^2-4) mod N, P, 1 ]; #end; -#InstallGlobalFunction(IsBPSWLucasPseudoPrime, -#function(N) -# local params, func, lucas; -# if N = 2 then return true; fi; -# if IsSquareInt(N) or IsEvenInt(N) then return false; fi; -# if ValueOption("BPSWLucasParameters") = fail -# then func:=BPSWLucasParameters_GAP; -# else func:=ValueOption("BPSWLucasParameters"); -# fi; -# if ValueOption("BPSWLucasTest") = fail then -# if func = BPSWLucasParameters_GAP -# then lucas:=function(N,D,P) return TraceModQF(P,N+1,N) = [2,P]; end; -# else lucas:=IsLucasPseudoPrimeDP; -# fi; -# else lucas:=ValueOption("BPSWLucasTest"); -# fi; -# params := CALL_FUNC_LIST(func,[N]); -# if Jacobi(params[1],N) = 0 and params[1] < N and 0 < params[1] then return false; fi; -# return CALL_FUNC_LIST(lucas,[N, params[1], params[2]]); -#end); - -############################################################################## -## -#F IsLucasPseudoPrimeDP(N,D,P) - Check if N is a Lucas pseudoprime for -## x^2+P*x+(P^2-D)/4. D must be a nonsquare mod N, and N must be odd or prime. -## -############################################################################## -InstallGlobalFunction(IsLucasPseudoPrimeDP, -function(N,D,P) - local Q; - if N = 2 then return true; fi; - Q := (P^2-D)/4 mod N; - if not ( IsOddInt(N) and 0 <> Q mod N and Jacobi(D,N) = -1 ) then Error(); fi; - return IsOddInt(N) and 0 <> Q mod N and Jacobi(D,N) = -1 and 0 = LucasMod(P,Q,N,N+1)[1]; -end); - -############################################################################## -## -#F IsStrongLucasPseudoPrimeDP(N,D,P) - Check if N is a strong Lucas -## pseudoprime for x^2+P*x+(P^2-D)/4. N must be odd or prime. -## -############################################################################## -InstallGlobalFunction(IsStrongLucasPseudoPrimeDP, -function(N,D,P) - local Q,d,s,J,L,r,Qi; - if N = 2 then return true; fi; - if N in [-1,0,1] then return false; fi; - if not ( IsOddInt(N) and GcdInt(N,D)=1 ) then return false; fi; - Q := (P^2-D)/4 mod N; - J := Jacobi(D,N); - d := N - J; s:=0; while IsEvenInt(d) do s:=s+1; d:=d/2; od; # Now N-(D/N) = 2^s * d, d odd - L := LucasMod(P,Q,N,d); - # Does n divide U_d ? - if L[1] = 0 then return true; fi; - # Does n divide V_{2^r d} for some r=0,1,...,s-1 ? - Qi := PowerModInt(Q,d,N); - for r in [0..s-1] do - if L[2] = 0 then return true; fi; - # L is [Ui,Vi], make it [U2i,V2i] = [ Ui*Vi, Vi^2 - 2Q^i], where i=2^s d - L[1] := L[1]*L[2] mod N; - L[2] := (L[2]^2 - 2*Qi) mod N; - Qi := Qi*Qi mod N; - od; - return false; -end); ############################################################################## ## diff --git a/lib/helpbase.gi b/lib/helpbase.gi index f3cf5a8f04..15dcd0edad 100644 --- a/lib/helpbase.gi +++ b/lib/helpbase.gi @@ -738,9 +738,9 @@ end); ############################################################################# ## -#F HELP_SHOW_BOOKS( ignored... ) . . . . . . . . . . . show available books +#F HELP_SHOW_BOOKS() . . . . . . . . . . . . . . . . . show available books ## -InstallGlobalFunction(HELP_SHOW_BOOKS, function( arg ) +InstallGlobalFunction(HELP_SHOW_BOOKS, function() local books; books := [" Table of currently available help books", diff --git a/lib/primality.gd b/lib/primality.gd index 1f6ca240be..b8787d957c 100644 --- a/lib/primality.gd +++ b/lib/primality.gd @@ -97,8 +97,6 @@ DeclareGlobalFunction("IsSquareInt"); DeclareGlobalFunction("IsStrongPseudoPrimeBaseA"); DeclareGlobalFunction("IsBPSWLucasPseudoPrime"); -DeclareGlobalFunction("IsLucasPseudoPrimeDP"); -DeclareGlobalFunction("IsStrongLucasPseudoPrimeDP"); DeclareGlobalFunction("IsBPSWPseudoPrime"); DeclareGlobalFunction("IsBPSWPseudoPrime_VerifyCorrectness"); diff --git a/lib/primality.gi b/lib/primality.gi index 63ff2bb37c..b5a288c320 100644 --- a/lib/primality.gi +++ b/lib/primality.gi @@ -347,71 +347,6 @@ end); # while Jacobi( P^2-4, N ) <> -1 do P:=(P+1) mod N; if P = 2 then return fail; fi; od; # return [ (P^2-4) mod N, P, 1 ]; #end; -#InstallGlobalFunction(IsBPSWLucasPseudoPrime, -#function(N) -# local params, func, lucas; -# if N = 2 then return true; fi; -# if IsSquareInt(N) or IsEvenInt(N) then return false; fi; -# if ValueOption("BPSWLucasParameters") = fail -# then func:=BPSWLucasParameters_GAP; -# else func:=ValueOption("BPSWLucasParameters"); -# fi; -# if ValueOption("BPSWLucasTest") = fail then -# if func = BPSWLucasParameters_GAP -# then lucas:=function(N,D,P) return TraceModQF(P,N+1,N) = [2,P]; end; -# else lucas:=IsLucasPseudoPrimeDP; -# fi; -# else lucas:=ValueOption("BPSWLucasTest"); -# fi; -# params := CALL_FUNC_LIST(func,[N]); -# if Jacobi(params[1],N) = 0 and params[1] < N and 0 < params[1] then return false; fi; -# return CALL_FUNC_LIST(lucas,[N, params[1], params[2]]); -#end); - -############################################################################## -## -#F IsLucasPseudoPrimeDP(N,D,P) - Check if N is a Lucas pseudoprime for -## x^2+P*x+(P^2-D)/4. D must be a nonsquare mod N, and N must be odd or prime. -## -############################################################################## -InstallGlobalFunction(IsLucasPseudoPrimeDP, -function(N,D,P) - local Q; - if N = 2 then return true; fi; - Q := (P^2-D)/4 mod N; - if not ( IsOddInt(N) and 0 <> Q mod N and Jacobi(D,N) = -1 ) then Error(); fi; - return IsOddInt(N) and 0 <> Q mod N and Jacobi(D,N) = -1 and 0 = LucasMod(P,Q,N,N+1)[1]; -end); - -############################################################################## -## -#F IsStrongLucasPseudoPrimeDP(N,D,P) - Check if N is a strong Lucas -## pseudoprime for x^2+P*x+(P^2-D)/4. N must be odd or prime. -## -############################################################################## -InstallGlobalFunction(IsStrongLucasPseudoPrimeDP, -function(N,D,P) - local Q,d,s,J,L,r,Qi; - if N = 2 then return true; fi; - if N in [-1,0,1] then return false; fi; - if not ( IsOddInt(N) and GcdInt(N,D)=1 ) then return false; fi; - Q := (P^2-D)/4 mod N; - J := Jacobi(D,N); - d := N - J; s:=0; while IsEvenInt(d) do s:=s+1; d:=d/2; od; # Now N-(D/N) = 2^s * d, d odd - L := LucasMod(P,Q,N,d); - # Does n divide U_d ? - if L[1] = 0 then return true; fi; - # Does n divide V_{2^r d} for some r=0,1,...,s-1 ? - Qi := PowerModInt(Q,d,N); - for r in [0..s-1] do - if L[2] = 0 then return true; fi; - # L is [Ui,Vi], make it [U2i,V2i] = [ Ui*Vi, Vi^2 - 2Q^i], where i=2^s d - L[1] := L[1]*L[2] mod N; - L[2] := (L[2]^2 - 2*Qi) mod N; - Qi := Qi*Qi mod N; - od; - return false; -end); ############################################################################## ## diff --git a/src/boehm_gc.c b/src/boehm_gc.c index a0bbd942aa..0235f5bc3e 100644 --- a/src/boehm_gc.c +++ b/src/boehm_gc.c @@ -544,14 +544,9 @@ UInt ResizeBag(Bag bag, UInt new_size) } -/***************************************************************************** -** The following functions are not required respectively supported, so empty -** implementations are provided -** -*/ - void InitGlobalBag(Bag * addr, const Char * cookie) { + // No need to track globals with Boehm GC } void SwapMasterPoint(Bag bag1, Bag bag2) diff --git a/src/listoper.c b/src/listoper.c index a30e7b7af9..08ef0484b9 100644 --- a/src/listoper.c +++ b/src/listoper.c @@ -1758,8 +1758,8 @@ FuncADD_TO_LIST_ENTRIES_PLIST_RANGE(Obj self, Obj list, Obj range, Obj x) ** ** Examples: x^2y^3 < y^7, x^4 y^5 < x^3 y^6 */ -static Obj FuncMONOM_TOT_DEG_LEX ( Obj self, Obj u, Obj v ) { - +static Obj FuncMONOM_TOT_DEG_LEX(Obj self, Obj u, Obj v) +{ Int4 i, lu, lv; Obj total; @@ -1835,8 +1835,8 @@ static Obj FuncMONOM_TOT_DEG_LEX ( Obj self, Obj u, Obj v ) { ** ** Examples: x^2y^3 < y^7, x^4 y^5 < x^3 y^6 */ -static Obj FuncMONOM_GRLEX( Obj self, Obj u, Obj v ) { - +static Obj FuncMONOM_GRLEX(Obj self, Obj u, Obj v) +{ Int4 i, lu, lv; Obj total,ai,bi; @@ -1902,8 +1902,8 @@ static Obj FuncMONOM_GRLEX( Obj self, Obj u, Obj v ) { ** representation. This is time critical and thus in the kernel. ** the function assumes that all lists are plists. */ -static Obj FuncZIPPED_SUM_LISTS( Obj self, Obj z1, Obj z2, Obj zero, Obj f ) { - +static Obj FuncZIPPED_SUM_LISTS(Obj self, Obj z1, Obj z2, Obj zero, Obj f) +{ Int l1,l2,i; Int i1,i2; Obj sum,x,y; @@ -1981,8 +1981,8 @@ static Obj FuncZIPPED_SUM_LISTS( Obj self, Obj z1, Obj z2, Obj zero, Obj f ) { ** implements the multiplication of monomials. Both must be plain lists ** of integers. */ -static Obj FuncMONOM_PROD( Obj self, Obj m1, Obj m2 ) { - +static Obj FuncMONOM_PROD(Obj self, Obj m1, Obj m2) +{ UInt a,b,l1,l2,i1,i2,i; Obj e,f,c,prod; diff --git a/src/trans.cc b/src/trans.cc index f50a2cfb53..891a858598 100644 --- a/src/trans.cc +++ b/src/trans.cc @@ -4121,7 +4121,8 @@ static StructGVarFilt GVarFilts[] = { }; -/****************************************************************************** +/**************************************************************************** +** *V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export */ static StructGVarFunc GVarFuncs[] = { @@ -4183,7 +4184,8 @@ static StructGVarFunc GVarFuncs[] = { }; -/****************************************************************************** +/**************************************************************************** +** *F InitKernel( ) . . . . . . . . initialise kernel data structures */ static Int InitKernel(StructInitInfo * module) @@ -4271,7 +4273,8 @@ static Int InitKernel(StructInitInfo * module) return 0; } -/****************************************************************************** +/**************************************************************************** +** *F InitLibrary( ) . . . . . . . initialise library data structures */ static Int InitLibrary(StructInitInfo * module) @@ -4285,9 +4288,8 @@ static Int InitLibrary(StructInitInfo * module) // code which would not otherwise be accessible, since no other // transformation created in this file is a T_TRANS4 unless its internal // degree is > 65536. Such transformation can be created by packages with - // a - // kernel module, and so we introduce the next transformation for testing - // purposes. + // a kernel module, and so we introduce the next transformation for + // testing purposes. Obj ID_TRANS4 = NEW_TRANS4(0); AssReadOnlyGVar(GVarName("ID_TRANS4"), ID_TRANS4); diff --git a/tst/testinstall/coder.tst b/tst/testinstall/coder.tst index 9b24d64773..a625d73333 100644 --- a/tst/testinstall/coder.tst +++ b/tst/testinstall/coder.tst @@ -1,3 +1,4 @@ +#@local f,r,l # # Tests for the GAP coder logic. # @@ -8,6 +9,29 @@ # gap> START_TEST("coder.tst"); +# +# non boolean expression as condition +# +gap> function() if 1 then fi; end(); +Error, must be 'true' or 'false' (not the integer 1) + +# +# return is allowed in functions +# +gap> function() return; end(); +gap> function() return 1; end(); +1 + +# +# help system +# +gap> function() ?qwert_asdf end; +Syntax error: '?' cannot be used in this context in stream:1 +function() ?qwert_asdf end; + ^^^^^^^^^^^^^^^^ +Syntax error: while parsing a function: statement or 'end' expected in stream:\ +2 + # # function call with options # @@ -26,71 +50,47 @@ gap> ({}-> f(1 : ("a") := 23 ) )(); # # records # -gap> function() -> local r; -> r := rec(a:=1); -> Display(r); -> r.a := 1; -> Display(r.a); -> Display(IsBound(r.a)); -> Unbind(r.a); -> return r; -> end(); -rec( - a := 1 ) +gap> r := ({}-> rec(a:=1) )(); +rec( a := 1 ) + +# +gap> function() r.a := 1; end(); +gap> ({}-> r.a )(); 1 +gap> ({}-> IsBound(r.a) )(); true +gap> function() Unbind(r.a); end(); +gap> ({}-> r )(); rec( ) # -gap> function() -> local r; -> r := rec(a:=1); -> Display(r); -> r!.a := 1; -> Display(r!.a); -> Display(IsBound(r!.a)); -> Unbind(r!.a); -> return r; -> end(); -rec( - a := 1 ) +gap> function() r!.a := 1; end(); +gap> ({}-> r!.a )(); 1 +gap> ({}-> IsBound(r!.a) )(); true +gap> function() Unbind(r!.a); end(); +gap> ({}-> r )(); rec( ) # -gap> function() -> local r; -> r := rec(("a"):=1); -> Display(r); -> r.("a") := 1; -> Display(r.("a")); -> Display(IsBound(r.("a"))); -> Unbind(r.("a")); -> return r; -> end(); -rec( - a := 1 ) +gap> function() r.("a") := 1; end(); +gap> ({}-> r.("a") )(); 1 +gap> ({}-> IsBound(r.("a")) )(); true +gap> function() Unbind(r.("a")); end(); +gap> ({}-> r )(); rec( ) # -gap> function() -> local r; -> r := rec(("a"):=1); -> Display(r); -> r!.("a") := 1; -> Display(r!.("a")); -> Display(IsBound(r!.("a"))); -> Unbind(r!.("a")); -> return r; -> end(); -rec( - a := 1 ) +gap> function() r!.("a") := 1; end(); +gap> ({}-> r!.("a") )(); 1 +gap> ({}-> IsBound(r!.("a")) )(); true +gap> function() Unbind(r!.("a")); end(); +gap> ({}-> r )(); rec( ) # test special case in CodeRecExprBeginElmExpr @@ -110,32 +110,26 @@ rec( 42 := 3, 43 := 4, x := 1, y := 2 ) gap> r := Objectify(NewType(NewFamily("MockFamily"), IsComponentObjectRep), rec());; # -gap> function() -> r!.a := 1; -> Display(r!.a); -> Display(IsBound(r!.a)); -> Unbind(r!.a); -> Display(IsBound(r!.a)); -> end(); +gap> function() r!.a := 1; end(); +gap> ({}-> r!.a )(); 1 +gap> ({}-> IsBound(r!.a) )(); true -false +gap> function() Unbind(r!.a); end(); # -gap> function() -> r!.("a") := 1; -> Display(r!.("a")); -> Display(IsBound(r!.("a"))); -> Unbind(r!.("a")); -> Display(IsBound(r!.("a"))); -> end(); +gap> function() r!.("a") := 1; end(); +gap> ({}-> r!.("a") )(); 1 +gap> ({}-> IsBound(r!.("a")) )(); true -false +gap> function() Unbind(r!.("a")); end(); # # lists # +gap> l := ({}-> [1,2,3] )(); +[ 1, 2, 3 ] gap> function() > local l; > l:=[1,2,3]; @@ -221,17 +215,6 @@ Error, PosObj Assignment: must be a positive small integer (not the\ # gap> l := Objectify(NewType(NewFamily("MockFamily"), IsPositionalObjectRep),[]);; -# -gap> l![1] := 42; -42 -gap> l![1]; -42 -gap> IsBound(l![1]); -true -gap> Unbind(l![1]); -gap> IsBound(l![1]); -false - # gap> function() > l![1] := 42; @@ -263,17 +246,6 @@ Error, PosObj Assignment: must be a positive small integer (not the\ # gap> l := Objectify(NewType(NewFamily("MockFamily"), IsAtomicPositionalObjectRep),[23]);; -# -gap> l![1] := 42; -42 -gap> l![1]; -42 -gap> IsBound(l![1]); -true -gap> Unbind(l![1]); -gap> IsBound(l![1]); -false - # gap> function() > l![1] := 42; diff --git a/tst/testinstall/interpreter.tst b/tst/testinstall/interpreter.tst index e13308ab72..f10a18035d 100644 --- a/tst/testinstall/interpreter.tst +++ b/tst/testinstall/interpreter.tst @@ -1,3 +1,4 @@ +#@local f,r,l # # Tests for the GAP interpreter logic. # @@ -14,14 +15,6 @@ gap> START_TEST("interpreter.tst"); gap> if 1 then fi; Error, must be 'true' or 'false' (not the integer 1) -# -# 'quit' inside functions -# -gap> function() quit; end; -Syntax error: 'quit;' cannot be used in this context in stream:1 -function() quit; end; - ^^^^ - # # return is not allowed in interpreter # @@ -30,12 +23,6 @@ gap> return; gap> return 1; 'return' must not be used in file read-eval loop -# -# isolated quit and QUIT are ignore in test files -# -gap> quit; -gap> QUIT; - # # help system # From 739efd41eacabb56c44c1003cca812ccacce3c94 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 18 May 2026 10:58:45 +0200 Subject: [PATCH 069/123] ci: trigger PackageDistro from PR comments (#6379) Add an issue_comment workflow for pull requests that accepts the exact bot command, checks collaborator permissions, and dispatches the PackageDistro workflow for the PR head. The workflow also keeps a bot comment on the PR up to date so rejected requests get a clear reply and accepted requests are replaced by the later PackageDistro result. AI assistance: Codex implemented the workflow and verification updates. Co-authored-by: Codex --- .github/workflows/package-distro-trigger.yml | 186 +++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 .github/workflows/package-distro-trigger.yml diff --git a/.github/workflows/package-distro-trigger.yml b/.github/workflows/package-distro-trigger.yml new file mode 100644 index 0000000000..7f4aafe11a --- /dev/null +++ b/.github/workflows/package-distro-trigger.yml @@ -0,0 +1,186 @@ +# +# This workflow lets GAP collaborators request a full PackageDistro test run +# from a GAP pull request comment. +# +# Usage: +# 1. Open a pull request on gap-system/gap. +# 2. Comment exactly: +# @gap-package-distribution-bot test +# 3. The workflow checks that the commenter has at least triage permission, +# creates or updates a marker comment on the PR, and dispatches the +# PackageDistro `test-gap-pr.yml` workflow. +# 4. PackageDistro tests the current PR head against all packages and updates +# the same marker comment with the result. +# +name: PackageDistro PR trigger + +on: + issue_comment: + types: [created] + +permissions: + contents: read + issues: write + pull-requests: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.issue.number }} + cancel-in-progress: false + +jobs: + dispatch-package-distro: + name: Dispatch PackageDistro test + if: ${{ github.event.issue.pull_request != null }} + runs-on: ubuntu-latest + steps: + - name: Check command + id: command + env: + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + expected='@gap-package-distribution-bot test' + if [[ "${COMMENT_BODY}" == "${expected}" ]]; then + echo "matches=true" >> "$GITHUB_OUTPUT" + else + echo "matches=false" >> "$GITHUB_OUTPUT" + fi + + - uses: actions/create-github-app-token@v3 + id: gap-token + if: ${{ steps.command.outputs.matches == 'true' }} + with: + client-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: gap-system + repositories: gap + + - name: Check commenter permission + id: permission + if: ${{ steps.command.outputs.matches == 'true' }} + env: + GH_TOKEN: ${{ steps.gap-token.outputs.token }} + REPO: ${{ github.repository }} + ACTOR: ${{ github.event.comment.user.login }} + run: | + api_url="https://api.github.com/repos/${REPO}/collaborators/${ACTOR}/permission" + http_code=$( + curl -sSL \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + -o permission.json \ + -w '%{http_code}' \ + "${api_url}" + ) + if [[ "${http_code}" == "200" ]]; then + permission=$(jq -r '.permission // "none"' permission.json) + else + permission="none" + fi + echo "permission=${permission}" >> "$GITHUB_OUTPUT" + case "${permission}" in + admin|maintain|write|triage) + echo "authorized=true" >> "$GITHUB_OUTPUT" + ;; + *) + echo "authorized=false" >> "$GITHUB_OUTPUT" + ;; + esac + + - name: Find prior bot comment + id: find-comment + if: ${{ steps.command.outputs.matches == 'true' }} + uses: peter-evans/find-comment@v4 + with: + token: ${{ steps.gap-token.outputs.token }} + issue-number: ${{ github.event.issue.number }} + body-includes: "" + + - name: Reply to unauthorized request + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized != 'true' + }} + uses: peter-evans/create-or-update-comment@v5 + with: + token: ${{ steps.gap-token.outputs.token }} + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.issue.number }} + edit-mode: replace + body: | + + `@gap-package-distribution-bot test` may only be used by GAP collaborators with at least triage access. + + - uses: actions/create-github-app-token@v3 + id: pkgdistro-token + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized == 'true' + }} + with: + client-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: gap-system + repositories: PackageDistro + + - name: Acknowledge accepted request + id: acknowledge-request + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized == 'true' + }} + uses: peter-evans/create-or-update-comment@v5 + with: + token: ${{ steps.gap-token.outputs.token }} + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.issue.number }} + edit-mode: replace + body: | + + Accepted `@gap-package-distribution-bot test`. + + PackageDistro was asked to run the full package test suite against the current head of this pull request. This comment will be updated with the result. + + - name: Dispatch PackageDistro workflow + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized == 'true' + }} + env: + GH_TOKEN: ${{ steps.pkgdistro-token.outputs.token }} + PR_URL: ${{ github.event.issue.html_url }} + COMMENT_ID: ${{ steps.acknowledge-request.outputs.comment-id }} + REQUESTER: ${{ github.event.comment.user.login }} + COMMAND: ${{ github.event.comment.body }} + run: | + comment_id_json=null + if [[ -n "${COMMENT_ID}" ]]; then + comment_id_json=${COMMENT_ID} + fi + jq -n \ + --arg ref main \ + --arg pr_url "${PR_URL}" \ + --arg requester "${REQUESTER}" \ + --arg command "${COMMAND}" \ + --arg callback_repo "${GITHUB_REPOSITORY}" \ + --arg callback_pr_number "${{ github.event.issue.number }}" \ + --argjson callback_comment_id "${comment_id_json}" \ + '{ + ref: $ref, + inputs: { + "gap-pr-url": $pr_url, + "callback-repo": $callback_repo, + "callback-pr-number": $callback_pr_number, + requester: $requester, + command: $command + } + (if $callback_comment_id == null then {} else {"callback-comment-id": ($callback_comment_id | tostring)} end) + }' > payload.json + curl -fsSL \ + -X POST \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/gap-system/PackageDistro/actions/workflows/test-gap-pr.yml/dispatches \ + -d @payload.json From 18bfe078ed51371fa66a2ed710904615f589f7d3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 18 May 2026 11:10:33 +0200 Subject: [PATCH 070/123] CI: fix package distro trigger --- .github/workflows/package-distro-trigger.yml | 24 ++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/package-distro-trigger.yml b/.github/workflows/package-distro-trigger.yml index 7f4aafe11a..f9a7a8f10c 100644 --- a/.github/workflows/package-distro-trigger.yml +++ b/.github/workflows/package-distro-trigger.yml @@ -12,6 +12,11 @@ # 4. PackageDistro tests the current PR head against all packages and updates # the same marker comment with the result. # +# The same-repository GAP checks and comments use `github.token`. The dispatch +# to PackageDistro still needs GitHub App credentials: configure +# `APP_CLIENT_ID` as an organization or repository variable (or secret) and +# `APP_PRIVATE_KEY` as a secret available to this repository. +# name: PackageDistro PR trigger on: @@ -45,20 +50,11 @@ jobs: echo "matches=false" >> "$GITHUB_OUTPUT" fi - - uses: actions/create-github-app-token@v3 - id: gap-token - if: ${{ steps.command.outputs.matches == 'true' }} - with: - client-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - owner: gap-system - repositories: gap - - name: Check commenter permission id: permission if: ${{ steps.command.outputs.matches == 'true' }} env: - GH_TOKEN: ${{ steps.gap-token.outputs.token }} + GH_TOKEN: ${{ github.token }} REPO: ${{ github.repository }} ACTOR: ${{ github.event.comment.user.login }} run: | @@ -91,7 +87,7 @@ jobs: if: ${{ steps.command.outputs.matches == 'true' }} uses: peter-evans/find-comment@v4 with: - token: ${{ steps.gap-token.outputs.token }} + token: ${{ github.token }} issue-number: ${{ github.event.issue.number }} body-includes: "" @@ -103,7 +99,7 @@ jobs: }} uses: peter-evans/create-or-update-comment@v5 with: - token: ${{ steps.gap-token.outputs.token }} + token: ${{ github.token }} comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ github.event.issue.number }} edit-mode: replace @@ -119,7 +115,7 @@ jobs: steps.permission.outputs.authorized == 'true' }} with: - client-id: ${{ secrets.APP_ID }} + client-id: ${{ vars.APP_CLIENT_ID || secrets.APP_CLIENT_ID || secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} owner: gap-system repositories: PackageDistro @@ -133,7 +129,7 @@ jobs: }} uses: peter-evans/create-or-update-comment@v5 with: - token: ${{ steps.gap-token.outputs.token }} + token: ${{ github.token }} comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ github.event.issue.number }} edit-mode: replace From c91f24a1fdc022d53a36d5b8e49fba3b5a4b20d4 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 18 May 2026 17:19:45 +0200 Subject: [PATCH 071/123] More work on package distro trigger --- .github/workflows/package-distro-trigger.yml | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/package-distro-trigger.yml b/.github/workflows/package-distro-trigger.yml index f9a7a8f10c..2a29e746e8 100644 --- a/.github/workflows/package-distro-trigger.yml +++ b/.github/workflows/package-distro-trigger.yml @@ -12,10 +12,11 @@ # 4. PackageDistro tests the current PR head against all packages and updates # the same marker comment with the result. # -# The same-repository GAP checks and comments use `github.token`. The dispatch -# to PackageDistro still needs GitHub App credentials: configure -# `APP_CLIENT_ID` as an organization or repository variable (or secret) and -# `APP_PRIVATE_KEY` as a secret available to this repository. +# The GAP comments and the dispatch to PackageDistro use GitHub App tokens: +# configure `APP_CLIENT_ID` as an organization or repository variable (or +# secret) and `APP_PRIVATE_KEY` as a secret available to this repository. The +# app must be installed on both `gap-system/gap` and +# `gap-system/PackageDistro`. # name: PackageDistro PR trigger @@ -50,11 +51,20 @@ jobs: echo "matches=false" >> "$GITHUB_OUTPUT" fi + - uses: actions/create-github-app-token@v3 + id: gap-token + if: ${{ steps.command.outputs.matches == 'true' }} + with: + client-id: ${{ vars.APP_CLIENT_ID || secrets.APP_CLIENT_ID || secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: gap-system + repositories: gap + - name: Check commenter permission id: permission if: ${{ steps.command.outputs.matches == 'true' }} env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.gap-token.outputs.token }} REPO: ${{ github.repository }} ACTOR: ${{ github.event.comment.user.login }} run: | @@ -87,7 +97,7 @@ jobs: if: ${{ steps.command.outputs.matches == 'true' }} uses: peter-evans/find-comment@v4 with: - token: ${{ github.token }} + token: ${{ steps.gap-token.outputs.token }} issue-number: ${{ github.event.issue.number }} body-includes: "" @@ -99,7 +109,7 @@ jobs: }} uses: peter-evans/create-or-update-comment@v5 with: - token: ${{ github.token }} + token: ${{ steps.gap-token.outputs.token }} comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ github.event.issue.number }} edit-mode: replace @@ -129,7 +139,7 @@ jobs: }} uses: peter-evans/create-or-update-comment@v5 with: - token: ${{ github.token }} + token: ${{ steps.gap-token.outputs.token }} comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ github.event.issue.number }} edit-mode: replace From 5dd382ab7037bbf5d7b37611c3bdd686c65280e3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 18 May 2026 17:38:23 +0200 Subject: [PATCH 072/123] Yet more work on package distro trigger --- .github/workflows/package-distro-trigger.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/package-distro-trigger.yml b/.github/workflows/package-distro-trigger.yml index 2a29e746e8..615d6fda0e 100644 --- a/.github/workflows/package-distro-trigger.yml +++ b/.github/workflows/package-distro-trigger.yml @@ -174,15 +174,16 @@ jobs: --arg callback_repo "${GITHUB_REPOSITORY}" \ --arg callback_pr_number "${{ github.event.issue.number }}" \ --argjson callback_comment_id "${comment_id_json}" \ - '{ - ref: $ref, - inputs: { + '({ "gap-pr-url": $pr_url, "callback-repo": $callback_repo, "callback-pr-number": $callback_pr_number, requester: $requester, command: $command - } + (if $callback_comment_id == null then {} else {"callback-comment-id": ($callback_comment_id | tostring)} end) + } + (if $callback_comment_id == null then {} else {"callback-comment-id": ($callback_comment_id | tostring)} end)) as $inputs + | { + ref: $ref, + inputs: $inputs }' > payload.json curl -fsSL \ -X POST \ From 4baffd1922e99b61ada63ad80fe189403ab659bb Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 18 May 2026 22:33:34 +0200 Subject: [PATCH 073/123] kernel: unify & speed up conversion from integer to FFE (#6398) Refactor the kernel code for (small) finite field elements. First, a new helper function `IntToFFE` does the conversion in a single place, instead of repeating this in multiple functions. Second, this new helper is improved to speed up the conversion from integers to finite field elements, by using binary add-and-double loop instead of a linear successor walk. This affects for example addition and multiplication of integers and FFEs. Before: gap> q:=2;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 6 gap> q:=257;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 63 gap> q:=2003;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 339 gap> q:=65521;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 10478 After: gap> q:=2;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 6 gap> q:=257;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 16 gap> q:=2003;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 14 gap> q:=65521;; for i in [1..100000] do x:=Z(q)*(q-1); od; time; 10 One can perhaps do even better, but this seemed good enough. AI assistance: Codex helped prepare this optimization and commit. Co-authored-by: Codex --- src/finfield.c | 158 ++++++++++++++----------------------------------- 1 file changed, 43 insertions(+), 115 deletions(-) diff --git a/src/finfield.c b/src/finfield.c index b2b3915c4e..5f2bdb2e69 100644 --- a/src/finfield.c +++ b/src/finfield.c @@ -597,7 +597,7 @@ static void PrFFE(Obj ffe) ** field before the addition. ** ** 'SumFFEFFE' just does the conversions mentioned above and then calls the -** macro 'SUM_FFV' to do the actual addition. +** function 'SUM_FFV' to do the actual addition. */ static Obj SUM_FFE_LARGE; @@ -642,64 +642,61 @@ static Obj SumFFEFFE(Obj opL, Obj opR) return NEW_FFE( fX, vX ); } -static Obj SumFFEInt(Obj opL, Obj opR) +static inline FFV IntToFFE(Obj op, FF fX) { - FFV vL, vR, vX; // value of left, right, result - FF fX; // field of result - Int pX; // char. of result - const FFV* sX; // successor table of result field + FFV base; + FFV res; + FFV vX; + const FFV * sX; + Int pX; - // get the field for the result - fX = FLD_FFE( opL ); pX = CHAR_FF( fX ); sX = SUCC_FF( fX ); - // get the right operand - vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX; + vX = ((INT_INTOBJ(op) % pX) + pX) % pX; if ( vX == 0 ) { - vR = 0; - } - else { - vR = 1; - for ( ; 1 < vX; vX-- ) vR = sX[vR]; + return 0; } - // get the left operand - vL = VAL_FFE( opL ); - - vX = SUM_FFV( vL, vR, sX ); - return NEW_FFE( fX, vX ); + base = 1; + res = 0; + while (vX != 0) { + if (vX & 1) { + res = SUM_FFV(res, base, sX); + } + vX >>= 1; + if (vX != 0) { + base = SUM_FFV(base, base, sX); + } + } + return res; } -static Obj SumIntFFE(Obj opL, Obj opR) +static inline Obj SumFFEInt(Obj opL, Obj opR) { FFV vL, vR, vX; // value of left, right, result FF fX; // field of result - Int pX; // char. of result const FFV* sX; // successor table of result field // get the field for the result - fX = FLD_FFE( opR ); - pX = CHAR_FF( fX ); + fX = FLD_FFE( opL ); sX = SUCC_FF( fX ); - // get the left operand - vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX; - if ( vX == 0 ) { - vL = 0; - } - else { - vL = 1; - for ( ; 1 < vX; vX-- ) vL = sX[vL]; - } - // get the right operand - vR = VAL_FFE( opR ); + vR = IntToFFE( opR, fX ); + + // get the left operand + vL = VAL_FFE( opL ); vX = SUM_FFV( vL, vR, sX ); return NEW_FFE( fX, vX ); } +static Obj SumIntFFE(Obj opL, Obj opR) +{ + return SumFFEInt(opR, opL); +} + /**************************************************************************** ** @@ -751,7 +748,7 @@ static Obj AInvFFE(Obj op) ** field before the subtraction. ** ** 'DiffFFEFFE' just does the conversions mentioned above and then calls the -** macros 'NEG_FFV' and 'SUM_FFV' to do the actual subtraction. +** functions 'NEG_FFV' and 'SUM_FFV' to do the actual subtraction. */ static Obj DIFF_FFE_LARGE; @@ -801,23 +798,14 @@ static Obj DiffFFEInt(Obj opL, Obj opR) { FFV vL, vR, vX; // value of left, right, result FF fX; // field of result - Int pX; // char. of result const FFV* sX; // successor table of result field // get the field for the result fX = FLD_FFE( opL ); - pX = CHAR_FF( fX ); sX = SUCC_FF( fX ); // get the right operand - vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX; - if ( vX == 0 ) { - vR = 0; - } - else { - vR = 1; - for ( ; 1 < vX; vX-- ) vR = sX[vR]; - } + vR = IntToFFE( opR, fX ); // get the left operand vL = VAL_FFE( opL ); @@ -831,23 +819,14 @@ static Obj DiffIntFFE(Obj opL, Obj opR) { FFV vL, vR, vX; // value of left, right, result FF fX; // field of result - Int pX; // char. of result const FFV* sX; // successor table of result field // get the field for the result fX = FLD_FFE( opR ); - pX = CHAR_FF( fX ); sX = SUCC_FF( fX ); // get the left operand - vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX; - if ( vX == 0 ) { - vL = 0; - } - else { - vL = 1; - for ( ; 1 < vX; vX-- ) vL = sX[vL]; - } + vL = IntToFFE( opL, fX ); // get the right operand vR = VAL_FFE( opR ); @@ -871,7 +850,7 @@ static Obj DiffIntFFE(Obj opL, Obj opR) ** field before the multiplication. ** ** 'ProdFFEFFE' just does the conversions mentioned above and then calls the -** macro 'PROD_FFV' to do the actual multiplication. +** function 'PROD_FFV' to do the actual multiplication. */ static Obj PROD_FFE_LARGE; @@ -916,27 +895,18 @@ static Obj ProdFFEFFE(Obj opL, Obj opR) return NEW_FFE( fX, vX ); } -static Obj ProdFFEInt(Obj opL, Obj opR) +static inline Obj ProdFFEInt(Obj opL, Obj opR) { FFV vL, vR, vX; // value of left, right, result FF fX; // field of result - Int pX; // char. of result const FFV* sX; // successor table of result field // get the field for the result fX = FLD_FFE( opL ); - pX = CHAR_FF( fX ); sX = SUCC_FF( fX ); // get the right operand - vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX; - if ( vX == 0 ) { - vR = 0; - } - else { - vR = 1; - for ( ; 1 < vX; vX-- ) vR = sX[vR]; - } + vR = IntToFFE( opR, fX ); // get the left operand vL = VAL_FFE( opL ); @@ -947,31 +917,7 @@ static Obj ProdFFEInt(Obj opL, Obj opR) static Obj ProdIntFFE(Obj opL, Obj opR) { - FFV vL, vR, vX; // value of left, right, result - FF fX; // field of result - Int pX; // char. of result - const FFV* sX; // successor table of result field - - // get the field for the result - fX = FLD_FFE( opR ); - pX = CHAR_FF( fX ); - sX = SUCC_FF( fX ); - - // get the left operand - vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX; - if ( vX == 0 ) { - vL = 0; - } - else { - vL = 1; - for ( ; 1 < vX; vX-- ) vL = sX[vL]; - } - - // get the right operand - vR = VAL_FFE( opR ); - - vX = PROD_FFV( vL, vR, sX ); - return NEW_FFE( fX, vX ); + return ProdFFEInt(opR, opL); } @@ -1026,7 +972,7 @@ static Obj InvFFE(Obj op) ** field before the division. ** ** 'QuoFFEFFE' just does the conversions mentioned above and then calls the -** macro 'QUO_FFV' to do the actual division. +** function 'QUO_FFV' to do the actual division. */ static Obj QUO_FFE_LARGE; @@ -1078,23 +1024,14 @@ static Obj QuoFFEInt(Obj opL, Obj opR) { FFV vL, vR, vX; // value of left, right, result FF fX; // field of result - Int pX; // char. of result const FFV* sX; // successor table of result field // get the field for the result fX = FLD_FFE( opL ); - pX = CHAR_FF( fX ); sX = SUCC_FF( fX ); // get the right operand - vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX; - if ( vX == 0 ) { - vR = 0; - } - else { - vR = 1; - for ( ; 1 < vX; vX-- ) vR = sX[vR]; - } + vR = IntToFFE( opR, fX ); // get the left operand vL = VAL_FFE( opL ); @@ -1110,23 +1047,14 @@ static Obj QuoIntFFE(Obj opL, Obj opR) { FFV vL, vR, vX; // value of left, right, result FF fX; // field of result - Int pX; // char. of result const FFV* sX; // successor table of result field // get the field for the result fX = FLD_FFE( opR ); - pX = CHAR_FF( fX ); sX = SUCC_FF( fX ); // get the left operand - vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX; - if ( vX == 0 ) { - vL = 0; - } - else { - vL = 1; - for ( ; 1 < vX; vX-- ) vL = sX[vL]; - } + vL = IntToFFE( opL, fX ); // get the right operand vR = VAL_FFE( opR ); @@ -1148,7 +1076,7 @@ static Obj QuoIntFFE(Obj opL, Obj opR) ** left operand is represented, even if it lies in a much smaller field. ** ** 'PowFFEInt' just does the conversions mentioned above and then calls the -** macro 'POW_FFV' to do the actual exponentiation. +** function 'POW_FFV' to do the actual exponentiation. */ static Obj PowFFEInt(Obj opL, Obj opR) { From c911423bbefbe2a5034b2b0e2a2c2520f7181246 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Tue, 19 May 2026 10:01:00 +0200 Subject: [PATCH 074/123] Fix the powering of matrix objects by integers (#6397) * fix powering of matrix objects Tha change affects those matrix objects for which `POW_MAT_INT` does the work. The function `POW_OBJ_INT` (which is used for matrices over rings that aren't fields) did not have this problem. * add a `RowsOfMatrix` method for `IsMatrix` --- lib/matrix.gi | 14 +++++++++++++- tst/testinstall/MatrixObj/arith.tst | 8 ++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/matrix.gi b/lib/matrix.gi index 8deda4ee65..569d65c5b9 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -1456,6 +1456,15 @@ InstallMethod( RowsOfMatrix, [ IsMatrix and IsPlistRep ], Immutable ); +# The following should be better than the generic method for +# matrix objects for 'IsMatrixOrMatrixObj', +# which first 'Unpack's the matrix and then +# creates new vector objects from the rows of the result. +InstallMethod( RowsOfMatrix, + "generic method for a matrix that is a list", + [ IsMatrix ], + PlainListCopy ); + InstallMethod( NumberRows, "generic method for a (perhaps empty) matrix", [ IsMatrix ], @@ -4797,7 +4806,10 @@ BindGlobal("POW_MAT_INT", function(mat, n) b := rec(vectors := [], pivots := [], heads := []); t := []; # maybe better start with a random vector? - for a in id do + for a in RowsOfMatrix( id ) do +#TODO: 'RowsOfMatrix' is not what we want to call here. +# In fact, we should better create standard basis vectors +# as we need them, instead of creating 'id' . r := addb(b,a); if r = true then repeat diff --git a/tst/testinstall/MatrixObj/arith.tst b/tst/testinstall/MatrixObj/arith.tst index 40b646af3f..87bdccbd01 100644 --- a/tst/testinstall/MatrixObj/arith.tst +++ b/tst/testinstall/MatrixObj/arith.tst @@ -16,5 +16,13 @@ Error, * is not defined gap> mat * matobj; Error, * is not defined +# Powering matrices works. +gap> mat:= Matrix( Integers, [ [ 1, 1 ], [ 0, 1 ] ] );; +gap> Unpack( mat^2 ) = Unpack( mat )^2; +true +gap> mat:= Matrix( Rationals, [ [ 1, 1 ], [ 0, 1 ] ] );; +gap> Unpack( mat^2 ) = Unpack( mat )^2; +true + # gap> STOP_TEST( "arith.tst" ); From 3abf782f34ac19d46a426e79c194a4cabffc4256 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 19 May 2026 11:52:39 +0200 Subject: [PATCH 075/123] Prepare testinstall testsuite for --bare (#6406) --- lib/grpperm.gd | 4 +- lib/test.gi | 2 +- tst/testinstall/pgroups.tst | 2 + tst/testinstall/random.tst | 8 ++-- tst/testinstall/sylowhall.tst | 77 +++++++++++++++++++++-------------- 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/lib/grpperm.gd b/lib/grpperm.gd index 86e2ccc7e9..50e2f16ac4 100644 --- a/lib/grpperm.gd +++ b/lib/grpperm.gd @@ -301,7 +301,7 @@ DeclareAttribute( "AllBlocks", IsPermGroup ); ## ## ## -DeclareGlobalFunction( "TransitiveGroupsAvailable" ); +BindGlobal( "TransitiveGroupsAvailable", ReturnFalse ); # dummy declarations to satisfy library references to transitive groups # library @@ -356,7 +356,7 @@ DeclareAttribute( "TransitiveIdentification", IsPermGroup ); ## ## ## -DeclareGlobalFunction( "PrimitiveGroupsAvailable" ); +BindGlobal( "PrimitiveGroupsAvailable", ReturnFalse ); ############################################################################# ## diff --git a/lib/test.gi b/lib/test.gi index 32addda12d..b2b729b86e 100644 --- a/lib/test.gi +++ b/lib/test.gi @@ -614,7 +614,7 @@ DeclareGlobalName("TextAttr"); # from GAPDoc DeclareGlobalName("DefaultReportDiffColors"); # initialized in Test() or by the user BindGlobal("DefaultReportDiff", function(inp, expout, found, fnam, line, time) if UserPreference("UseColorsInTerminal") = true - and IsBound( GAPInfo.PackagesLoaded.gapdoc ) then + and IsBound( DefaultReportDiffColors ) then Print(DefaultReportDiffColors.message); Print("########> Diff in "); if IsStream(fnam) then diff --git a/tst/testinstall/pgroups.tst b/tst/testinstall/pgroups.tst index f9b082a100..665c31764b 100644 --- a/tst/testinstall/pgroups.tst +++ b/tst/testinstall/pgroups.tst @@ -203,6 +203,7 @@ gap> IsRegularPGroup(G); false # +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> G:=SmallGroup(243,11);; gap> HasIsPowerfulPGroup(G); false @@ -268,6 +269,7 @@ gap> IsRegularPGroup(DirectProduct(List([[27,3],[243,22],[27,3]],SmallGroup))); true gap> IsRegularPGroup(DirectProduct(List([[27,3],[243,25]],SmallGroup))); false +#@fi # gap> STOP_TEST("pgroups.tst"); diff --git a/tst/testinstall/random.tst b/tst/testinstall/random.tst index f474932867..70e83cceb4 100644 --- a/tst/testinstall/random.tst +++ b/tst/testinstall/random.tst @@ -64,11 +64,11 @@ gap> randomTest(AlternatingGroup(5), Random); # gap> randomTest(Group((1,2),(3,4)), Random); -gap> randomTest(PrimitiveGroup(5,2), Random); -gap> randomTest(PrimitiveGroup(5,3), Random); +gap> randomTest(Group((2,4)(3,5), (1,2,3,5,4)), Random); +gap> randomTest(Group((2,3,4,5), (1,2,3,5,4)), Random); gap> randomTest(Group((1,2),(3,4))*(1,2,3), Random); -gap> randomTest(PrimitiveGroup(5,2)*(1,2,6), Random); -gap> randomTest(PrimitiveGroup(5,3)*(1,4,6), Random); +gap> randomTest(Group((2,4)(3,5), (1,2,3,5,4))*(1,2,6), Random); +gap> randomTest(Group((2,3,4,5), (1,2,3,5,4))*(1,4,6), Random); # # pc groups diff --git a/tst/testinstall/sylowhall.tst b/tst/testinstall/sylowhall.tst index a9d7fdeede..1723aaf466 100644 --- a/tst/testinstall/sylowhall.tst +++ b/tst/testinstall/sylowhall.tst @@ -2,20 +2,26 @@ gap> START_TEST("sylowhall.tst"); gap> G := GL(3,4);; PrimeDivisors(Size(G)); [ 2, 3, 5, 7 ] +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> IdGroup(SylowSubgroup(G, 2)); [ 64, 242 ] gap> IdGroup(SylowSubgroup(G, 3)); [ 81, 7 ] -gap> IdGroup(SylowSubgroup(G, 5)); -[ 5, 1 ] -gap> IdGroup(SylowSubgroup(G, 7)); -[ 7, 1 ] +#@fi +gap> StructureDescription(SylowSubgroup(G, 5)); +"C5" +gap> StructureDescription(SylowSubgroup(G, 7)); +"C7" gap> SylowSystem(G); fail gap> HallSystem(G); fail -gap> fine := true;; for p in PrimeDivisors(Size(G)) do fine := fine and HasHallSubgroup(G, [p]); od; fine; +#@if IsPackageMarkedForLoading( "smallgrp", "" ) +gap> ForAll(PrimeDivisors(Size(G)), p -> HasHallSubgroup(G, [p])); true +#@fi + +# gap> G := GL(4,3);; PrimeDivisors(Size(G)); [ 2, 3, 5, 13 ] gap> HallSubgroup(G, [2, 3, 5, 13]) = G; @@ -24,13 +30,13 @@ gap> fine := true;; for p in PrimeDivisors(Size(G)) do fine := fine and HallSubg true gap> IsTrivial(HallSubgroup(G, [7, 11, 17])); true + +# gap> D := DihedralGroup(24);; -gap> IdGroup(SylowSubgroup(D,2)); -[ 8, 3 ] -gap> PCore(D, 2)=D; -false -gap> IdGroup(PCore(D, 2)); -[ 4, 1 ] +gap> StructureDescription(SylowSubgroup(D,2)); +"D8" +gap> StructureDescription(PCore(D, 2)); +"C4" gap> HasHallSubgroup(D,[2]) and HallSubgroup(D,[2]) = SylowSubgroup(D,2); true gap> SylowComplement(D,2)=HallSubgroup(D,[3]); @@ -39,14 +45,20 @@ gap> SylowComplement(D,2)=SylowSubgroup(D,3); true gap> SylowComplement(D,5)=D; true + +# gap> A := AlternatingGroup(4);; gap> SylowComplement(A, 3)=Group((1,2)(3,4), (1,3)(2,4)); true -gap> G := SmallGroup(8,4);; SylowComplement(G,5)=G; + +# +gap> G := QuaternionGroup(8);; SylowComplement(G,5)=G; true gap> IsTrivial(SylowComplement(G,2)); true -gap> G := SmallGroup(1080, 248);; + +# +gap> G := PcGroupCode(13145332246515941463, 1080);; # SmallGroup(1080, 248) gap> List(SylowSystem(G), Size); [ 8, 27, 5 ] gap> fine := true;; for p in PrimeDivisors(Size(G)) do fine := fine and HasSylowSubgroup(G, p); od; fine; @@ -55,15 +67,14 @@ gap> HasHallSubgroup(G,[2]) and HasHallSubgroup(G,[2]) and HasHallSubgroup(G,[5] true gap> HasHallSubgroup(G, [2, 5]); false -gap> IdGroup(HallSubgroup(G, [2,5])); -[ 40, 10 ] +gap> StructureDescription(HallSubgroup(G, [2,5])); +"C5 x D8" gap> PCore(G,2) = SylowSubgroup(G,2); true -gap> G := SmallGroup(1080, 248);; IsNilpotentGroup(G); +gap> IsNilpotentGroup(G); true gap> PCore(G,2) = SylowSubgroup(G,2); true -gap> G := SmallGroup(1080, 248);; gap> List(HallSystem(G), Size); [ 1, 8, 216, 1080, 40, 27, 135, 5 ] gap> fine := true;; for pi in Combinations(PrimeDivisors(Size(G))) do fine := fine and HasHallSubgroup(G, pi); od; fine; @@ -72,27 +83,31 @@ gap> HasSylowComplement(G, 2); false gap> SylowComplement(G, 2)=HallSubgroup(G, [3,5]); true -gap> IdGroup(HallSubgroup(AlternatingGroup(5), [2,3])); -[ 12, 3 ] -gap> IdGroup(SylowSubgroup(Group((1,2),(1,2,3,4,5)), 2)); -[ 8, 3 ] -gap> IdGroup(PCore(Group(()), 2)); -[ 1, 1 ] +gap> StructureDescription(HallSubgroup(AlternatingGroup(5), [2,3])); +"A4" +gap> StructureDescription(SylowSubgroup(Group((1,2),(1,2,3,4,5)), 2)); +"D8" +gap> StructureDescription(PCore(Group(()), 2)); +"1" gap> PCore(Group((1,2),(1,2,3,4,5)), 2) = PCore(Group((1,2),(1,2,3,4,5)), 7); true gap> G := Group((1,3),(1,2,3,4), (5,6,7));; gap> PCore(G, 2) = Group((1,3),(1,2,3,4)); true + +# gap> F := FreeGroup("x", "y");; x := F.1;; y := F.2;; gap> G := F/[x*y*x^(-1)*y^(-1), x^30, (x*y)^70];; -gap> IdGroup(SylowSubgroup(G, 2)); -[ 4, 2 ] -gap> IdGroup(HallSubgroup(G, [2,3])); -[ 12, 5 ] +gap> StructureDescription(SylowSubgroup(G, 2)); +"C2 x C2" +gap> StructureDescription(HallSubgroup(G, [2,3])); +"C6 x C2" gap> IsAbelian(G); true -gap> IdGroup(SylowSubgroup(G, 5)); -[ 25, 2 ] -gap> IdGroup(HallSubgroup(G, [5,7])); -[ 175, 2 ] +gap> StructureDescription(SylowSubgroup(G, 5)); +"C5 x C5" +gap> StructureDescription(HallSubgroup(G, [5,7])); +"C35 x C5" + +# gap> STOP_TEST("sylowhall.tst"); From 2d64e3a143345ac0c26347af9d39ab8447fca04e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 19 May 2026 15:51:15 +0200 Subject: [PATCH 076/123] Put compressed marices/vectors into filter IsMatrix/IsList (#6400) --- hpcgap/lib/vec8bit.gi | 2 +- hpcgap/lib/vecmat.gi | 2 +- lib/mat8bit.gd | 2 +- lib/vec8bit.gd | 2 +- lib/vec8bit.gi | 2 +- lib/vecmat.gd | 4 ++-- lib/vecmat.gi | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index 00d34ac9d1..02154628bb 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -1030,7 +1030,7 @@ InstallMethodWithRandomSource( Randomize, for i in [1..Length(v)] do v[i] := Random(rs,l); od; return v; end ); -InstallMethod( MutableCopyMatrix, "for an 8bit matrix", +InstallOtherMethod( MutableCopyMatrix, "for an 8bit matrix", [ Is8BitMatrixRep ], function( m ) local mm; diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index 8291757030..121736776e 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -2436,7 +2436,7 @@ InstallMethodWithRandomSource( Randomize, return v; end ); -InstallMethod( MutableCopyMatrix, "for a gf2 matrix", +InstallOtherMethod( MutableCopyMatrix, "for a gf2 matrix", [ IsGF2MatrixRep ], function( m ) local mm; diff --git a/lib/mat8bit.gd b/lib/mat8bit.gd index 2e8279f9bd..abde8e342c 100644 --- a/lib/mat8bit.gd +++ b/lib/mat8bit.gd @@ -45,7 +45,7 @@ ## but is determined by the common base domain of the rows of the matrix. ## DeclareRepresentation( "Is8BitMatrixRep", - IsPositionalObjectRep and IsRowListMatrix + IsPositionalObjectRep and IsRowListMatrix and IsMatrix and IsCopyable and IsNoImmediateMethodsObject and HasNumberRows and HasNumberColumns diff --git a/lib/vec8bit.gd b/lib/vec8bit.gd index 092c3ff08e..9cca4572c9 100644 --- a/lib/vec8bit.gd +++ b/lib/vec8bit.gd @@ -47,7 +47,7 @@ MakeImmutable(PRIMES_COMPACT_FIELDS); ## , the entries are packed into bytes. ## DeclareRepresentation( "Is8BitVectorRep", - IsDataObjectRep and IsVectorObj + IsDataObjectRep and IsVectorObj and IsList and IsCopyable and IsNoImmediateMethodsObject and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain); diff --git a/lib/vec8bit.gi b/lib/vec8bit.gi index 5c491f4320..39893b4afb 100644 --- a/lib/vec8bit.gi +++ b/lib/vec8bit.gi @@ -985,7 +985,7 @@ InstallMethodWithRandomSource( Randomize, for i in [1..Length(v)] do v[i] := Random(rs,l); od; return v; end ); -InstallMethod( MutableCopyMatrix, "for an 8bit matrix", +InstallOtherMethod( MutableCopyMatrix, "for an 8bit matrix", [ Is8BitMatrixRep ], function( m ) local mm; diff --git a/lib/vecmat.gd b/lib/vecmat.gd index 393a969f93..9b27408ed2 100644 --- a/lib/vecmat.gd +++ b/lib/vecmat.gd @@ -50,7 +50,7 @@ BIND_GLOBAL( "GF2Zero", 0*Z(2) ); ## , the entries are packed into bits. ## DeclareRepresentation( "IsGF2VectorRep", - IsDataObjectRep and IsVectorObj + IsDataObjectRep and IsVectorObj and IsList and IsCopyable and IsNoImmediateMethodsObject and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain); @@ -254,7 +254,7 @@ DeclareGlobalFunction( "ConvertToMatrixRep" ); ## i+1. ## DeclareRepresentation( "IsGF2MatrixRep", - IsPositionalObjectRep and IsRowListMatrix + IsPositionalObjectRep and IsRowListMatrix and IsMatrix and IsCopyable and IsNoImmediateMethodsObject and HasNumberRows and HasNumberColumns diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 1c83a13c01..24e2f72445 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -2434,7 +2434,7 @@ InstallMethodWithRandomSource( Randomize, return v; end ); -InstallMethod( MutableCopyMatrix, "for a gf2 matrix", +InstallOtherMethod( MutableCopyMatrix, "for a gf2 matrix", [ IsGF2MatrixRep ], function( m ) local mm; From 6ed18706de1911cd8442c1b131463014f5178742 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 19 May 2026 19:55:29 +0200 Subject: [PATCH 077/123] PackageVariablesInfo: better support variadic functions (#6404) Teach args helper about multi-arg variadic functions. --- lib/package.gi | 9 +++++---- tst/mockpkg/gap/mockpkg.gi | 4 ++++ tst/testinstall/package.tst | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/package.gi b/lib/package.gi index 1930c9d6fd..a4b404027e 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -3348,12 +3348,13 @@ InstallGlobalFunction( PackageVariablesInfo, function( pkgname, version ) fi; num:= NumberArgumentsFunction( func ); nam:= NamesLocalVariablesFunction( func ); - if num = -1 then - str:= "arg"; - elif nam = fail then + if nam = fail then str:= "..."; else - str:= JoinStringsWithSeparator( nam{ [ 1 .. num ] }, ", " ); + str:= JoinStringsWithSeparator( nam{ [ 1 .. AbsInt(num) ] }, ", " ); + if num < 0 then + Append( str, "..." ); + fi; fi; return Concatenation( "( ", str, " )" ); end; diff --git a/tst/mockpkg/gap/mockpkg.gi b/tst/mockpkg/gap/mockpkg.gi index 3bcefc9c79..9ef3c4719a 100644 --- a/tst/mockpkg/gap/mockpkg.gi +++ b/tst/mockpkg/gap/mockpkg.gi @@ -13,3 +13,7 @@ InstallMethod( mockpkg_Operation, [ IsGroup, IsPosInt ], { G, n } -> n ); InstallMethod( mockpkg_Attribute, [ IsSolvableGroup ], G -> G ); InstallMethod( mockpkg_Property, [ IsNilpotentGroup ], IsAbelian ); + +BindGlobal( "mockpkg_Vararg", function(first, rest...) + return Concatenation([first], rest); +end ); diff --git a/tst/testinstall/package.tst b/tst/testinstall/package.tst index 2b1a5d6e84..48df3fbf39 100644 --- a/tst/testinstall/package.tst +++ b/tst/testinstall/package.tst @@ -450,9 +450,10 @@ new global functions: new global variables: mockpkg_ExtensionData* + mockpkg_Vararg( first, rest... )* new operations: - mockpkg_Operation( arg )* + mockpkg_Operation( ... )* new attributes: mockpkg_Attribute( ... )* From c92da5e32da75f33095791d46b9cae5176328d6d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 21 May 2026 16:45:42 +0200 Subject: [PATCH 078/123] kernel: strengthen vecgf2 and vec8bit validation, reject empty vectors were not supported (#6401) Add runtime argument checks to the user-facing GF2 and 8-bit kernel entry points instead of relying on debug-only assertions or unchecked representation assumptions. Use shared Require helpers for compressed vectors and matrices, and tighten plain-list validation where these entry points expect list-backed inputs. Harden the exported vec8bit kernel entry points that assumed a first row existed, and fix SHIFT_VEC8BIT_RIGHT for empty compressed vectors. AI assistance from OpenAI Codex helped prepare these kernel validation changes. Co-authored-by: Codex --- src/vec8bit.c | 187 ++++- src/vecgf2.c | 158 +++- src/vecgf2.h | 8 + tst/testinstall/kernel/vec8bit.tst | 1187 ++++++++++++++++++++++++++++ tst/testinstall/kernel/vecgf2.tst | 973 ++++++++++++++++++++++- 5 files changed, 2459 insertions(+), 54 deletions(-) diff --git a/src/vec8bit.c b/src/vec8bit.c index 9137672f8c..3b50507c67 100644 --- a/src/vec8bit.c +++ b/src/vec8bit.c @@ -60,6 +60,10 @@ RequireArgumentCondition(funcname, op, IS_MAT8BIT_REP(op), \ "must belong to Is8BitMatrixRep") +#define RequireFFE(funcname, op) \ + RequireArgumentCondition(funcname, op, IS_FFE(op), \ + "must be a finite field element") + /**************************************************************************** ** *F IS_VEC8BIT_REP( ) . . . check that is in 8bit GFQ vector rep @@ -815,6 +819,7 @@ static UInt LcmDegree(UInt d, UInt d1) */ static Obj FuncCONV_VEC8BIT(Obj self, Obj list, Obj q) { + RequireSmallList(SELF_NAME, list); UInt iq = GetPositiveSmallInt(SELF_NAME, q); ConvVec8Bit(list, iq); return 0; @@ -937,6 +942,7 @@ static Obj NewVec8Bit(Obj list, UInt q) */ static Obj FuncCOPY_VEC8BIT(Obj self, Obj list, Obj q) { + RequireSmallList(SELF_NAME, list); UInt iq = GetPositiveSmallInt(SELF_NAME, q); return NewVec8Bit(list, iq); } @@ -1019,9 +1025,7 @@ void PlainVec8Bit(Obj list) */ static Obj FuncPLAIN_VEC8BIT(Obj self, Obj list) { - if (!IS_VEC8BIT_REP(list)) { - RequireArgument(SELF_NAME, list, "must be an 8bit vector"); - } + RequireVec8BitRep(SELF_NAME, list); if (DoFilter(IsLockedRepresentationVector, list) == True) { ErrorMayQuit("Cannot convert a locked vector compressed over " "GF(%d) to a plain list", @@ -1214,8 +1218,8 @@ static Obj ConvertToVectorRep; // BH: changed to static static Obj FuncSUM_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) { - GAP_ASSERT(IS_VEC8BIT_REP(vl)); - GAP_ASSERT(IS_VEC8BIT_REP(vr)); + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); Obj sum; if (FIELD_VEC8BIT(vl) != FIELD_VEC8BIT(vr)) { @@ -1395,6 +1399,9 @@ static Obj FuncPROD_VEC8BIT_FFE(Obj self, Obj vec, Obj ffe) Obj info; UInt d; + RequireVec8BitRep(SELF_NAME, vec); + RequireFFE(SELF_NAME, ffe); + if (VAL_FFE(ffe) == 1) { // ffe is the one return CopyVec8Bit(vec, IS_MUTABLE_OBJ(vec)); } @@ -1427,6 +1434,7 @@ static Obj FuncPROD_VEC8BIT_FFE(Obj self, Obj vec, Obj ffe) static Obj FuncZERO_VEC8BIT(Obj self, Obj vec) { + RequireVec8BitRep(SELF_NAME, vec); return ZeroVec8Bit(FIELD_VEC8BIT(vec), LEN_VEC8BIT(vec), 1); } @@ -1456,6 +1464,8 @@ static Obj FuncZERO_VEC8BIT_2(Obj self, Obj q, Obj len) static Obj FuncPROD_FFE_VEC8BIT(Obj self, Obj ffe, Obj vec) { + RequireFFE(SELF_NAME, ffe); + RequireVec8BitRep(SELF_NAME, vec); return FuncPROD_VEC8BIT_FFE(self, vec, ffe); } @@ -1492,16 +1502,19 @@ static Obj AInvVec8Bit(Obj vec, UInt mut) static Obj FuncAINV_VEC8BIT_MUTABLE(Obj self, Obj vec) { + RequireVec8BitRep(SELF_NAME, vec); return AInvVec8Bit(vec, 1); } static Obj FuncAINV_VEC8BIT_SAME_MUTABILITY(Obj self, Obj vec) { + RequireVec8BitRep(SELF_NAME, vec); return AInvVec8Bit(vec, IS_MUTABLE_OBJ(vec)); } static Obj FuncAINV_VEC8BIT_IMMUTABLE(Obj self, Obj vec) { + RequireVec8BitRep(SELF_NAME, vec); return AInvVec8Bit(vec, 0); } @@ -1608,6 +1621,8 @@ static void AddVec8BitVec8BitMultInner( static Obj FuncMULT_VECTOR_VEC8BITS(Obj self, Obj vec, Obj mul) { + RequireVec8BitRep(SELF_NAME, vec); + RequireFFE(SELF_NAME, mul); UInt q; q = FIELD_VEC8BIT(vec); @@ -1646,6 +1661,11 @@ static Obj AddRowVector; static Obj FuncADD_ROWVECTOR_VEC8BITS_5( Obj self, Obj vl, Obj vr, Obj mul, Obj from, Obj to) { + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); + RequireFFE(SELF_NAME, mul); + RequirePositiveSmallInt(SELF_NAME, from); + RequirePositiveSmallInt(SELF_NAME, to); UInt q; UInt len; len = LEN_VEC8BIT(vl); @@ -1720,6 +1740,9 @@ static Obj FuncADD_ROWVECTOR_VEC8BITS_5( static Obj FuncADD_ROWVECTOR_VEC8BITS_3(Obj self, Obj vl, Obj vr, Obj mul) { + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); + RequireFFE(SELF_NAME, mul); UInt q; if (LEN_VEC8BIT(vl) != LEN_VEC8BIT(vr)) { ErrorMayQuit( @@ -1778,6 +1801,8 @@ static Obj FuncADD_ROWVECTOR_VEC8BITS_3(Obj self, Obj vl, Obj vr, Obj mul) static Obj FuncADD_ROWVECTOR_VEC8BITS_2(Obj self, Obj vl, Obj vr) { + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); UInt q; if (LEN_VEC8BIT(vl) != LEN_VEC8BIT(vr)) { ErrorMayQuit( @@ -1913,6 +1938,8 @@ static Obj FuncDIFF_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) Obj diff; // UInt p; + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); if (FIELD_VEC8BIT(vl) != FIELD_VEC8BIT(vr)) { UInt ql = FIELD_VEC8BIT(vl), qr = FIELD_VEC8BIT(vr); @@ -2086,6 +2113,8 @@ static Obj ScalarProductVec8Bits(Obj vl, Obj vr) static Obj FuncPROD_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) { + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); if (FIELD_VEC8BIT(vl) != FIELD_VEC8BIT(vr)) return ProdListList(vl, vr); @@ -2146,6 +2175,8 @@ static UInt DistanceVec8Bits(Obj vl, Obj vr) static Obj FuncDISTANCE_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) { + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); if (FIELD_VEC8BIT(vl) != FIELD_VEC8BIT(vr) || LEN_VEC8BIT(vl) != LEN_VEC8BIT(vr)) return TRY_NEXT_METHOD; @@ -2215,6 +2246,10 @@ static Obj FuncDISTANCE_DISTRIB_VEC8BITS( UInt len; UInt q; + RequirePlainList(SELF_NAME, veclis); + RequireVec8BitRep(SELF_NAME, vec); + RequirePlainList(SELF_NAME, d); + len = LEN_VEC8BIT(vec); q = FIELD_VEC8BIT(vec); @@ -2331,6 +2366,8 @@ static Obj FuncA_CLOSEST_VEC8BIT( UInt len; UInt q; + RequirePlainList(SELF_NAME, veclis); + RequireVec8BitRep(SELF_NAME, vec); RequireNonnegativeSmallInt(SELF_NAME, cnt); RequireNonnegativeSmallInt(SELF_NAME, stop); @@ -2371,6 +2408,8 @@ static Obj FuncA_CLOSEST_VEC8BIT_COORDS( Obj res; + RequirePlainList(SELF_NAME, veclis); + RequireVec8BitRep(SELF_NAME, vec); RequireNonnegativeSmallInt(SELF_NAME, cnt); RequireNonnegativeSmallInt(SELF_NAME, stop); @@ -2413,6 +2452,7 @@ static Obj FuncA_CLOSEST_VEC8BIT_COORDS( static Obj FuncNUMBER_VEC8BIT(Obj self, Obj vec) { + RequireVec8BitRep(SELF_NAME, vec); Obj info; UInt elts; UInt len; @@ -2608,6 +2648,7 @@ static Obj FuncCOSET_LEADERS_INNER_8BITS( RequireSmallInt(SELF_NAME, weight); RequireSmallInt(SELF_NAME, tofind); RequirePlainList(SELF_NAME, leaders); + RequirePlainList(SELF_NAME, felts); lenv = LEN_PLIST(veclis); q = LEN_PLIST(felts); @@ -2628,6 +2669,8 @@ static Obj FuncCOSET_LEADERS_INNER_8BITS( static Obj FuncEQ_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) { + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); if (FIELD_VEC8BIT(vl) != FIELD_VEC8BIT(vr)) return EqListList(vl, vr) ? True : False; @@ -2645,6 +2688,8 @@ static Obj FuncEQ_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) static Obj FuncLT_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) { + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); if (FIELD_VEC8BIT(vl) != FIELD_VEC8BIT(vr)) return LtListList(vl, vr) ? True : False; @@ -2665,6 +2710,7 @@ static Obj FuncLT_VEC8BIT_VEC8BIT(Obj self, Obj vl, Obj vr) static Obj FuncSHALLOWCOPY_VEC8BIT(Obj self, Obj list) { + RequireVec8BitRep(SELF_NAME, list); return CopyVec8Bit(list, 1); } @@ -2675,6 +2721,7 @@ static Obj FuncSHALLOWCOPY_VEC8BIT(Obj self, Obj list) */ static Obj FuncLEN_VEC8BIT(Obj self, Obj list) { + RequireVec8BitRep(SELF_NAME, list); return INTOBJ_INT(LEN_VEC8BIT(list)); } @@ -2684,6 +2731,7 @@ static Obj FuncLEN_VEC8BIT(Obj self, Obj list) */ static Obj FuncQ_VEC8BIT(Obj self, Obj list) { + RequireVec8BitRep(SELF_NAME, list); return INTOBJ_INT(FIELD_VEC8BIT(list)); } @@ -2704,6 +2752,7 @@ static Obj FuncELM0_VEC8BIT(Obj self, Obj list, Obj pos) Obj info; UInt elts; + RequireVec8BitRep(SELF_NAME, list); p = GetPositiveSmallInt(SELF_NAME, pos); if (LEN_VEC8BIT(list) < p) { return Fail; @@ -2733,6 +2782,7 @@ static Obj FuncELM_VEC8BIT(Obj self, Obj list, Obj pos) Obj info; UInt elts; + RequireVec8BitRep(SELF_NAME, list); p = GetPositiveSmallInt(SELF_NAME, pos); if (LEN_VEC8BIT(list) < p) { ErrorMayQuit("List Element: [%d] must have an assigned value", @@ -2773,6 +2823,8 @@ static Obj FuncELMS_VEC8BIT(Obj self, Obj list, Obj poss) UInt1 byte; UInt len2; + RequireVec8BitRep(SELF_NAME, list); + RequirePlainList(SELF_NAME, poss); len = LEN_PLIST(poss); info = GetFieldInfo8Bit(FIELD_VEC8BIT(list)); len2 = LEN_VEC8BIT(list); @@ -2840,6 +2892,9 @@ static Obj FuncELMS_VEC8BIT_RANGE(Obj self, Obj list, Obj range) UInt e; UInt1 byte; + RequireVec8BitRep(SELF_NAME, list); + RequireArgumentCondition(SELF_NAME, range, IS_RANGE(range), "must be a range"); + info = GetFieldInfo8Bit(FIELD_VEC8BIT(list)); elts = ELS_BYTE_FIELDINFO_8BIT(info); len = GET_LEN_RANGE(range); @@ -3012,6 +3067,7 @@ void ASS_VEC8BIT(Obj list, Obj pos, Obj elm) static Obj FuncASS_VEC8BIT(Obj self, Obj list, Obj pos, Obj elm) { + RequireVec8BitRep(SELF_NAME, list); ASS_VEC8BIT(list, pos, elm); return 0; } @@ -3032,6 +3088,7 @@ static Obj FuncUNB_VEC8BIT(Obj self, Obj list, Obj pos) Obj info; UInt elts; + RequireVec8BitRep(SELF_NAME, list); // check that is mutable RequireMutable("List Unbind", list, "list"); if (True == DoFilter(IsLockedRepresentationVector, list)) { @@ -3121,12 +3178,15 @@ static UInt PositionNonZeroVec8Bit(Obj list, UInt from) static Obj FuncPOSITION_NONZERO_VEC8BIT(Obj self, Obj list, Obj zero) { + RequireVec8BitRep(SELF_NAME, list); return INTOBJ_INT(PositionNonZeroVec8Bit(list, 0)); } static Obj FuncPOSITION_NONZERO_VEC8BIT3(Obj self, Obj list, Obj zero, Obj from) { + RequireVec8BitRep(SELF_NAME, list); + RequireNonnegativeSmallInt(SELF_NAME, from); return INTOBJ_INT(PositionNonZeroVec8Bit(list, INT_INTOBJ(from))); } @@ -3150,6 +3210,9 @@ static Obj FuncAPPEND_VEC8BIT(Obj self, Obj vecl, Obj vecr) const UInt1 * settab; UInt posl, posr; + RequireVec8BitRep(SELF_NAME, vecl); + RequireVec8BitRep(SELF_NAME, vecr); + if (FIELD_VEC8BIT(vecl) != FIELD_VEC8BIT(vecr)) return TRY_NEXT_METHOD; @@ -3224,6 +3287,9 @@ static Obj FuncPROD_VEC8BIT_MATRIX(Obj self, Obj vec, Obj mat) const Obj * ffefelt; Obj x; + RequireVec8BitRep(SELF_NAME, vec); + RequirePlainList(SELF_NAME, mat); + len = LEN_VEC8BIT(vec); l2 = LEN_PLIST(mat); q = FIELD_VEC8BIT(vec); @@ -3310,6 +3376,14 @@ static inline UInt NR_COLS_MAT8BIT(Obj mat) return LEN_VEC8BIT(ELM_MAT8BIT(mat, 1)); } +static inline void RequireNonemptyMat8BitRows(const Char * funcname, Obj mat) +{ + if (LEN_MAT8BIT(mat) == 0) + ErrorMayQuit("%s: compressed 8bit matrices with empty rows are not " + "supported", + (Int)funcname, 0); +} + /**************************************************************************** ** *F PlainMat8Bit( ) @@ -3337,6 +3411,7 @@ static void PlainMat8Bit(Obj mat) static Obj FuncPLAIN_MAT8BIT(Obj self, Obj mat) { + RequireMat8BitRep(SELF_NAME, mat); PlainMat8Bit(mat); return 0; } @@ -3356,6 +3431,7 @@ static Obj FuncCONV_MAT8BIT(Obj self, Obj list, Obj q) Obj tmp; Obj type; + RequirePlainList(SELF_NAME, list); UInt iq = GetPositiveSmallInt(SELF_NAME, q); PLAIN_LIST(list); len = LEN_PLIST(list); @@ -3464,8 +3540,9 @@ static Obj FuncPROD_VEC8BIT_MAT8BIT(Obj self, Obj vec, Obj mat) { UInt q, q1, q2; - GAP_ASSERT(IS_VEC8BIT_REP(vec)); - GAP_ASSERT(IS_MAT8BIT_REP(mat)); + RequireVec8BitRep(SELF_NAME, vec); + RequireMat8BitRep(SELF_NAME, mat); + RequireNonemptyMat8BitRows(SELF_NAME, mat); // Now field mismatches -- consider promoting the vector q = FIELD_VEC8BIT(vec); @@ -3549,8 +3626,9 @@ static Obj FuncPROD_MAT8BIT_VEC8BIT(Obj self, Obj mat, Obj vec) { UInt q, q1, q2; - GAP_ASSERT(IS_MAT8BIT_REP(mat)); - GAP_ASSERT(IS_VEC8BIT_REP(vec)); + RequireMat8BitRep(SELF_NAME, mat); + RequireVec8BitRep(SELF_NAME, vec); + RequireNonemptyMat8BitRows(SELF_NAME, mat); // Now field mismatches -- consider promoting the vector q = FIELD_VEC8BIT(vec); @@ -3626,8 +3704,10 @@ static Obj ProdMat8BitMat8Bit(Obj matl, Obj matr) static Obj FuncPROD_MAT8BIT_MAT8BIT(Obj self, Obj matl, Obj matr) { - GAP_ASSERT(IS_MAT8BIT_REP(matl)); - GAP_ASSERT(IS_MAT8BIT_REP(matr)); + RequireMat8BitRep(SELF_NAME, matl); + RequireMat8BitRep(SELF_NAME, matr); + RequireNonemptyMat8BitRows(SELF_NAME, matl); + RequireNonemptyMat8BitRows(SELF_NAME, matr); if (FIELD_MAT8BIT(matl) != FIELD_MAT8BIT(matr)) { return TRY_NEXT_METHOD; @@ -3802,7 +3882,8 @@ static Obj InverseMat8Bit(Obj mat, UInt mut) static Obj FuncINV_MAT8BIT_MUTABLE(Obj self, Obj mat) { - GAP_ASSERT(IS_MAT8BIT_REP(mat)); + RequireMat8BitRep(SELF_NAME, mat); + RequireNonemptyMat8BitRows(SELF_NAME, mat); if (LEN_MAT8BIT(mat) != LEN_VEC8BIT(ELM_MAT8BIT(mat, 1))) { ErrorMayQuit("InverseOp: matrix must be square, not %d by %d", @@ -3820,7 +3901,8 @@ static Obj FuncINV_MAT8BIT_MUTABLE(Obj self, Obj mat) static Obj FuncINV_MAT8BIT_SAME_MUTABILITY(Obj self, Obj mat) { - GAP_ASSERT(IS_MAT8BIT_REP(mat)); + RequireMat8BitRep(SELF_NAME, mat); + RequireNonemptyMat8BitRows(SELF_NAME, mat); if (LEN_MAT8BIT(mat) != LEN_VEC8BIT(ELM_MAT8BIT(mat, 1))) { ErrorMayQuit( "InverseSameMutability: matrix must be square, not %d by %d", @@ -3838,7 +3920,8 @@ static Obj FuncINV_MAT8BIT_SAME_MUTABILITY(Obj self, Obj mat) static Obj FuncINV_MAT8BIT_IMMUTABLE(Obj self, Obj mat) { - GAP_ASSERT(IS_MAT8BIT_REP(mat)); + RequireMat8BitRep(SELF_NAME, mat); + RequireNonemptyMat8BitRows(SELF_NAME, mat); if (LEN_MAT8BIT(mat) != LEN_VEC8BIT(ELM_MAT8BIT(mat, 1))) { ErrorMayQuit("Inverse: matrix must be square, not %d by %d", LEN_MAT8BIT(mat), LEN_VEC8BIT(ELM_MAT8BIT(mat, 1))); @@ -3864,7 +3947,8 @@ static Obj FuncASS_MAT8BIT(Obj self, Obj mat, Obj pos, Obj obj) UInt p; Obj type; - GAP_ASSERT(IS_MAT8BIT_REP(mat)); + RequireMat8BitRep(SELF_NAME, mat); + RequireNonemptyMat8BitRows(SELF_NAME, mat); p = GetPositiveSmallInt(SELF_NAME, pos); len = LEN_MAT8BIT(mat); @@ -3957,7 +4041,7 @@ static Obj FuncASS_MAT8BIT(Obj self, Obj mat, Obj pos, Obj obj) */ static Obj FuncELM_MAT8BIT(Obj self, Obj mat, Obj pos) { - GAP_ASSERT(IS_MAT8BIT_REP(mat)); + RequireMat8BitRep(SELF_NAME, mat); UInt r = GetPositiveSmallInt(SELF_NAME, pos); if (LEN_MAT8BIT(mat) < r) { ErrorMayQuit("row index %d exceeds %d, the number of rows", r, @@ -4111,8 +4195,10 @@ static Obj SumMat8BitMat8Bit(Obj ml, Obj mr) static Obj FuncSUM_MAT8BIT_MAT8BIT(Obj self, Obj ml, Obj mr) { - GAP_ASSERT(IS_MAT8BIT_REP(ml)); - GAP_ASSERT(IS_MAT8BIT_REP(mr)); + RequireMat8BitRep(SELF_NAME, ml); + RequireMat8BitRep(SELF_NAME, mr); + RequireNonemptyMat8BitRows(SELF_NAME, ml); + RequireNonemptyMat8BitRows(SELF_NAME, mr); if (FIELD_MAT8BIT(ml) != FIELD_MAT8BIT(mr)) { return TRY_NEXT_METHOD; @@ -4204,8 +4290,10 @@ static Obj DiffMat8BitMat8Bit(Obj ml, Obj mr) static Obj FuncDIFF_MAT8BIT_MAT8BIT(Obj self, Obj ml, Obj mr) { - GAP_ASSERT(IS_MAT8BIT_REP(ml)); - GAP_ASSERT(IS_MAT8BIT_REP(mr)); + RequireMat8BitRep(SELF_NAME, ml); + RequireMat8BitRep(SELF_NAME, mr); + RequireNonemptyMat8BitRows(SELF_NAME, ml); + RequireNonemptyMat8BitRows(SELF_NAME, mr); if (FIELD_MAT8BIT(ml) != FIELD_MAT8BIT(mr)) return TRY_NEXT_METHOD; @@ -4407,6 +4495,8 @@ static void ShiftRightVec8Bit(Obj vec, UInt amount) // pads with zeros // make room len = LEN_VEC8BIT(vec); ResizeVec8Bit(vec, len + amount, 0); + if (len == 0) + return; q = FIELD_VEC8BIT(vec); info = GetFieldInfo8Bit(q); @@ -4461,6 +4551,10 @@ static void ShiftRightVec8Bit(Obj vec, UInt amount) // pads with zeros static Obj FuncADD_COEFFS_VEC8BIT_3(Obj self, Obj vec1, Obj vec2, Obj mult) { + RequireVec8BitRep(SELF_NAME, vec1); + RequireVec8BitRep(SELF_NAME, vec2); + RequireFFE(SELF_NAME, mult); + UInt q; UInt len; len = LEN_VEC8BIT(vec2); @@ -4525,6 +4619,9 @@ static Obj FuncADD_COEFFS_VEC8BIT_3(Obj self, Obj vec1, Obj vec2, Obj mult) static Obj FuncADD_COEFFS_VEC8BIT_2(Obj self, Obj vec1, Obj vec2) { + RequireVec8BitRep(SELF_NAME, vec1); + RequireVec8BitRep(SELF_NAME, vec2); + UInt q; UInt len; len = LEN_VEC8BIT(vec2); @@ -4578,8 +4675,8 @@ static Obj FuncADD_COEFFS_VEC8BIT_2(Obj self, Obj vec1, Obj vec2) static Obj FuncSHIFT_VEC8BIT_LEFT(Obj self, Obj vec, Obj amount) { - if (!IS_MUTABLE_OBJ(vec)) - RequireArgument(SELF_NAME, vec, "must be mutable"); + RequireVec8BitRep(SELF_NAME, vec); + RequireMutable(SELF_NAME, vec, "vector"); RequireNonnegativeSmallInt(SELF_NAME, amount); ShiftLeftVec8Bit(vec, INT_INTOBJ(amount)); return (Obj)0; @@ -4593,9 +4690,10 @@ static Obj FuncSHIFT_VEC8BIT_LEFT(Obj self, Obj vec, Obj amount) static Obj FuncSHIFT_VEC8BIT_RIGHT(Obj self, Obj vec, Obj amount, Obj zero) { - if (!IS_MUTABLE_OBJ(vec)) - RequireArgument(SELF_NAME, vec, "must be mutable"); + RequireVec8BitRep(SELF_NAME, vec); + RequireMutable(SELF_NAME, vec, "vector"); RequireNonnegativeSmallInt(SELF_NAME, amount); + RequireFFE(SELF_NAME, zero); ShiftRightVec8Bit(vec, INT_INTOBJ(amount)); return (Obj)0; } @@ -4608,6 +4706,7 @@ static Obj FuncSHIFT_VEC8BIT_RIGHT(Obj self, Obj vec, Obj amount, Obj zero) static Obj FuncRESIZE_VEC8BIT(Obj self, Obj vec, Obj newsize) { + RequireVec8BitRep(SELF_NAME, vec); RequireMutable(SELF_NAME, vec, "vector"); RequireNonnegativeSmallInt(SELF_NAME, newsize); ResizeVec8Bit(vec, INT_INTOBJ(newsize), 0); @@ -4622,6 +4721,7 @@ static Obj FuncRESIZE_VEC8BIT(Obj self, Obj vec, Obj newsize) static Obj FuncRIGHTMOST_NONZERO_VEC8BIT(Obj self, Obj vec) { + RequireVec8BitRep(SELF_NAME, vec); return INTOBJ_INT(RightMostNonZeroVec8Bit(vec)); } @@ -4807,6 +4907,12 @@ static Obj FuncPROD_COEFFS_VEC8BIT(Obj self, Obj vl, Obj ll, Obj vr, Obj lr) Obj res; UInt lenp; UInt last; + + RequireVec8BitRep(SELF_NAME, vl); + RequireVec8BitRep(SELF_NAME, vr); + RequireNonnegativeSmallInt(SELF_NAME, ll); + RequireNonnegativeSmallInt(SELF_NAME, lr); + q = FIELD_VEC8BIT(vl); if (q != FIELD_VEC8BIT(vr)) { Obj info1; @@ -4837,8 +4943,6 @@ static Obj FuncPROD_COEFFS_VEC8BIT(Obj self, Obj vl, Obj ll, Obj vr, Obj lr) q = q0; } - RequireNonnegativeSmallInt(SELF_NAME, ll); - RequireNonnegativeSmallInt(SELF_NAME, lr); ll1 = INT_INTOBJ(ll); lr1 = INT_INTOBJ(lr); if (0 > ll1 || ll1 > LEN_VEC8BIT(vl)) @@ -4855,7 +4959,8 @@ static Obj FuncPROD_COEFFS_VEC8BIT(Obj self, Obj vl, Obj ll, Obj vr, Obj lr) else lenp = ll1 + lr1 - 1; res = ZeroVec8Bit(q, lenp, 1); - ProdCoeffsVec8Bit(res, vl, ll1, vr, lr1); + if (lenp > 0) + ProdCoeffsVec8Bit(res, vl, ll1, vr, lr1); last = RightMostNonZeroVec8Bit(res); if (last != lenp) ResizeVec8Bit(res, last, 1); @@ -5060,10 +5165,11 @@ static Obj FuncREDUCE_COEFFS_VEC8BIT(Obj self, Obj vl, Obj ll, Obj vrshifted) UInt last; RequireVec8BitRep(SELF_NAME, vl); + RequireNonnegativeSmallInt(SELF_NAME, ll); + RequirePlainList(SELF_NAME, vrshifted); q = FIELD_VEC8BIT(vl); if (q != FIELD_VEC8BIT(ELM_PLIST(vrshifted, 1))) return Fail; - RequireNonnegativeSmallInt(SELF_NAME, ll); if (INT_INTOBJ(ll) > LEN_VEC8BIT(vl)) { ErrorQuit("ReduceCoeffs: given length of left argt (%d) is " "longer than the argt (%d)", @@ -5397,7 +5503,7 @@ static Obj FuncSEMIECHELON_LIST_VEC8BITS(Obj self, Obj mat) Obj row; UInt q; - GAP_ASSERT(IS_PLIST(mat)); + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) @@ -5436,7 +5542,7 @@ static Obj FuncSEMIECHELON_LIST_VEC8BITS_TRANSFORMATIONS(Obj self, Obj mat) UInt q; UInt width; - GAP_ASSERT(IS_PLIST(mat)); + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) @@ -5475,7 +5581,7 @@ static Obj FuncTRIANGULIZE_LIST_VEC8BITS(Obj self, Obj mat) Obj row; UInt q; - GAP_ASSERT(IS_PLIST(mat)); + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) @@ -5514,7 +5620,7 @@ static Obj FuncRANK_LIST_VEC8BITS(Obj self, Obj mat) Obj row; UInt q; - GAP_ASSERT(IS_PLIST(mat)); + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) @@ -5553,7 +5659,7 @@ static Obj FuncDETERMINANT_LIST_VEC8BITS(Obj self, Obj mat) UInt q; Obj det; - GAP_ASSERT(IS_PLIST(mat)); + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) @@ -5613,8 +5719,8 @@ static Int Cmp_MAT8BIT_MAT8BIT(Obj ml, Obj mr) static Obj FuncEQ_MAT8BIT_MAT8BIT(Obj self, Obj ml, Obj mr) { - GAP_ASSERT(IS_MAT8BIT_REP(ml)); - GAP_ASSERT(IS_MAT8BIT_REP(mr)); + RequireMat8BitRep(SELF_NAME, ml); + RequireMat8BitRep(SELF_NAME, mr); if (LEN_MAT8BIT(ml) != LEN_MAT8BIT(mr)) return False; @@ -5632,8 +5738,8 @@ static Obj FuncEQ_MAT8BIT_MAT8BIT(Obj self, Obj ml, Obj mr) static Obj FuncLT_MAT8BIT_MAT8BIT(Obj self, Obj ml, Obj mr) { - GAP_ASSERT(IS_MAT8BIT_REP(ml)); - GAP_ASSERT(IS_MAT8BIT_REP(mr)); + RequireMat8BitRep(SELF_NAME, ml); + RequireMat8BitRep(SELF_NAME, mr); if (LEN_MAT8BIT(ml) == 0) return (LEN_MAT8BIT(mr) != 0) ? True : False; @@ -5665,6 +5771,7 @@ static Obj FuncTRANSPOSED_MAT8BIT(Obj self, Obj mat) Obj type; RequireMat8BitRep(SELF_NAME, mat); + RequireNonemptyMat8BitRows(SELF_NAME, mat); // we will give result same type as mat // we assume here that there is a first row -- a zero row mat8bit is a @@ -5762,8 +5869,10 @@ static Obj FuncKRONECKERPRODUCT_MAT8BIT_MAT8BIT(Obj self, Obj matl, Obj matr) const UInt1 * getelt, *setelt, *scalar, *add; const UInt1 * datar; - GAP_ASSERT(IS_MAT8BIT_REP(matl)); - GAP_ASSERT(IS_MAT8BIT_REP(matr)); + RequireMat8BitRep(SELF_NAME, matl); + RequireMat8BitRep(SELF_NAME, matr); + RequireNonemptyMat8BitRows(SELF_NAME, matl); + RequireNonemptyMat8BitRows(SELF_NAME, matr); nrowl = LEN_MAT8BIT(matl); nrowr = LEN_MAT8BIT(matr); diff --git a/src/vecgf2.c b/src/vecgf2.c index 6c3e64a1c2..b3c7454cb0 100644 --- a/src/vecgf2.c +++ b/src/vecgf2.c @@ -86,6 +86,8 @@ Obj TYPE_LIST_GF2MAT_IMM; */ Obj IsGF2VectorRep; +Obj IsGF2MatrixRep; + /**************************************************************************** ** @@ -100,6 +102,18 @@ static Obj GF2One; */ static Obj GF2Zero; +#define RequireGF2VecRep(funcname, op) \ + RequireArgumentCondition(funcname, op, IS_GF2VEC_REP(op), \ + "must be a GF2 vector") + +#define RequireGF2MatRep(funcname, op) \ + RequireArgumentCondition(funcname, op, IS_GF2MAT_REP(op), \ + "must be a GF2 matrix") + +#define RequireFFE(funcname, op) \ + RequireArgumentCondition(funcname, op, IS_FFE(op), \ + "must be a finite field element") + /**************************************************************************** ** @@ -835,6 +849,12 @@ static Obj FuncPROD_GF2VEC_ANYMAT(Obj self, Obj vec, Obj mat) UInt i; UInt block = 0; + RequireGF2VecRep(SELF_NAME, vec); + RequirePlainList(SELF_NAME, mat); + + if (LEN_PLIST(mat) == 0) + return TRY_NEXT_METHOD; + len = LEN_GF2VEC(vec); if (len > LEN_PLIST(mat)) len = LEN_PLIST(mat); @@ -1389,6 +1409,7 @@ static void ConvGF2Vec(Obj list) */ static Obj FuncCONV_GF2VEC(Obj self, Obj list) { + RequireSmallList(SELF_NAME, list); ConvGF2Vec(list); return 0; } @@ -1467,7 +1488,6 @@ static Obj NewGF2Vec(Obj list) return res; } - /**************************************************************************** ** *F FuncCOPY_GF2VEC( , ) . . . . . convert into a GF2 vector rep @@ -1492,6 +1512,7 @@ static Obj FuncCONV_GF2MAT(Obj self, Obj list) UInt len, i; Obj tmp; UInt mut; + RequireSmallList(SELF_NAME, list); len = LEN_LIST(list); if (len == 0) return (Obj)0; @@ -1664,6 +1685,9 @@ static Int Cmp_GF2VEC_GF2VEC(Obj vl, Obj vr) */ static Obj FuncEQ_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) { + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); + // we can do this case MUCH faster if we just want equality if (LEN_GF2VEC(vl) != LEN_GF2VEC(vr)) return False; @@ -1677,6 +1701,7 @@ static Obj FuncEQ_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) */ static Obj FuncLEN_GF2VEC(Obj self, Obj list) { + RequireGF2VecRep(SELF_NAME, list); return INTOBJ_INT(LEN_GF2VEC(list)); } @@ -1692,6 +1717,7 @@ static Obj FuncLEN_GF2VEC(Obj self, Obj list) */ static Obj FuncELM0_GF2VEC(Obj self, Obj list, Obj pos) { + RequireGF2VecRep(SELF_NAME, list); UInt p = GetSmallInt(SELF_NAME, pos); if (LEN_GF2VEC(list) < p) { return Fail; @@ -1712,6 +1738,7 @@ static Obj FuncELM0_GF2VEC(Obj self, Obj list, Obj pos) */ static Obj FuncELM_GF2VEC(Obj self, Obj list, Obj pos) { + RequireGF2VecRep(SELF_NAME, list); UInt p = GetSmallInt(SELF_NAME, pos); if (LEN_GF2VEC(list) < p) { ErrorMayQuit("List Element: [%d] must have an assigned value", @@ -1743,6 +1770,8 @@ static Obj FuncELMS_GF2VEC(Obj self, Obj list, Obj poss) Int i; // loop variable Obj apos; + RequireGF2VecRep(SELF_NAME, list); + // get the length of lenList = LEN_GF2VEC(list); @@ -1830,6 +1859,8 @@ static Obj FuncELMS_GF2VEC(Obj self, Obj list, Obj poss) static Obj FuncASS_GF2VEC(Obj self, Obj list, Obj pos, Obj elm) { + RequireGF2VecRep(SELF_NAME, list); + // check that is mutable RequireMutable("List Assignment", list, "list"); @@ -1875,6 +1906,7 @@ static Obj FuncASS_GF2VEC(Obj self, Obj list, Obj pos, Obj elm) */ static Obj FuncPLAIN_GF2MAT(Obj self, Obj list) { + RequireGF2MatRep(SELF_NAME, list); PlainGF2Mat(list); return 0; } @@ -1892,6 +1924,8 @@ static Obj FuncPLAIN_GF2MAT(Obj self, Obj list) */ static Obj FuncASS_GF2MAT(Obj self, Obj list, Obj pos, Obj elm) { + RequireGF2MatRep(SELF_NAME, list); + // check that is mutable RequireMutable("List Assignment", list, "list"); @@ -1939,6 +1973,7 @@ static Obj FuncASS_GF2MAT(Obj self, Obj list, Obj pos, Obj elm) */ static Obj FuncELM_GF2MAT(Obj self, Obj mat, Obj row) { + RequireGF2MatRep(SELF_NAME, mat); UInt r = GetSmallInt(SELF_NAME, row); if (LEN_GF2MAT(mat) < r) { ErrorMayQuit("row index %d exceeds %d, the number of rows", r, @@ -1955,6 +1990,7 @@ static Obj FuncELM_GF2MAT(Obj self, Obj mat, Obj row) */ static Obj FuncSWAP_ROWS_GF2MAT(Obj self, Obj mat, Obj row1, Obj row2) { + RequireGF2MatRep(SELF_NAME, mat); RequireMutable(SELF_NAME, mat, "mat"); UInt r1 = GetSmallInt(SELF_NAME, row1); @@ -1984,6 +2020,7 @@ static Obj FuncSWAP_ROWS_GF2MAT(Obj self, Obj mat, Obj row1, Obj row2) */ static Obj FuncSWAP_COLS_GF2MAT(Obj self, Obj mat, Obj col1, Obj col2) { + RequireGF2MatRep(SELF_NAME, mat); UInt c1 = GetSmallInt(SELF_NAME, col1); UInt c2 = GetSmallInt(SELF_NAME, col2); UInt m = LEN_GF2MAT(mat); @@ -2032,6 +2069,8 @@ static Obj FuncSWAP_COLS_GF2MAT(Obj self, Obj mat, Obj col1, Obj col2) */ static Obj FuncUNB_GF2VEC(Obj self, Obj list, Obj pos) { + RequireGF2VecRep(SELF_NAME, list); + // check that is mutable RequireMutable("List Unbind", list, "vector"); @@ -2069,6 +2108,8 @@ static Obj FuncUNB_GF2VEC(Obj self, Obj list, Obj pos) */ static Obj FuncUNB_GF2MAT(Obj self, Obj list, Obj pos) { + RequireGF2MatRep(SELF_NAME, list); + // check that is mutable RequireMutable("List Unbind", list, "matrix"); @@ -2108,6 +2149,8 @@ static Obj FuncZERO_GF2VEC(Obj self, Obj mat) Obj zero; UInt len; + RequireGF2VecRep(SELF_NAME, mat); + // create a new GF2 vector len = LEN_GF2VEC(mat); NEW_GF2VEC(zero, TYPE_LIST_GF2VEC, len); @@ -2141,6 +2184,8 @@ static Obj FuncINV_GF2MAT_MUTABLE(Obj self, Obj mat) { UInt len; + RequireGF2MatRep(SELF_NAME, mat); + len = LEN_GF2MAT(mat); if (len != 0) { if (len != LEN_GF2VEC(ELM_GF2MAT(mat, 1))) { @@ -2162,6 +2207,8 @@ static Obj FuncINV_GF2MAT_SAME_MUTABILITY(Obj self, Obj mat) { UInt len; + RequireGF2MatRep(SELF_NAME, mat); + len = LEN_GF2MAT(mat); if (len != 0) { if (len != LEN_GF2VEC(ELM_GF2MAT(mat, 1))) { @@ -2183,6 +2230,8 @@ static Obj FuncINV_GF2MAT_IMMUTABLE(Obj self, Obj mat) { UInt len; + RequireGF2MatRep(SELF_NAME, mat); + len = LEN_GF2MAT(mat); if (len != 0) { if (len != LEN_GF2VEC(ELM_GF2MAT(mat, 1))) { @@ -2203,6 +2252,7 @@ static Obj FuncINV_PLIST_GF2VECS_DESTRUCTIVE(Obj self, Obj list) { UInt len, i; Obj row; + RequirePlainList(SELF_NAME, list); len = LEN_PLIST(list); for (i = 1; i <= len; i++) { row = ELM_PLIST(list, i); @@ -2242,6 +2292,9 @@ static Obj FuncSUM_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) Obj sum; // sum, result UInt ll, lr; + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); + ll = LEN_GF2VEC(vl); lr = LEN_GF2VEC(vr); @@ -2269,6 +2322,9 @@ static Obj FuncSUM_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) */ static Obj FuncMULT_VECTOR_GF2VECS_2(Obj self, Obj vl, Obj mul) { + RequireGF2VecRep(SELF_NAME, vl); + RequireFFE(SELF_NAME, mul); + if (EQ(mul, GF2One)) return (Obj)0; else if (EQ(mul, GF2Zero)) { @@ -2289,6 +2345,8 @@ static Obj FuncMULT_VECTOR_GF2VECS_2(Obj self, Obj vl, Obj mul) */ static Obj FuncPROD_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) { + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); return ProdGF2VecGF2Vec(vl, vr); } @@ -2305,6 +2363,8 @@ static Obj FuncPROD_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) */ static Obj FuncPROD_GF2VEC_GF2MAT(Obj self, Obj vl, Obj vr) { + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2MatRep(SELF_NAME, vr); return ProdGF2VecGF2Mat(vl, vr); } @@ -2320,6 +2380,8 @@ static Obj FuncPROD_GF2VEC_GF2MAT(Obj self, Obj vl, Obj vr) */ static Obj FuncPROD_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr) { + RequireGF2MatRep(SELF_NAME, ml); + RequireGF2MatRep(SELF_NAME, mr); UInt lenl = LEN_GF2MAT(ml); UInt lenm; if (lenl >= 128) { @@ -2344,6 +2406,8 @@ static Obj FuncPROD_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr) */ static Obj FuncPROD_GF2MAT_GF2MAT_SIMPLE(Obj self, Obj ml, Obj mr) { + RequireGF2MatRep(SELF_NAME, ml); + RequireGF2MatRep(SELF_NAME, mr); return ProdGF2MatGF2MatSimple(ml, mr); } @@ -2362,6 +2426,10 @@ static Obj FuncPROD_GF2MAT_GF2MAT_SIMPLE(Obj self, Obj ml, Obj mr) static Obj FuncPROD_GF2MAT_GF2MAT_ADVANCED( Obj self, Obj ml, Obj mr, Obj greaselevel, Obj blocksize) { + RequireGF2MatRep(SELF_NAME, ml); + RequireGF2MatRep(SELF_NAME, mr); + RequireSmallInt(SELF_NAME, greaselevel); + RequireSmallInt(SELF_NAME, blocksize); return ProdGF2MatGF2MatAdvanced(ml, mr, INT_INTOBJ(greaselevel), INT_INTOBJ(blocksize)); } @@ -2379,6 +2447,8 @@ static Obj FuncPROD_GF2MAT_GF2MAT_ADVANCED( */ static Obj FuncPROD_GF2MAT_GF2VEC(Obj self, Obj vl, Obj vr) { + RequireGF2MatRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); return ProdGF2MatGF2Vec(vl, vr); } @@ -2389,6 +2459,10 @@ static Obj FuncPROD_GF2MAT_GF2VEC(Obj self, Obj vl, Obj vr) */ static Obj FuncADDCOEFFS_GF2VEC_GF2VEC_MULT(Obj self, Obj vl, Obj vr, Obj mul) { + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); + RequireFFE(SELF_NAME, mul); + // do nothing if is zero if (EQ(mul, GF2Zero)) { return INTOBJ_INT(RightMostOneGF2Vec(vl)); @@ -2409,6 +2483,8 @@ static Obj FuncADDCOEFFS_GF2VEC_GF2VEC_MULT(Obj self, Obj vl, Obj vr, Obj mul) */ static Obj FuncADDCOEFFS_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) { + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); return AddCoeffsGF2VecGF2Vec(vl, vr); } @@ -2425,6 +2501,8 @@ static Obj FuncSHRINKCOEFFS_GF2VEC(Obj self, Obj vec) UInt * ptr; UInt off; + RequireGF2VecRep(SELF_NAME, vec); + // get length and number of blocks len = LEN_GF2VEC(vec); if (len == 0) { @@ -2522,11 +2600,14 @@ static UInt PositionNonZeroGF2Vec(Obj vec, UInt from) static Obj FuncPOSITION_NONZERO_GF2VEC(Obj self, Obj vec, Obj zero) { + RequireGF2VecRep(SELF_NAME, vec); return INTOBJ_INT(PositionNonZeroGF2Vec(vec, 0)); } static Obj FuncPOSITION_NONZERO_GF2VEC3(Obj self, Obj vec, Obj zero, Obj from) { + RequireGF2VecRep(SELF_NAME, vec); + RequireNonnegativeSmallInt(SELF_NAME, from); return INTOBJ_INT(PositionNonZeroGF2Vec(vec, INT_INTOBJ(from))); } @@ -2538,12 +2619,8 @@ static Obj FuncCOPY_SECTION_GF2VECS( Int ito = GetPositiveSmallInt(SELF_NAME, to); Int ihowmany = GetSmallInt(SELF_NAME, howmany); - if (!IS_GF2VEC_REP(src)) { - RequireArgument(SELF_NAME, src, "must be a GF2 vector"); - } - if (!IS_GF2VEC_REP(dest)) { - RequireArgument(SELF_NAME, dest, "must be a GF2 vector"); - } + RequireGF2VecRep(SELF_NAME, src); + RequireGF2VecRep(SELF_NAME, dest); UInt lens = LEN_GF2VEC(src); UInt lend = LEN_GF2VEC(dest); @@ -2566,6 +2643,9 @@ static Obj FuncCOPY_SECTION_GF2VECS( static Obj FuncAPPEND_GF2VEC(Obj self, Obj vecl, Obj vecr) { UInt lenl, lenr; + RequireGF2VecRep(SELF_NAME, vecl); + RequireGF2VecRep(SELF_NAME, vecr); + RequireMutable(SELF_NAME, vecl, "vector"); lenl = LEN_GF2VEC(vecl); lenr = LEN_GF2VEC(vecr); if (True == DoFilter(IsLockedRepresentationVector, vecl) && lenr > 0) { @@ -2586,6 +2666,7 @@ static Obj FuncAPPEND_GF2VEC(Obj self, Obj vecl, Obj vecr) static Obj FuncSHALLOWCOPY_GF2VEC(Obj self, Obj vec) { + RequireGF2VecRep(SELF_NAME, vec); return ShallowCopyVecGF2(vec); } @@ -2603,6 +2684,8 @@ static Obj FuncSUM_GF2MAT_GF2MAT(Obj self, Obj matl, Obj matr) Obj vl, vr, sv; UInt i; Obj rtype; + RequireGF2MatRep(SELF_NAME, matl); + RequireGF2MatRep(SELF_NAME, matr); ll = LEN_GF2MAT(matl); lr = LEN_GF2MAT(matr); if (ll > lr) { @@ -2695,10 +2778,11 @@ static Obj FuncTRANSPOSED_GF2MAT(Obj self, Obj mat) UInt imod, nrb, nstart; UInt i, j, k, n; - if (TNUM_OBJ(mat) != T_POSOBJ) { - ErrorMayQuit("TRANSPOSED_GF2MAT: Need compressed matrix over GF(2)", - 0, 0); - } + RequireGF2MatRep(SELF_NAME, mat); + + if (LEN_GF2MAT(mat) == 0) + return TRY_NEXT_METHOD; + // type for mat typ = TYPE_LIST_GF2MAT; @@ -2780,6 +2864,7 @@ static Obj FuncNUMBER_GF2VEC(Obj self, Obj vec) Obj zahl; // the long number UInt * num2; mp_limb_t * vp; + RequireGF2VecRep(SELF_NAME, vec); len = LEN_GF2VEC(vec); if (len == 0) return INTOBJ_INT(1); @@ -2842,6 +2927,8 @@ static Obj FuncNUMBER_GF2VEC(Obj self, Obj vec) */ static Obj FuncLT_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) { + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); return (Cmp_GF2VEC_GF2VEC(vl, vr) < 0) ? True : False; } @@ -2876,6 +2963,8 @@ static Int Cmp_GF2MAT_GF2MAT(Obj ml, Obj mr) static Obj FuncEQ_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr) { + RequireGF2MatRep(SELF_NAME, ml); + RequireGF2MatRep(SELF_NAME, mr); if (ELM_PLIST(ml, 1) != ELM_PLIST(mr, 1)) return False; return (0 == Cmp_GF2MAT_GF2MAT(ml, mr)) ? True : False; @@ -2888,6 +2977,8 @@ static Obj FuncEQ_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr) static Obj FuncLT_GF2MAT_GF2MAT(Obj self, Obj ml, Obj mr) { + RequireGF2MatRep(SELF_NAME, ml); + RequireGF2MatRep(SELF_NAME, mr); return (Cmp_GF2MAT_GF2MAT(ml, mr) < 0) ? True : False; } @@ -2931,6 +3022,8 @@ static Obj FuncDIST_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) UInt * ptL; // bit field of UInt * ptR; // bit field of UInt * end; // pointer used to zero out end bit + RequireGF2VecRep(SELF_NAME, vl); + RequireGF2VecRep(SELF_NAME, vr); // get and check the length len = LEN_GF2VEC(vl); @@ -2938,6 +3031,8 @@ static Obj FuncDIST_GF2VEC_GF2VEC(Obj self, Obj vl, Obj vr) ErrorMayQuit("DIST_GF2VEC_GF2VEC: vectors must have the same length", 0, 0); } + if (len == 0) + return INTOBJ_INT(0); // calculate the offsets ptL = BLOCKS_GF2VEC(vl); @@ -3010,6 +3105,10 @@ static Obj FuncDIST_VEC_CLOS_VEC( Obj sum; // sum vector UInt len; + RequirePlainList(SELF_NAME, veclis); + RequireGF2VecRep(SELF_NAME, vec); + RequirePlainList(SELF_NAME, d); + len = LEN_GF2VEC(vec); // get space for sum vector @@ -3123,6 +3222,9 @@ static Obj FuncA_CLOS_VEC( Obj best; // best vector UInt len; + RequirePlainList(SELF_NAME, veclis); + RequireGF2VecRep(SELF_NAME, vec); + len = LEN_GF2VEC(vec); RequireNonnegativeSmallInt(SELF_NAME, cnt); @@ -3155,6 +3257,9 @@ static Obj FuncA_CLOS_VEC_COORDS( Obj res; // length 2 plist for results UInt len, len2, i; + RequirePlainList(SELF_NAME, veclis); + RequireGF2VecRep(SELF_NAME, vec); + len = LEN_GF2VEC(vec); len2 = LEN_PLIST(veclis); @@ -3293,6 +3398,7 @@ static Obj FuncCOSET_LEADERS_INNER_GF2( static Obj FuncRIGHTMOST_NONZERO_GF2VEC(Obj self, Obj vec) { + RequireGF2VecRep(SELF_NAME, vec); return INTOBJ_INT(RightMostOneGF2Vec(vec)); } @@ -3362,6 +3468,7 @@ static void ResizeGF2Vec(Obj vec, UInt newlen) static Obj FuncRESIZE_GF2VEC(Obj self, Obj vec, Obj newlen) { + RequireGF2VecRep(SELF_NAME, vec); RequireMutable(SELF_NAME, vec, "vector"); RequireNonnegativeSmallInt(SELF_NAME, newlen); ResizeGF2Vec(vec, INT_INTOBJ(newlen)); @@ -3421,6 +3528,7 @@ static void ShiftLeftGF2Vec(Obj vec, UInt amount) static Obj FuncSHIFT_LEFT_GF2VEC(Obj self, Obj vec, Obj amount) { + RequireGF2VecRep(SELF_NAME, vec); RequireMutable(SELF_NAME, vec, "vector"); RequireNonnegativeSmallInt(SELF_NAME, amount); ShiftLeftGF2Vec(vec, INT_INTOBJ(amount)); @@ -3484,8 +3592,10 @@ static void ShiftRightGF2Vec(Obj vec, UInt amount) static Obj FuncSHIFT_RIGHT_GF2VEC(Obj self, Obj vec, Obj amount, Obj zero) { + RequireGF2VecRep(SELF_NAME, vec); RequireMutable(SELF_NAME, vec, "vector"); RequireNonnegativeSmallInt(SELF_NAME, amount); + RequireFFE(SELF_NAME, zero); ShiftRightGF2Vec(vec, INT_INTOBJ(amount)); return (Obj)0; } @@ -3546,6 +3656,9 @@ static void AddShiftedVecGF2VecGF2(Obj vec1, Obj vec2, UInt len2, UInt off) static Obj FuncADD_GF2VEC_GF2VEC_SHIFTED(Obj self, Obj vec1, Obj vec2, Obj len2, Obj off) { + RequireGF2VecRep(SELF_NAME, vec1); + RequireGF2VecRep(SELF_NAME, vec2); + RequireMutable(SELF_NAME, vec1, "vector"); RequireNonnegativeSmallInt(SELF_NAME, off); RequireNonnegativeSmallInt(SELF_NAME, len2); Int off1 = INT_INTOBJ(off); @@ -3619,8 +3732,8 @@ FuncPROD_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2) Obj prod; UInt last; - RequireSmallInt(SELF_NAME, len1); - RequireSmallInt(SELF_NAME, len2); + RequireNonnegativeSmallInt(SELF_NAME, len1); + RequireNonnegativeSmallInt(SELF_NAME, len2); len2a = INT_INTOBJ(len2); if (len2a > LEN_GF2VEC(vec2)) ErrorMayQuit("PROD_COEFFS_GF2VEC: must not be more than the " @@ -3686,6 +3799,9 @@ FuncREDUCE_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2) { UInt last; Int len2a; + RequireGF2VecRep(SELF_NAME, vec1); + RequireGF2VecRep(SELF_NAME, vec2); + RequireMutable(SELF_NAME, vec1, "vector"); RequireNonnegativeSmallInt(SELF_NAME, len1); RequireNonnegativeSmallInt(SELF_NAME, len2); if (INT_INTOBJ(len1) > LEN_GF2VEC(vec1)) @@ -3729,10 +3845,13 @@ static Obj FuncQUOTREM_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2) { Int len2a; - Int len1a = INT_INTOBJ(len1); + Int len1a; Obj quotv, remv, ret; + RequireGF2VecRep(SELF_NAME, vec1); + RequireGF2VecRep(SELF_NAME, vec2); RequireNonnegativeSmallInt(SELF_NAME, len1); RequireNonnegativeSmallInt(SELF_NAME, len2); + len1a = INT_INTOBJ(len1); if (INT_INTOBJ(len1) > LEN_GF2VEC(vec1)) ErrorMayQuit("QuotremCoeffs: given length of left argt " "(%d)\nis longer than the argt (%d)", @@ -3791,6 +3910,7 @@ static Obj FuncSEMIECHELON_LIST_GF2VECS(Obj self, Obj mat) UInt i, len; UInt width; Obj row; + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD; @@ -3825,6 +3945,7 @@ static Obj FuncSEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS(Obj self, Obj mat) UInt i, len; UInt width; Obj row; + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD; @@ -3855,6 +3976,7 @@ static Obj FuncTRIANGULIZE_LIST_GF2VECS(Obj self, Obj mat) UInt i, len; UInt width; Obj row; + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD; @@ -3886,6 +4008,7 @@ static Obj FuncRANK_LIST_GF2VECS(Obj self, Obj mat) UInt i, len; UInt width; Obj row; + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD; @@ -3916,6 +4039,7 @@ static Obj FuncDETERMINANT_LIST_GF2VECS(Obj self, Obj mat) UInt i, len; UInt width; Obj row; + RequirePlainList(SELF_NAME, mat); len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD; @@ -3948,6 +4072,9 @@ static Obj FuncKRONECKERPRODUCT_GF2MAT_GF2MAT(Obj self, Obj matl, Obj matr) UInt * data; const UInt * datar; + RequireGF2MatRep(SELF_NAME, matl); + RequireGF2MatRep(SELF_NAME, matr); + nrowl = LEN_GF2MAT(matl); nrowr = LEN_GF2MAT(matr); nrowp = nrowl * nrowr; @@ -4036,6 +4163,7 @@ static Obj FuncKRONECKERPRODUCT_GF2MAT_GF2MAT(Obj self, Obj matl, Obj matr) */ static Obj FuncMAT_ELM_GF2MAT(Obj self, Obj mat, Obj row, Obj col) { + RequireGF2MatRep(SELF_NAME, mat); UInt r = GetPositiveSmallInt(SELF_NAME, row); UInt c = GetPositiveSmallInt(SELF_NAME, col); @@ -4063,6 +4191,7 @@ static Obj FuncMAT_ELM_GF2MAT(Obj self, Obj mat, Obj row, Obj col) static Obj FuncSET_MAT_ELM_GF2MAT(Obj self, Obj mat, Obj row, Obj col, Obj elm) { + RequireGF2MatRep(SELF_NAME, mat); UInt r = GetPositiveSmallInt(SELF_NAME, row); UInt c = GetPositiveSmallInt(SELF_NAME, col); @@ -4203,6 +4332,7 @@ static Int InitKernel(StructInitInfo * module) InitCopyGVar("TYPE_LIST_GF2VEC_LOCKED", &TYPE_LIST_GF2VEC_LOCKED); ImportFuncFromLibrary("IsGF2VectorRep", &IsGF2VectorRep); + ImportFuncFromLibrary("IsGF2MatrixRep", &IsGF2MatrixRep); InitCopyGVar("TYPE_LIST_GF2MAT", &TYPE_LIST_GF2MAT); InitCopyGVar("TYPE_LIST_GF2MAT_IMM", &TYPE_LIST_GF2MAT_IMM); diff --git a/src/vecgf2.h b/src/vecgf2.h index ddeac8639a..8471236efd 100644 --- a/src/vecgf2.h +++ b/src/vecgf2.h @@ -20,6 +20,13 @@ #define IS_GF2VEC_REP(obj) \ (TNUM_OBJ(obj) == T_DATOBJ && DoFilter(IsGF2VectorRep, obj) == True) +/**************************************************************************** +** +*F IS_GF2MAT_REP( ) . . . . . . check that is in GF2 matrix rep +*/ +#define IS_GF2MAT_REP(obj) \ + (TNUM_OBJ(obj) == T_POSOBJ && DoFilter(IsGF2MatrixRep, obj) == True) + /**************************************************************************** ** @@ -234,6 +241,7 @@ extern Obj TYPE_LIST_GF2MAT_IMM; extern Obj IsGF2VectorRep; +extern Obj IsGF2MatrixRep; Obj ShallowCopyVecGF2(Obj vec); diff --git a/tst/testinstall/kernel/vec8bit.tst b/tst/testinstall/kernel/vec8bit.tst index 6e951a3ef0..b9fe3df7e4 100644 --- a/tst/testinstall/kernel/vec8bit.tst +++ b/tst/testinstall/kernel/vec8bit.tst @@ -2,11 +2,1198 @@ # Tests for functions defined in src/vec8bit.c # gap> START_TEST("kernel/vec8bit.tst"); +gap> q := 5;; +gap> z := 0*Z(q);; +gap> o := Z(q)^0;; +gap> t := Z(q);; +gap> V8 := function(list) +> local v; +> v := ShallowCopy(list); +> CONV_VEC8BIT(v, q); +> return v; +> end;; +gap> M8 := function(rows) +> local m, i; +> m := List(rows, ShallowCopy); +> for i in [1 .. Length(m)] do +> CONV_VEC8BIT(m[i], q); +> od; +> CONV_MAT8BIT(m, q); +> return m; +> end;; +gap> IM8 := function(rows) +> local m; +> m := M8(rows); +> MakeImmutable(m); +> return m; +> end;; +gap> ZeroRowMat8 := function() +> local m; +> m := []; +> CONV_MAT8BIT(m, q); +> return m; +> end;; +gap> Mx08 := n -> M8(List([1 .. n], i -> []));; +gap> Veclis8 := function(rows) +> local f, fdi, fdip, veclis, row, mults, j, mult; +> f := AsSSortedList(GF(q)); +> fdi := []; +> for j in [2 .. Length(f)] do +> fdi[j - 1] := f[j] - f[j - 1]; +> od; +> Add(fdi, -Last(f)); +> fdip := List(fdi, x -> Position(fdi, x)); +> veclis := []; +> for row in rows do +> mults := []; +> mults[Length(fdi) + 1] := false; +> for j in [1 .. Length(fdi)] do +> if fdip[j] < j then +> mult := mults[fdip[j]]; +> else +> mult := fdi[j] * row; +> fi; +> mults[j] := mult; +> od; +> Add(veclis, mults); +> od; +> return veclis; +> end;; +gap> empty := V8([]);; +gap> one := V8([o]);; +gap> oneZero := V8([z]);; +gap> pair := V8([o, t]);; +gap> pair2 := V8([t, o]);; +gap> f5 := AsSSortedList(GF(q));; # +# CONV_VEC8BIT +# +gap> v := [];; CONV_VEC8BIT(v, q); v; +< mutable compressed vector length 0 over GF(5) > + +# bad arguments +gap> CONV_VEC8BIT(fail, q); +Error, CONV_VEC8BIT: must be a small list (not the value 'fail') +gap> CONV_VEC8BIT(v, fail); +Error, CONV_VEC8BIT: must be a positive small integer (not the value 'fail\ +') + +# +# COPY_VEC8BIT +# +gap> v := [];; w := COPY_VEC8BIT(v, q); v; +< mutable compressed vector length 0 over GF(5) > +[ ] + +# bad arguments +gap> COPY_VEC8BIT(fail, q); +Error, COPY_VEC8BIT: must be a small list (not the value 'fail') +gap> COPY_VEC8BIT(v, fail); +Error, COPY_VEC8BIT: must be a positive small integer (not the value 'fail\ +') + +# +# PLAIN_VEC8BIT +# +gap> v := V8([]);; PLAIN_VEC8BIT(v);; IsPlistRep(v); Length(v); +true +0 + +# bad arguments +gap> PLAIN_VEC8BIT(fail); +Error, PLAIN_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fa\ +il') + +# +# LEN_VEC8BIT +# +gap> LEN_VEC8BIT(empty); +0 +gap> LEN_VEC8BIT(pair); +2 + +# bad arguments +gap> LEN_VEC8BIT(fail); +Error, LEN_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fail\ +') + +# +# ELM0_VEC8BIT +# +gap> ELM0_VEC8BIT(empty, 1); +fail +gap> ELM0_VEC8BIT(one, 1); +Z(5)^0 + +# bad arguments +gap> ELM0_VEC8BIT(fail, 1); +Error, ELM0_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fai\ +l') +gap> ELM0_VEC8BIT(empty, fail); +Error, ELM0_VEC8BIT: must be a positive small integer (not the value 'fa\ +il') + +# +# ELM_VEC8BIT +# +gap> ELM_VEC8BIT(one, 1); +Z(5)^0 + +# bad arguments +gap> ELM_VEC8BIT(fail, 1); +Error, ELM_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fail\ +') +gap> ELM_VEC8BIT(one, fail); +Error, ELM_VEC8BIT: must be a positive small integer (not the value 'fai\ +l') + +# +# ELMS_VEC8BIT +# +gap> ELMS_VEC8BIT(empty, []) = empty; +true +gap> ELMS_VEC8BIT(pair, [2]); # = V8([t])); +[ Z(5) ] + +# bad arguments +gap> ELMS_VEC8BIT(fail, []); +Error, ELMS_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fai\ +l') +gap> ELMS_VEC8BIT(empty, fail); +Error, ELMS_VEC8BIT: must be a plain list (not the value 'fail') + +# +# ELMS_VEC8BIT_RANGE +# +gap> ELMS_VEC8BIT_RANGE(one, [1 .. 1]); +Error, ELMS_VEC8BIT_RANGE: must be a range (not a strictly-sorted plai\ +n list of cyclotomics) +gap> ELMS_VEC8BIT_RANGE(pair, [1 .. 2]) = pair; +true + +# bad arguments +gap> ELMS_VEC8BIT_RANGE(fail, [1 .. 1]); +Error, ELMS_VEC8BIT_RANGE: must belong to Is8BitVectorRep (not the valu\ +e 'fail') +gap> ELMS_VEC8BIT_RANGE(one, fail); +Error, ELMS_VEC8BIT_RANGE: must be a range (not the value 'fail') + +# +# ASS_VEC8BIT +# +gap> v := V8([]);; ASS_VEC8BIT(v, 1, z);; v = V8([z]); +true +gap> v := [Z(23), Z(23)];; ConvertToVectorRep(v);; ASS_VEC8BIT(v, 1, Z(23^5));; +gap> Is8BitVectorRep(v); +false +gap> v; +[ z, Z(23) ] + +# bad arguments +gap> v := V8([z, z]);; +gap> ASS_VEC8BIT(fail, 1, z); +Error, ASS_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fail\ +') +gap> ASS_VEC8BIT(v, fail, z); +Error, ASS_VEC8BIT: must be a positive small integer (not the value 'fai\ +l') +gap> ASS_VEC8BIT(v, 1, fail);; +gap> IsPlistRep(v); +true +gap> v; +[ fail, 0*Z(5) ] + +# +# UNB_VEC8BIT +# +gap> v := V8([o]);; UNB_VEC8BIT(v, 1);; v = empty; +true + +# bad arguments +gap> UNB_VEC8BIT(fail, 1); +Error, UNB_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fail\ +') +gap> UNB_VEC8BIT(v, fail); +Error, UNB_VEC8BIT: must be a positive small integer (not the value 'fai\ +l') + +# +# Q_VEC8BIT +# +gap> Q_VEC8BIT(empty); +5 + +# bad arguments +gap> Q_VEC8BIT(fail); +Error, Q_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fail') + +# +# SHALLOWCOPY_VEC8BIT +# +gap> v := SHALLOWCOPY_VEC8BIT(empty);; v = empty and not IsIdenticalObj(v, empty); +true + +# bad arguments +gap> SHALLOWCOPY_VEC8BIT(fail); +Error, SHALLOWCOPY_VEC8BIT: must belong to Is8BitVectorRep (not the val\ +ue 'fail') + +# +# SUM_VEC8BIT_VEC8BIT +# +gap> SUM_VEC8BIT_VEC8BIT(empty, empty); +< mutable compressed vector length 0 over GF(5) > +gap> SUM_VEC8BIT_VEC8BIT(one, oneZero); +[ Z(5)^0 ] + +# bad arguments +gap> SUM_VEC8BIT_VEC8BIT(fail, empty); +Error, SUM_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the value\ + 'fail') +gap> SUM_VEC8BIT_VEC8BIT(empty, fail); +Error, SUM_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the value\ + 'fail') + +# +# DIFF_VEC8BIT_VEC8BIT +# +gap> DIFF_VEC8BIT_VEC8BIT(empty, empty); +< mutable compressed vector length 0 over GF(5) > +gap> DIFF_VEC8BIT_VEC8BIT(one, oneZero); +[ Z(5)^0 ] + +# bad arguments +gap> DIFF_VEC8BIT_VEC8BIT(fail, empty); +Error, DIFF_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the valu\ +e 'fail') +gap> DIFF_VEC8BIT_VEC8BIT(empty, fail); +Error, DIFF_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the valu\ +e 'fail') + +# +# PROD_VEC8BIT_FFE +# +gap> PROD_VEC8BIT_FFE(empty, o); +< mutable compressed vector length 0 over GF(5) > +gap> PROD_VEC8BIT_FFE(one, z); +[ 0*Z(5) ] + +# bad arguments +gap> PROD_VEC8BIT_FFE(fail, o); +Error, PROD_VEC8BIT_FFE: must belong to Is8BitVectorRep (not the value '\ +fail') +gap> PROD_VEC8BIT_FFE(empty, fail); +Error, PROD_VEC8BIT_FFE: must be a finite field element (not the value '\ +fail') + +# +# PROD_FFE_VEC8BIT +# +gap> PROD_FFE_VEC8BIT(o, empty); +< mutable compressed vector length 0 over GF(5) > +gap> PROD_FFE_VEC8BIT(z, one); +[ 0*Z(5) ] + +# bad arguments +gap> PROD_FFE_VEC8BIT(fail, empty); +Error, PROD_FFE_VEC8BIT: must be a finite field element (not the value '\ +fail') +gap> PROD_FFE_VEC8BIT(o, fail); +Error, PROD_FFE_VEC8BIT: must belong to Is8BitVectorRep (not the value '\ +fail') + +# +# AINV_VEC8BIT_MUTABLE +# +gap> AINV_VEC8BIT_MUTABLE(empty); +< mutable compressed vector length 0 over GF(5) > +gap> AINV_VEC8BIT_MUTABLE(oneZero); +[ 0*Z(5) ] + +# bad arguments +gap> AINV_VEC8BIT_MUTABLE(fail); +Error, AINV_VEC8BIT_MUTABLE: must belong to Is8BitVectorRep (not the val\ +ue 'fail') + +# +# AINV_VEC8BIT_IMMUTABLE +# +gap> AINV_VEC8BIT_IMMUTABLE(empty); +< immutable compressed vector length 0 over GF(5) > +gap> AINV_VEC8BIT_IMMUTABLE(oneZero); +[ 0*Z(5) ] + +# bad arguments +gap> AINV_VEC8BIT_IMMUTABLE(fail); +Error, AINV_VEC8BIT_IMMUTABLE: must belong to Is8BitVectorRep (not the v\ +alue 'fail') + +# +# AINV_VEC8BIT_SAME_MUTABILITY +# +gap> AINV_VEC8BIT_SAME_MUTABILITY(empty); +< mutable compressed vector length 0 over GF(5) > +gap> AINV_VEC8BIT_SAME_MUTABILITY(oneZero); +[ 0*Z(5) ] + +# bad arguments +gap> AINV_VEC8BIT_SAME_MUTABILITY(fail); +Error, AINV_VEC8BIT_SAME_MUTABILITY: must belong to Is8BitVectorRep (not\ + the value 'fail') + +# +# ZERO_VEC8BIT +# +gap> ZERO_VEC8BIT(empty); +< mutable compressed vector length 0 over GF(5) > +gap> ZERO_VEC8BIT(pair); +[ 0*Z(5), 0*Z(5) ] + +# bad arguments +gap> ZERO_VEC8BIT(fail); +Error, ZERO_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fail\ +') + +# +# ZERO_VEC8BIT_2 +# +gap> ZERO_VEC8BIT_2(q, 0); +< mutable compressed vector length 0 over GF(5) > +gap> ZERO_VEC8BIT_2(q, 2); +[ 0*Z(5), 0*Z(5) ] + +# bad arguments +gap> ZERO_VEC8BIT_2(fail, 0); +Error, ZERO_VEC8BIT_2: must be a positive small integer (not the value 'fa\ +il') +gap> ZERO_VEC8BIT_2(q, fail); +Error, ZERO_VEC8BIT_2: must be a non-negative small integer (not the val\ +ue 'fail') + +# +# EQ_VEC8BIT_VEC8BIT +# +gap> EQ_VEC8BIT_VEC8BIT(empty, empty); +true +gap> EQ_VEC8BIT_VEC8BIT(empty, one); +false + +# bad arguments +gap> EQ_VEC8BIT_VEC8BIT(fail, empty); +Error, EQ_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the value \ +'fail') +gap> EQ_VEC8BIT_VEC8BIT(empty, fail); +Error, EQ_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the value \ +'fail') + +# +# LT_VEC8BIT_VEC8BIT +# +gap> LT_VEC8BIT_VEC8BIT(empty, one); +true +gap> LT_VEC8BIT_VEC8BIT(one, empty); +false + +# bad arguments +gap> LT_VEC8BIT_VEC8BIT(fail, one); +Error, LT_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the value \ +'fail') +gap> LT_VEC8BIT_VEC8BIT(empty, fail); +Error, LT_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the value \ +'fail') + +# +# PROD_VEC8BIT_VEC8BIT +# +gap> PROD_VEC8BIT_VEC8BIT(empty, empty); +0*Z(5) +gap> PROD_VEC8BIT_VEC8BIT(one, one); +Z(5)^0 + +# bad arguments +gap> PROD_VEC8BIT_VEC8BIT(fail, empty); +Error, PROD_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the valu\ +e 'fail') +gap> PROD_VEC8BIT_VEC8BIT(empty, fail); +Error, PROD_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the valu\ +e 'fail') + +# +# DISTANCE_VEC8BIT_VEC8BIT +# +gap> DISTANCE_VEC8BIT_VEC8BIT(empty, empty); +0 +gap> DISTANCE_VEC8BIT_VEC8BIT(one, oneZero); +1 + +# bad arguments +gap> DISTANCE_VEC8BIT_VEC8BIT(fail, empty); +Error, DISTANCE_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the \ +value 'fail') +gap> DISTANCE_VEC8BIT_VEC8BIT(empty, fail); +Error, DISTANCE_VEC8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the \ +value 'fail') + +# +# ADD_ROWVECTOR_VEC8BITS_5 +# +gap> v := V8([o, z]);; ADD_ROWVECTOR_VEC8BITS_5(v, V8([z, o]), o, 2, 2);; v = V8([o, o]); +true + +# bad arguments +gap> ADD_ROWVECTOR_VEC8BITS_5(fail, V8([z, o]), o, 2, 2); +Error, ADD_ROWVECTOR_VEC8BITS_5: must belong to Is8BitVectorRep (not the \ +value 'fail') +gap> ADD_ROWVECTOR_VEC8BITS_5(v, fail, o, 2, 2); +Error, ADD_ROWVECTOR_VEC8BITS_5: must belong to Is8BitVectorRep (not the \ +value 'fail') +gap> ADD_ROWVECTOR_VEC8BITS_5(v, V8([z, o]), fail, 2, 2); +Error, ADD_ROWVECTOR_VEC8BITS_5: must be a finite field element (not the\ + value 'fail') +gap> ADD_ROWVECTOR_VEC8BITS_5(v, V8([z, o]), o, fail, 2); +Error, ADD_ROWVECTOR_VEC8BITS_5: must be a positive small integer (not \ +the value 'fail') +gap> ADD_ROWVECTOR_VEC8BITS_5(v, V8([z, o]), o, 2, fail); +Error, ADD_ROWVECTOR_VEC8BITS_5: must be a positive small integer (not th\ +e value 'fail') + +# +# ADD_ROWVECTOR_VEC8BITS_3 +# +gap> v := V8([]);; ADD_ROWVECTOR_VEC8BITS_3(v, empty, o);; v = empty; +true + +# bad arguments +gap> ADD_ROWVECTOR_VEC8BITS_3(fail, empty, o); +Error, ADD_ROWVECTOR_VEC8BITS_3: must belong to Is8BitVectorRep (not the \ +value 'fail') +gap> ADD_ROWVECTOR_VEC8BITS_3(v, fail, o); +Error, ADD_ROWVECTOR_VEC8BITS_3: must belong to Is8BitVectorRep (not the \ +value 'fail') +gap> ADD_ROWVECTOR_VEC8BITS_3(v, empty, fail); +Error, ADD_ROWVECTOR_VEC8BITS_3: must be a finite field element (not the\ + value 'fail') + +# +# ADD_ROWVECTOR_VEC8BITS_2 +# +gap> v := V8([]);; ADD_ROWVECTOR_VEC8BITS_2(v, empty);; v = empty; +true + +# bad arguments +gap> ADD_ROWVECTOR_VEC8BITS_2(fail, empty); +Error, ADD_ROWVECTOR_VEC8BITS_2: must belong to Is8BitVectorRep (not the \ +value 'fail') +gap> ADD_ROWVECTOR_VEC8BITS_2(v, fail); +Error, ADD_ROWVECTOR_VEC8BITS_2: must belong to Is8BitVectorRep (not the \ +value 'fail') + +# +# MULT_VECTOR_VEC8BITS +# +gap> v := V8([]);; MULT_VECTOR_VEC8BITS(v, o);; v = empty; +true + +# bad arguments +gap> MULT_VECTOR_VEC8BITS(fail, o); +Error, MULT_VECTOR_VEC8BITS: must belong to Is8BitVectorRep (not the val\ +ue 'fail') +gap> MULT_VECTOR_VEC8BITS(v, fail); +Error, MULT_VECTOR_VEC8BITS: must be a finite field element (not the val\ +ue 'fail') + +# +# POSITION_NONZERO_VEC8BIT +# +gap> POSITION_NONZERO_VEC8BIT(empty, z); +1 +gap> POSITION_NONZERO_VEC8BIT(one, z); +1 + +# bad arguments +gap> POSITION_NONZERO_VEC8BIT(fail, z); +Error, POSITION_NONZERO_VEC8BIT: must belong to Is8BitVectorRep (not th\ +e value 'fail') +gap> POSITION_NONZERO_VEC8BIT(empty, fail); +1 + +# +# POSITION_NONZERO_VEC8BIT3 +# +gap> POSITION_NONZERO_VEC8BIT3(empty, z, 1); +1 +gap> POSITION_NONZERO_VEC8BIT3(V8([z, o]), z, 2); +3 + +# bad arguments +gap> POSITION_NONZERO_VEC8BIT3(fail, z, 1); +Error, POSITION_NONZERO_VEC8BIT3: must belong to Is8BitVectorRep (not t\ +he value 'fail') +gap> POSITION_NONZERO_VEC8BIT3(empty, fail, 1); +1 +gap> POSITION_NONZERO_VEC8BIT3(empty, z, fail); +Error, POSITION_NONZERO_VEC8BIT3: must be a non-negative small integer \ +(not the value 'fail') + +# +# APPEND_VEC8BIT +# +gap> v := V8([]);; APPEND_VEC8BIT(v, one);; v = one; +true + +# bad arguments +gap> APPEND_VEC8BIT(fail, one); +Error, APPEND_VEC8BIT: must belong to Is8BitVectorRep (not the value 'f\ +ail') +gap> APPEND_VEC8BIT(v, fail); +Error, APPEND_VEC8BIT: must belong to Is8BitVectorRep (not the value 'f\ +ail') + +# +# NUMBER_VEC8BIT +# +gap> NUMBER_VEC8BIT(empty); +1 +gap> NUMBER_VEC8BIT(one); +1 + +# bad arguments +gap> NUMBER_VEC8BIT(fail); +Error, NUMBER_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fa\ +il') + +# +# PROD_VEC8BIT_MATRIX +# +gap> PROD_VEC8BIT_MATRIX(one, [fail]); +"TRY_NEXT_METHOD" +gap> PROD_VEC8BIT_MATRIX(one, [one]); +[ Z(5)^0 ] + +# bad arguments +gap> PROD_VEC8BIT_MATRIX(fail, [fail]); +Error, PROD_VEC8BIT_MATRIX: must belong to Is8BitVectorRep (not the valu\ +e 'fail') +gap> PROD_VEC8BIT_MATRIX(one, fail); +Error, PROD_VEC8BIT_MATRIX: must be a plain list (not the value 'fail') + +# +# CONV_MAT8BIT +# +gap> m := [V8([]), V8([])];; CONV_MAT8BIT(m, q);; EQ_MAT8BIT_MAT8BIT(m, Mx08(2)); +true + +# bad arguments +gap> CONV_MAT8BIT(fail, q); +Error, CONV_MAT8BIT: must be a plain list (not the value 'fail') +gap> CONV_MAT8BIT(m, fail); +Error, CONV_MAT8BIT: must be a plain list (not a positional object) + +# +# PLAIN_MAT8BIT +# +gap> m := Mx08(2);; PLAIN_MAT8BIT(m);; IsPlistRep(m) and m = [[], []]; +true + +# bad arguments +gap> PLAIN_MAT8BIT(fail); +Error, PLAIN_MAT8BIT: must belong to Is8BitMatrixRep (not the value 'fai\ +l') + +# +# PROD_VEC8BIT_MAT8BIT +# +gap> PROD_VEC8BIT_MAT8BIT(empty, ZeroRowMat8()); +Error, PROD_VEC8BIT_MAT8BIT: compressed 8bit matrices with empty rows are not \ +supported +gap> PROD_VEC8BIT_MAT8BIT(empty, Mx08(2)); +< mutable compressed vector length 0 over GF(5) > + +# bad arguments +gap> PROD_VEC8BIT_MAT8BIT(fail, ZeroRowMat8()); +Error, PROD_VEC8BIT_MAT8BIT: must belong to Is8BitVectorRep (not the val\ +ue 'fail') +gap> PROD_VEC8BIT_MAT8BIT(empty, fail); +Error, PROD_VEC8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the val\ +ue 'fail') + +# +# PROD_MAT8BIT_VEC8BIT +# +gap> PROD_MAT8BIT_VEC8BIT(ZeroRowMat8(), empty); +Error, PROD_MAT8BIT_VEC8BIT: compressed 8bit matrices with empty rows are not \ +supported +gap> PROD_MAT8BIT_VEC8BIT(Mx08(2), empty); +[ 0*Z(5), 0*Z(5) ] + +# bad arguments +gap> PROD_MAT8BIT_VEC8BIT(fail, empty); +Error, PROD_MAT8BIT_VEC8BIT: must belong to Is8BitMatrixRep (not the val\ +ue 'fail') +gap> PROD_MAT8BIT_VEC8BIT(ZeroRowMat8(), fail); +Error, PROD_MAT8BIT_VEC8BIT: must belong to Is8BitVectorRep (not the val\ +ue 'fail') + +# +# PROD_MAT8BIT_MAT8BIT +# +gap> PROD_MAT8BIT_MAT8BIT(ZeroRowMat8(), ZeroRowMat8()); +Error, PROD_MAT8BIT_MAT8BIT: compressed 8bit matrices with empty rows are not \ +supported +gap> PROD_MAT8BIT_MAT8BIT(M8([[o], [z]]), Mx08(1)) = Mx08(2); +true + +# bad arguments +gap> PROD_MAT8BIT_MAT8BIT(fail, ZeroRowMat8()); +Error, PROD_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the va\ +lue 'fail') +gap> PROD_MAT8BIT_MAT8BIT(ZeroRowMat8(), fail); +Error, PROD_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the va\ +lue 'fail') + +# +# INV_MAT8BIT_MUTABLE +# +gap> INV_MAT8BIT_MUTABLE(ZeroRowMat8()); +Error, INV_MAT8BIT_MUTABLE: compressed 8bit matrices with empty rows are not s\ +upported +gap> INV_MAT8BIT_MUTABLE(M8([[o]])) = M8([[o]]); +true + +# bad arguments +gap> INV_MAT8BIT_MUTABLE(fail); +Error, INV_MAT8BIT_MUTABLE: must belong to Is8BitMatrixRep (not the valu\ +e 'fail') + +# +# INV_MAT8BIT_SAME_MUTABILITY +# +gap> INV_MAT8BIT_SAME_MUTABILITY(ZeroRowMat8()); +Error, INV_MAT8BIT_SAME_MUTABILITY: compressed 8bit matrices with empty rows a\ +re not supported +gap> INV_MAT8BIT_SAME_MUTABILITY(M8([[o]])) = M8([[o]]); +true + +# bad arguments +gap> INV_MAT8BIT_SAME_MUTABILITY(fail); +Error, INV_MAT8BIT_SAME_MUTABILITY: must belong to Is8BitMatrixRep (not \ +the value 'fail') + +# +# INV_MAT8BIT_IMMUTABLE +# +gap> INV_MAT8BIT_IMMUTABLE(ZeroRowMat8()); +Error, INV_MAT8BIT_IMMUTABLE: compressed 8bit matrices with empty rows are not\ + supported +gap> INV_MAT8BIT_IMMUTABLE(IM8([[o]])) = IM8([[o]]); +true + +# bad arguments +gap> INV_MAT8BIT_IMMUTABLE(fail); +Error, INV_MAT8BIT_IMMUTABLE: must belong to Is8BitMatrixRep (not the va\ +lue 'fail') + +# +# ASS_MAT8BIT +# +gap> ASS_MAT8BIT(ZeroRowMat8(), 1, empty); +Error, ASS_MAT8BIT: compressed 8bit matrices with empty rows are not supported +gap> m := Mx08(1);; ASS_MAT8BIT(m, 2, empty);; m = Mx08(2); +true + +# bad arguments +gap> ASS_MAT8BIT(fail, 1, empty); +Error, ASS_MAT8BIT: must belong to Is8BitMatrixRep (not the value 'fail'\ +) +gap> ASS_MAT8BIT(ZeroRowMat8(), fail, empty); +Error, ASS_MAT8BIT: compressed 8bit matrices with empty rows are not supported +gap> ASS_MAT8BIT(ZeroRowMat8(), 1, fail); +Error, ASS_MAT8BIT: compressed 8bit matrices with empty rows are not supported + +# +# ELM_MAT8BIT +# +gap> ELM_MAT8BIT(Mx08(2), 1); +< mutable compressed vector length 0 over GF(5) > + +# bad arguments +gap> ELM_MAT8BIT(fail, 1); +Error, ELM_MAT8BIT: must belong to Is8BitMatrixRep (not the value 'fail'\ +) +gap> ELM_MAT8BIT(Mx08(2), fail); +Error, ELM_MAT8BIT: must be a positive small integer (not the value 'fai\ +l') + +# +# SWAP_ROWS_MAT8BIT +# +gap> m := Mx08(2);; SWAP_ROWS_MAT8BIT(m, 1, 2);; m = Mx08(2); +true + +# bad arguments +gap> SWAP_ROWS_MAT8BIT(fail, 1, 2); +Error, SWAP_ROWS_MAT8BIT: must belong to Is8BitMatrixRep (not the value \ +'fail') +gap> SWAP_ROWS_MAT8BIT(m, fail, 2); +Error, SWAP_ROWS_MAT8BIT: must be a small integer (not the value 'fail'\ +) +gap> SWAP_ROWS_MAT8BIT(m, 1, fail); +Error, SWAP_ROWS_MAT8BIT: must be a small integer (not the value 'fail'\ +) + +# +# SWAP_COLS_MAT8BIT +# +gap> m := ZeroRowMat8();; SWAP_COLS_MAT8BIT(m, 1, 1);; EQ_MAT8BIT_MAT8BIT(m, ZeroRowMat8()); +true + +# bad arguments +gap> SWAP_COLS_MAT8BIT(fail, 1, 1); +Error, SWAP_COLS_MAT8BIT: must belong to Is8BitMatrixRep (not the value \ +'fail') +gap> SWAP_COLS_MAT8BIT(m, fail, 1); +Error, SWAP_COLS_MAT8BIT: must be a small integer (not the value 'fail'\ +) +gap> SWAP_COLS_MAT8BIT(m, 1, fail); +Error, SWAP_COLS_MAT8BIT: must be a small integer (not the value 'fail'\ +) + +# +# SUM_MAT8BIT_MAT8BIT +# +gap> SUM_MAT8BIT_MAT8BIT(ZeroRowMat8(), ZeroRowMat8()); +Error, SUM_MAT8BIT_MAT8BIT: compressed 8bit matrices with empty rows are not s\ +upported +gap> SUM_MAT8BIT_MAT8BIT(Mx08(2), Mx08(2)) = Mx08(2); +true + +# bad arguments +gap> SUM_MAT8BIT_MAT8BIT(fail, ZeroRowMat8()); +Error, SUM_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the value\ + 'fail') +gap> SUM_MAT8BIT_MAT8BIT(ZeroRowMat8(), fail); +Error, SUM_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the value\ + 'fail') + +# +# DIFF_MAT8BIT_MAT8BIT +# +gap> DIFF_MAT8BIT_MAT8BIT(ZeroRowMat8(), ZeroRowMat8()); +Error, DIFF_MAT8BIT_MAT8BIT: compressed 8bit matrices with empty rows are not \ +supported +gap> DIFF_MAT8BIT_MAT8BIT(Mx08(2), Mx08(2)) = Mx08(2); +true + +# bad arguments +gap> DIFF_MAT8BIT_MAT8BIT(fail, ZeroRowMat8()); +Error, DIFF_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the valu\ +e 'fail') +gap> DIFF_MAT8BIT_MAT8BIT(ZeroRowMat8(), fail); +Error, DIFF_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the valu\ +e 'fail') + +# +# ADD_COEFFS_VEC8BIT_3 +# +gap> v := V8([]);; ADD_COEFFS_VEC8BIT_3(v, empty, o); +0 +gap> v; +< mutable compressed vector length 0 over GF(5) > + +# bad arguments +gap> ADD_COEFFS_VEC8BIT_3(fail, empty, o); +Error, ADD_COEFFS_VEC8BIT_3: must belong to Is8BitVectorRep (not the va\ +lue 'fail') +gap> ADD_COEFFS_VEC8BIT_3(v, fail, o); +Error, ADD_COEFFS_VEC8BIT_3: must belong to Is8BitVectorRep (not the va\ +lue 'fail') +gap> ADD_COEFFS_VEC8BIT_3(v, empty, fail); +Error, ADD_COEFFS_VEC8BIT_3: must be a finite field element (not the va\ +lue 'fail') + +# +# ADD_COEFFS_VEC8BIT_2 +# +gap> v := V8([]);; ADD_COEFFS_VEC8BIT_2(v, empty); +0 +gap> v; +< mutable compressed vector length 0 over GF(5) > + +# bad arguments +gap> ADD_COEFFS_VEC8BIT_2(fail, empty); +Error, ADD_COEFFS_VEC8BIT_2: must belong to Is8BitVectorRep (not the va\ +lue 'fail') +gap> ADD_COEFFS_VEC8BIT_2(v, fail); +Error, ADD_COEFFS_VEC8BIT_2: must belong to Is8BitVectorRep (not the va\ +lue 'fail') + +# +# SHIFT_VEC8BIT_LEFT +# +gap> v := V8([]);; SHIFT_VEC8BIT_LEFT(v, 3);; v = empty; +true + +# bad arguments +gap> SHIFT_VEC8BIT_LEFT(fail, 3); +Error, SHIFT_VEC8BIT_LEFT: must belong to Is8BitVectorRep (not the value\ + 'fail') +gap> SHIFT_VEC8BIT_LEFT(v, fail); +Error, SHIFT_VEC8BIT_LEFT: must be a non-negative small integer (not \ +the value 'fail') + +# +# SHIFT_VEC8BIT_RIGHT +# +gap> v := V8([]);; SHIFT_VEC8BIT_RIGHT(v, 3, z);; v = V8([z, z, z]); +true + +# bad arguments +gap> SHIFT_VEC8BIT_RIGHT(fail, 3, z); +Error, SHIFT_VEC8BIT_RIGHT: must belong to Is8BitVectorRep (not the valu\ +e 'fail') +gap> SHIFT_VEC8BIT_RIGHT(v, fail, z); +Error, SHIFT_VEC8BIT_RIGHT: must be a non-negative small integer (not\ + the value 'fail') +gap> SHIFT_VEC8BIT_RIGHT(v, 3, fail); +Error, SHIFT_VEC8BIT_RIGHT: must be a finite field element (not the val\ +ue 'fail') + +# +# RESIZE_VEC8BIT +# +gap> v := V8([]);; RESIZE_VEC8BIT(v, 2);; v = V8([z, z]); +true + +# bad arguments +gap> RESIZE_VEC8BIT(fail, 2); +Error, RESIZE_VEC8BIT: must belong to Is8BitVectorRep (not the value 'fa\ +il') +gap> RESIZE_VEC8BIT(v, fail); +Error, RESIZE_VEC8BIT: must be a non-negative small integer (not the\ + value 'fail') + +# +# RIGHTMOST_NONZERO_VEC8BIT +# +gap> RIGHTMOST_NONZERO_VEC8BIT(empty); +0 +gap> RIGHTMOST_NONZERO_VEC8BIT(V8([z, o])); +2 + +# bad arguments +gap> RIGHTMOST_NONZERO_VEC8BIT(fail); +Error, RIGHTMOST_NONZERO_VEC8BIT: must belong to Is8BitVectorRep (not th\ +e value 'fail') + +# +# PROD_COEFFS_VEC8BIT +# +gap> PROD_COEFFS_VEC8BIT(empty, 0, empty, 0); +< mutable compressed vector length 0 over GF(5) > +gap> PROD_COEFFS_VEC8BIT(one, 1, one, 1); +[ Z(5)^0 ] + +# bad arguments +gap> PROD_COEFFS_VEC8BIT(fail, 0, empty, 0); +Error, PROD_COEFFS_VEC8BIT: must belong to Is8BitVectorRep (not the value\ + 'fail') +gap> PROD_COEFFS_VEC8BIT(empty, fail, empty, 0); +Error, PROD_COEFFS_VEC8BIT: must be a non-negative small integer (not the\ + value 'fail') +gap> PROD_COEFFS_VEC8BIT(empty, 0, fail, 0); +Error, PROD_COEFFS_VEC8BIT: must belong to Is8BitVectorRep (not the value\ + 'fail') +gap> PROD_COEFFS_VEC8BIT(empty, 0, empty, fail); +Error, PROD_COEFFS_VEC8BIT: must be a non-negative small integer (not the\ + value 'fail') + +# +# REDUCE_COEFFS_VEC8BIT +# +gap> s := MAKE_SHIFTED_COEFFS_VEC8BIT(V8([o]), 1);; +gap> v := V8([o]);; REDUCE_COEFFS_VEC8BIT(v, 1, s); +0 +gap> v; +< mutable compressed vector length 0 over GF(5) > + +# bad arguments +gap> REDUCE_COEFFS_VEC8BIT(fail, 1, s); +Error, REDUCE_COEFFS_VEC8BIT: must belong to Is8BitVectorRep (not the val\ +ue 'fail') +gap> REDUCE_COEFFS_VEC8BIT(v, fail, s); +Error, REDUCE_COEFFS_VEC8BIT: must be a non-negative small integer (not t\ +he value 'fail') +gap> REDUCE_COEFFS_VEC8BIT(v, 1, fail); +Error, REDUCE_COEFFS_VEC8BIT: must be a plain list (not the value \ +'fail') + +# +# QUOTREM_COEFFS_VEC8BIT +# +gap> s := MAKE_SHIFTED_COEFFS_VEC8BIT(V8([o]), 1);; +gap> QUOTREM_COEFFS_VEC8BIT(empty, 0, s); +[ < mutable compressed vector length 0 over GF(5) >, + < mutable compressed vector length 0 over GF(5) > ] + +# bad arguments +gap> QUOTREM_COEFFS_VEC8BIT(fail, 0, s); +Error, QUOTREM_COEFFS_VEC8BIT: must belong to Is8BitVectorRep (not the va\ +lue 'fail') +gap> QUOTREM_COEFFS_VEC8BIT(empty, fail, s); +Error, QUOTREM_COEFFS_VEC8BIT: must be a non-negative small integer (not \ +the value 'fail') +gap> QUOTREM_COEFFS_VEC8BIT(empty, 0, fail); +Error, QUOTREM_COEFFS_VEC8BIT: must be a plain list (not the value\ + 'fail') + +# +# MAKE_SHIFTED_COEFFS_VEC8BIT +# +gap> s := MAKE_SHIFTED_COEFFS_VEC8BIT(V8([o]), 1);; s[4]; +1 +gap> s[5]; +Z(5)^0 + +# bad arguments +gap> MAKE_SHIFTED_COEFFS_VEC8BIT(fail, 1); +Error, MAKE_SHIFTED_COEFFS_VEC8BIT: must belong to Is8BitVectorRep (not t\ +he value 'fail') +gap> MAKE_SHIFTED_COEFFS_VEC8BIT(V8([o]), fail); +Error, MAKE_SHIFTED_COEFFS_VEC8BIT: must be a non-negative small integer \ +(not the value 'fail') + +# +# DISTANCE_DISTRIB_VEC8BITS +# +gap> d := [0, 0];; DISTANCE_DISTRIB_VEC8BITS(Veclis8([one]), oneZero, d);; d; +[ 1, 4 ] + +# bad arguments +gap> DISTANCE_DISTRIB_VEC8BITS(fail, oneZero, d); +Error, DISTANCE_DISTRIB_VEC8BITS: must be a plain list (not the value\ + 'fail') +gap> DISTANCE_DISTRIB_VEC8BITS(Veclis8([one]), fail, d); +Error, DISTANCE_DISTRIB_VEC8BITS: must belong to Is8BitVectorRep (not th\ +e value 'fail') +gap> DISTANCE_DISTRIB_VEC8BITS(Veclis8([one]), oneZero, fail); +Error, DISTANCE_DISTRIB_VEC8BITS: must be a plain list (not the value 'fai\ +l') + +# +# A_CLOSEST_VEC8BIT +# +gap> A_CLOSEST_VEC8BIT(Veclis8([one]), one, 0, 0); +[ Z(5)^0 ] + +# bad arguments +gap> A_CLOSEST_VEC8BIT(fail, one, 0, 0); +Error, A_CLOSEST_VEC8BIT: must be a plain list (not the value 'fail') +gap> A_CLOSEST_VEC8BIT(Veclis8([one]), fail, 0, 0); +Error, A_CLOSEST_VEC8BIT: must belong to Is8BitVectorRep (not the value \ +'fail') +gap> A_CLOSEST_VEC8BIT(Veclis8([one]), one, fail, 0); +Error, A_CLOSEST_VEC8BIT: must be a non-negative small integer (not the \ +value 'fail') +gap> A_CLOSEST_VEC8BIT(Veclis8([one]), one, 0, fail); +Error, A_CLOSEST_VEC8BIT: must be a non-negative small integer (not the\ + value 'fail') + +# +# A_CLOSEST_VEC8BIT_COORDS +# +gap> A_CLOSEST_VEC8BIT_COORDS(Veclis8([one]), one, 0, 0); +[ [ Z(5)^0 ], [ 1 ] ] + +# bad arguments +gap> A_CLOSEST_VEC8BIT_COORDS(fail, one, 0, 0); +Error, A_CLOSEST_VEC8BIT_COORDS: must be a plain list (not the value \ +'fail') +gap> A_CLOSEST_VEC8BIT_COORDS(Veclis8([one]), fail, 0, 0); +Error, A_CLOSEST_VEC8BIT_COORDS: must belong to Is8BitVectorRep (not the\ + value 'fail') +gap> A_CLOSEST_VEC8BIT_COORDS(Veclis8([one]), one, fail, 0); +Error, A_CLOSEST_VEC8BIT_COORDS: must be a non-negative small integer (n\ +ot the value 'fail') +gap> A_CLOSEST_VEC8BIT_COORDS(Veclis8([one]), one, 0, fail); +Error, A_CLOSEST_VEC8BIT_COORDS: must be a non-negative small integer (\ +not the value 'fail') + +# +# COSET_LEADERS_INNER_8BITS +# +gap> leaders := [Immutable(oneZero)];; leaders[6] := false;; + +#gap> COSET_LEADERS_INNER_8BITS(Veclis8([one]), 1, 1, leaders, f5); +#4 +#gap> leaders[2]; +#[ Z(5)^0 ] +# +# bad arguments +gap> COSET_LEADERS_INNER_8BITS(fail, 1, 1, leaders, f5); +Error, COSET_LEADERS_INNER_8BITS: must be a plain list (not the value\ + 'fail') +gap> COSET_LEADERS_INNER_8BITS(Veclis8([one]), fail, 1, leaders, f5); +Error, COSET_LEADERS_INNER_8BITS: must be a small integer (not the va\ +lue 'fail') +gap> COSET_LEADERS_INNER_8BITS(Veclis8([one]), 1, fail, leaders, f5); +Error, COSET_LEADERS_INNER_8BITS: must be a small integer (not the va\ +lue 'fail') +gap> COSET_LEADERS_INNER_8BITS(Veclis8([one]), 1, 1, fail, f5); +Error, COSET_LEADERS_INNER_8BITS: must be a plain list (not the valu\ +e 'fail') +gap> COSET_LEADERS_INNER_8BITS(Veclis8([one]), 1, 1, leaders, fail); +Error, COSET_LEADERS_INNER_8BITS: must be a plain list (not the value \ +'fail') + +# +# SEMIECHELON_LIST_VEC8BITS +# +gap> s := SEMIECHELON_LIST_VEC8BITS([one]);; s.heads = [1] and s.vectors = [one]; +true + +# bad arguments +gap> SEMIECHELON_LIST_VEC8BITS(fail); +Error, SEMIECHELON_LIST_VEC8BITS: must be a plain list (not the value 'f\ +ail') + +# +# SEMIECHELON_LIST_VEC8BITS_TRANSFORMATIONS +# +gap> s := SEMIECHELON_LIST_VEC8BITS_TRANSFORMATIONS([one]);; s.heads = [1] and s.vectors = [one] and s.coeffs = [one]; +true + +# bad arguments +gap> SEMIECHELON_LIST_VEC8BITS_TRANSFORMATIONS(fail); +Error, SEMIECHELON_LIST_VEC8BITS_TRANSFORMATIONS: must be a plain list (\ +not the value 'fail') + +# +# TRIANGULIZE_LIST_VEC8BITS +# +gap> m := [one];; TRIANGULIZE_LIST_VEC8BITS(m);; m = [one]; +true + +# bad arguments +gap> TRIANGULIZE_LIST_VEC8BITS(fail); +Error, TRIANGULIZE_LIST_VEC8BITS: must be a plain list (not the value 'f\ +ail') + +# +# RANK_LIST_VEC8BITS +# +gap> RANK_LIST_VEC8BITS([one]); +1 + +# bad arguments +gap> RANK_LIST_VEC8BITS(fail); +Error, RANK_LIST_VEC8BITS: must be a plain list (not the value 'fail') + +# +# DETERMINANT_LIST_VEC8BITS +# +gap> DETERMINANT_LIST_VEC8BITS([one]); +Z(5)^0 + +# bad arguments +gap> DETERMINANT_LIST_VEC8BITS(fail); +Error, DETERMINANT_LIST_VEC8BITS: must be a plain list (not the value 'f\ +ail') + +# +# EQ_MAT8BIT_MAT8BIT +# +gap> EQ_MAT8BIT_MAT8BIT(Mx08(2), Mx08(2)) and EQ_MAT8BIT_MAT8BIT(ZeroRowMat8(), ZeroRowMat8()); +true + +# bad arguments +gap> EQ_MAT8BIT_MAT8BIT(fail, Mx08(2)); +Error, EQ_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the value \ +'fail') +gap> EQ_MAT8BIT_MAT8BIT(Mx08(2), fail); +Error, EQ_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the value \ +'fail') + +# +# LT_MAT8BIT_MAT8BIT +# +gap> LT_MAT8BIT_MAT8BIT(ZeroRowMat8(), Mx08(1)) and not LT_MAT8BIT_MAT8BIT(Mx08(1), ZeroRowMat8()); +true + +# bad arguments +gap> LT_MAT8BIT_MAT8BIT(fail, Mx08(1)); +Error, LT_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the value \ +'fail') +gap> LT_MAT8BIT_MAT8BIT(ZeroRowMat8(), fail); +Error, LT_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep (not the value \ +'fail') + +# +# TRANSPOSED_MAT8BIT +# +gap> TRANSPOSED_MAT8BIT(ZeroRowMat8()); +Error, TRANSPOSED_MAT8BIT: compressed 8bit matrices with empty rows are not su\ +pported +gap> EQ_MAT8BIT_MAT8BIT(TRANSPOSED_MAT8BIT(Mx08(2)), ZeroRowMat8()); +true + +# bad arguments gap> TRANSPOSED_MAT8BIT(fail); Error, TRANSPOSED_MAT8BIT: must belong to Is8BitMatrixRep (not the value\ 'fail') +# +# KRONECKERPRODUCT_MAT8BIT_MAT8BIT +# +gap> KRONECKERPRODUCT_MAT8BIT_MAT8BIT(ZeroRowMat8(), ZeroRowMat8()); +Error, KRONECKERPRODUCT_MAT8BIT_MAT8BIT: compressed 8bit matrices with empty r\ +ows are not supported +gap> KRONECKERPRODUCT_MAT8BIT_MAT8BIT(Mx08(2), M8([[o]])) = Mx08(2); +true + +# bad arguments +gap> KRONECKERPRODUCT_MAT8BIT_MAT8BIT(fail, ZeroRowMat8()); +Error, KRONECKERPRODUCT_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep\ + (not the value 'fail') +gap> KRONECKERPRODUCT_MAT8BIT_MAT8BIT(ZeroRowMat8(), fail); +Error, KRONECKERPRODUCT_MAT8BIT_MAT8BIT: must belong to Is8BitMatrixRep\ + (not the value 'fail') + +# +# MAT_ELM_MAT8BIT +# +gap> MAT_ELM_MAT8BIT(M8([[o]]), 1, 1); +Z(5)^0 + +# bad arguments +gap> MAT_ELM_MAT8BIT(fail, 1, 1); +Error, MAT_ELM_MAT8BIT: must belong to Is8BitMatrixRep (not the value 'f\ +ail') +gap> MAT_ELM_MAT8BIT(M8([[o]]), fail, 1); +Error, MAT_ELM_MAT8BIT: must be a positive small integer (not the value \ +'fail') +gap> MAT_ELM_MAT8BIT(M8([[o]]), 1, fail); +Error, MAT_ELM_MAT8BIT: must be a positive small integer (not the value \ +'fail') + +# +# SET_MAT_ELM_MAT8BIT +# +gap> m := M8([[z]]);; SET_MAT_ELM_MAT8BIT(m, 1, 1, o);; m = M8([[o]]); +true + +# bad arguments +gap> SET_MAT_ELM_MAT8BIT(fail, 1, 1, o); +Error, SET_MAT_ELM_MAT8BIT: must belong to Is8BitMatrixRep (not the valu\ +e 'fail') +gap> SET_MAT_ELM_MAT8BIT(m, fail, 1, o); +Error, SET_MAT_ELM_MAT8BIT: must be a positive small integer (not the va\ +lue 'fail') +gap> SET_MAT_ELM_MAT8BIT(m, 1, fail, o); +Error, SET_MAT_ELM_MAT8BIT: must be a positive small integer (not the va\ +lue 'fail') +gap> SET_MAT_ELM_MAT8BIT(m, 1, 1, fail); +Error, Attempt to convert locked compressed vector to plain list + # gap> STOP_TEST("kernel/vec8bit.tst"); diff --git a/tst/testinstall/kernel/vecgf2.tst b/tst/testinstall/kernel/vecgf2.tst index 7c4a838349..c3021d52cb 100644 --- a/tst/testinstall/kernel/vecgf2.tst +++ b/tst/testinstall/kernel/vecgf2.tst @@ -2,10 +2,981 @@ # Tests for functions defined in src/vecgf2.c # gap> START_TEST("kernel/vecgf2.tst"); +gap> z := 0*Z(2);; +gap> o := Z(2)^0;; +gap> V2 := function(list) +> local v; +> v := ShallowCopy(list); +> CONV_GF2VEC(v); +> return v; +> end;; +gap> M2 := function(rows) +> local m, i; +> m := List(rows, ShallowCopy); +> for i in [1 .. Length(m)] do +> CONV_GF2VEC(m[i]); +> od; +> CONV_GF2MAT(m); +> return m; +> end;; +gap> Mx02 := n -> M2(List([1 .. n], i -> []));; +gap> Veclis2 := function(rows) +> local f, fdi, fdip, veclis, row, mults, j, mult; +> f := AsSSortedList(GF(2)); +> fdi := []; +> for j in [2 .. Length(f)] do +> fdi[j - 1] := f[j] - f[j - 1]; +> od; +> Add(fdi, -Last(f)); +> fdip := List(fdi, x -> Position(fdi, x)); +> veclis := []; +> for row in rows do +> mults := []; +> mults[Length(fdi) + 1] := false; +> for j in [1 .. Length(fdi)] do +> if fdip[j] < j then +> mult := mults[fdip[j]]; +> else +> mult := fdi[j] * row; +> fi; +> mults[j] := mult; +> od; +> Add(veclis, mults); +> od; +> return veclis; +> end;; +gap> empty := V2([]);; +gap> one := V2([o]);; +gap> oneZero := V2([z]);; # +# CONV_GF2VEC +# +gap> v := [];; CONV_GF2VEC(v); v; + + +# bad arguments +gap> CONV_GF2VEC(fail); +Error, CONV_GF2VEC: must be a small list (not the value 'fail') + +# +# COPY_GF2VEC +# +gap> v := COPY_GF2VEC([]); + + +# bad arguments +gap> COPY_GF2VEC(fail); +Error, COPY_GF2VEC: argument must be a list of GF2 elements + +# +# PLAIN_GF2VEC +# +gap> v := V2([]);; PLAIN_GF2VEC(v);; IsPlistRep(v) and Length(v) = 0; +true + +# bad arguments +gap> PLAIN_GF2VEC(fail); +Error, PLAIN_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# PLAIN_GF2MAT +# +gap> m := Mx02(2);; PLAIN_GF2MAT(m);; IsPlistRep(m) and m = [[], []]; +true + +# bad arguments +gap> PLAIN_GF2MAT(fail); +Error, PLAIN_GF2MAT: must be a GF2 matrix (not the value 'fail') + +# +# EQ_GF2VEC_GF2VEC +# +gap> EQ_GF2VEC_GF2VEC(empty, empty); +true +gap> EQ_GF2VEC_GF2VEC(empty, one); +false + +# bad arguments +gap> EQ_GF2VEC_GF2VEC(fail, empty); +Error, EQ_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> EQ_GF2VEC_GF2VEC(empty, fail); +Error, EQ_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# LT_GF2VEC_GF2VEC +# +gap> LT_GF2VEC_GF2VEC(oneZero, one); +true +gap> LT_GF2VEC_GF2VEC(one, oneZero); +false + +# bad arguments +gap> LT_GF2VEC_GF2VEC(fail, one); +Error, LT_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> LT_GF2VEC_GF2VEC(oneZero, fail); +Error, LT_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# EQ_GF2MAT_GF2MAT +# +gap> EQ_GF2MAT_GF2MAT(Mx02(2), Mx02(2)); +true +gap> EQ_GF2MAT_GF2MAT(Mx02(1), Mx02(2)); +false + +# bad arguments +gap> EQ_GF2MAT_GF2MAT(fail, Mx02(2)); +Error, EQ_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> EQ_GF2MAT_GF2MAT(Mx02(2), fail); +Error, EQ_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') + +# +# LT_GF2MAT_GF2MAT +# +gap> LT_GF2MAT_GF2MAT(Mx02(1), Mx02(2)); +true +gap> LT_GF2MAT_GF2MAT(Mx02(2), Mx02(1)); +false + +# bad arguments +gap> LT_GF2MAT_GF2MAT(fail, Mx02(2)); +Error, LT_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> LT_GF2MAT_GF2MAT(Mx02(1), fail); +Error, LT_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') + +# +# LEN_GF2VEC +# +gap> LEN_GF2VEC(empty); +0 +gap> LEN_GF2VEC(V2([o, z])); +2 + +# bad arguments +gap> LEN_GF2VEC(fail); +Error, LEN_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# ELM0_GF2VEC +# +gap> ELM0_GF2VEC(empty, 1); +fail +gap> ELM0_GF2VEC(one, 1); +Z(2)^0 + +# bad arguments +gap> ELM0_GF2VEC(fail, 1); +Error, ELM0_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> ELM0_GF2VEC(empty, fail); +Error, ELM0_GF2VEC: must be a small integer (not the value 'fail') + +# +# ELM_GF2VEC +# +gap> ELM_GF2VEC(one, 1); +Z(2)^0 + +# bad arguments +gap> ELM_GF2VEC(fail, 1); +Error, ELM_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> ELM_GF2VEC(one, fail); +Error, ELM_GF2VEC: must be a small integer (not the value 'fail') + +# +# ELMS_GF2VEC +# +gap> ELMS_GF2VEC(empty, []) = empty; +true +gap> ELMS_GF2VEC(V2([o, z]), [1]); + + +# bad arguments +gap> ELMS_GF2VEC(fail, []); +Error, ELMS_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> ELMS_GF2VEC(empty, fail); +Error, Length: must be a list (not the value 'fail') + +# +# ASS_GF2VEC +# +gap> v := V2([]);; ASS_GF2VEC(v, 1, z);; v = oneZero; +true + +# bad arguments +gap> ASS_GF2VEC(fail, 1, z); +Error, ASS_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> ASS_GF2VEC(v, fail, z); +Error, ASS_GF2VEC: must be a small integer (not the value 'fail') +gap> ASS_GF2VEC(v, 1, fail); + +# +# ELM_GF2MAT +# +gap> ELM_GF2MAT(Mx02(2), 1); + + +# bad arguments +gap> ELM_GF2MAT(fail, 1); +Error, ELM_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> ELM_GF2MAT(Mx02(2), fail); +Error, ELM_GF2MAT: must be a small integer (not the value 'fail') + +# +# ASS_GF2MAT +# +gap> m := M2([[]]);; ASS_GF2MAT(m, 2, empty);; m = Mx02(2); +true + +# bad arguments +gap> ASS_GF2MAT(fail, 2, empty); +Error, ASS_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> ASS_GF2MAT(m, fail, empty); +Error, ASS_GF2MAT: must be a small integer (not the value 'fail') +gap> ASS_GF2MAT(m, 2, fail); + +# +# SWAP_ROWS_GF2MAT +# +gap> m := M2([[o], [z]]);; SWAP_ROWS_GF2MAT(m, 1, 2);; m = M2([[z], [o]]); +true + +# bad arguments +gap> SWAP_ROWS_GF2MAT(fail, 1, 2); +Error, SWAP_ROWS_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> SWAP_ROWS_GF2MAT(m, fail, 2); +Error, SWAP_ROWS_GF2MAT: must be a small integer (not the value 'fail') +gap> SWAP_ROWS_GF2MAT(m, 1, fail); +Error, SWAP_ROWS_GF2MAT: must be a small integer (not the value 'fail') + +# +# SWAP_COLS_GF2MAT +# +gap> m := M2([[o, z]]);; SWAP_COLS_GF2MAT(m, 1, 2);; m = M2([[z, o]]); +true + +# bad arguments +gap> SWAP_COLS_GF2MAT(fail, 1, 2); +Error, SWAP_COLS_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> SWAP_COLS_GF2MAT(m, fail, 2); +Error, SWAP_COLS_GF2MAT: must be a small integer (not the value 'fail') +gap> SWAP_COLS_GF2MAT(m, 1, fail); +Error, SWAP_COLS_GF2MAT: must be a small integer (not the value 'fail') + +# +# UNB_GF2VEC +# +gap> v := V2([o]);; UNB_GF2VEC(v, 1);; v = empty; +true + +# bad arguments +gap> UNB_GF2VEC(fail, 1); +Error, UNB_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> UNB_GF2VEC(v, fail); +Error, UNB_GF2VEC: must be a small integer (not the value 'fail') + +# +# UNB_GF2MAT +# +gap> m := M2([[]]);; UNB_GF2MAT(m, 1);; m = []; +true + +# bad arguments +gap> UNB_GF2MAT(fail, 1); +Error, UNB_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> UNB_GF2MAT(m, fail); +Error, UNB_GF2MAT: must be a small integer (not the value 'fail') + +# +# ZERO_GF2VEC +# +gap> ZERO_GF2VEC(empty); + +gap> ZERO_GF2VEC(V2([o, z])); + + +# bad arguments +gap> ZERO_GF2VEC(fail); +Error, ZERO_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# ZERO_GF2VEC_2 +# +gap> ZERO_GF2VEC_2(0); + +gap> ZERO_GF2VEC_2(2); + + +# bad arguments +gap> ZERO_GF2VEC_2(fail); +Error, ZERO_GF2VEC_2: must be a non-negative small integer (not the valu\ +e 'fail') + +# +# INV_GF2MAT_MUTABLE +# +gap> INV_GF2MAT_MUTABLE(M2([[o]])) = M2([[o]]); +true + +# bad arguments +gap> INV_GF2MAT_MUTABLE(fail); +Error, INV_GF2MAT_MUTABLE: must be a GF2 matrix (not the value 'fail') + +# +# INV_GF2MAT_SAME_MUTABILITY +# +gap> INV_GF2MAT_SAME_MUTABILITY(M2([[o]])) = M2([[o]]); +true + +# bad arguments +gap> INV_GF2MAT_SAME_MUTABILITY(fail); +Error, INV_GF2MAT_SAME_MUTABILITY: must be a GF2 matrix (not the value '\ +fail') + +# +# INV_GF2MAT_IMMUTABLE +# +gap> INV_GF2MAT_IMMUTABLE(Immutable(M2([[o]]))) = Immutable(M2([[o]])); +true + +# bad arguments +gap> INV_GF2MAT_IMMUTABLE(fail); +Error, INV_GF2MAT_IMMUTABLE: must be a GF2 matrix (not the value 'fail') + +# +# INV_PLIST_GF2VECS_DESTRUCTIVE +# +gap> m := [one];; INV_PLIST_GF2VECS_DESTRUCTIVE(m) = [one] and m = [one]; +true + +# bad arguments +gap> INV_PLIST_GF2VECS_DESTRUCTIVE(fail); +Error, INV_PLIST_GF2VECS_DESTRUCTIVE: must be a plain list (not the val\ +ue 'fail') + +# +# SUM_GF2VEC_GF2VEC +# +gap> SUM_GF2VEC_GF2VEC(empty, empty); + +gap> SUM_GF2VEC_GF2VEC(one, one); + + +# bad arguments +gap> SUM_GF2VEC_GF2VEC(fail, empty); +Error, SUM_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> SUM_GF2VEC_GF2VEC(empty, fail); +Error, SUM_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# PROD_GF2VEC_GF2VEC +# +gap> PROD_GF2VEC_GF2VEC(one, one); +Z(2)^0 + +# bad arguments +gap> PROD_GF2VEC_GF2VEC(fail, one); +Error, PROD_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> PROD_GF2VEC_GF2VEC(one, fail); +Error, PROD_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# PROD_GF2VEC_GF2MAT +# +gap> PROD_GF2VEC_GF2MAT(empty, Mx02(2)); + + +# bad arguments +gap> PROD_GF2VEC_GF2MAT(fail, Mx02(2)); +Error, PROD_GF2VEC_GF2MAT: must be a GF2 vector (not the value 'fail') +gap> PROD_GF2VEC_GF2MAT(empty, fail); +Error, PROD_GF2VEC_GF2MAT: must be a GF2 matrix (not the value 'fail') + +# +# PROD_GF2MAT_GF2VEC +# +gap> PROD_GF2MAT_GF2VEC(Mx02(2), empty); + + +# bad arguments +gap> PROD_GF2MAT_GF2VEC(fail, empty); +Error, PROD_GF2MAT_GF2VEC: must be a GF2 matrix (not the value 'fail') +gap> PROD_GF2MAT_GF2VEC(Mx02(2), fail); +Error, PROD_GF2MAT_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# PROD_GF2MAT_GF2MAT +# +gap> PROD_GF2MAT_GF2MAT(M2([[o], [z]]), Mx02(1)) = Mx02(2); +true + +# bad arguments +gap> PROD_GF2MAT_GF2MAT(fail, Mx02(1)); +Error, PROD_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> PROD_GF2MAT_GF2MAT(M2([[o], [z]]), fail); +Error, PROD_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') + +# +# PROD_GF2MAT_GF2MAT_SIMPLE +# +gap> PROD_GF2MAT_GF2MAT_SIMPLE(M2([[o], [z]]), Mx02(1)) = Mx02(2); +true + +# bad arguments +gap> PROD_GF2MAT_GF2MAT_SIMPLE(fail, Mx02(1)); +Error, PROD_GF2MAT_GF2MAT_SIMPLE: must be a GF2 matrix (not the value 'fa\ +il') +gap> PROD_GF2MAT_GF2MAT_SIMPLE(M2([[o], [z]]), fail); +Error, PROD_GF2MAT_GF2MAT_SIMPLE: must be a GF2 matrix (not the value 'fa\ +il') + +# +# PROD_GF2MAT_GF2MAT_ADVANCED +# +gap> PROD_GF2MAT_GF2MAT_ADVANCED(M2([[o]]), M2([[o]]), 1, 1) = M2([[o]]); +true + +# bad arguments +gap> PROD_GF2MAT_GF2MAT_ADVANCED(fail, M2([[o]]), 1, 1); +Error, PROD_GF2MAT_GF2MAT_ADVANCED: must be a GF2 matrix (not the value '\ +fail') +gap> PROD_GF2MAT_GF2MAT_ADVANCED(M2([[o]]), fail, 1, 1); +Error, PROD_GF2MAT_GF2MAT_ADVANCED: must be a GF2 matrix (not the value '\ +fail') +gap> PROD_GF2MAT_GF2MAT_ADVANCED(M2([[o]]), M2([[o]]), fail, 1); +Error, PROD_GF2MAT_GF2MAT_ADVANCED: must be a small integer (not\ + the value 'fail') +gap> PROD_GF2MAT_GF2MAT_ADVANCED(M2([[o]]), M2([[o]]), 1, fail); +Error, PROD_GF2MAT_GF2MAT_ADVANCED: must be a small integer (not t\ +he value 'fail') + +# +# ADDCOEFFS_GF2VEC_GF2VEC_MULT +# +gap> v := V2([]);; ADDCOEFFS_GF2VEC_GF2VEC_MULT(v, empty, z); +0 +gap> v; + + +# bad arguments +gap> ADDCOEFFS_GF2VEC_GF2VEC_MULT(fail, empty, z); +Error, ADDCOEFFS_GF2VEC_GF2VEC_MULT: must be a GF2 vector (not the value \ +'fail') +gap> ADDCOEFFS_GF2VEC_GF2VEC_MULT(v, fail, z); +Error, ADDCOEFFS_GF2VEC_GF2VEC_MULT: must be a GF2 vector (not the value \ +'fail') +gap> ADDCOEFFS_GF2VEC_GF2VEC_MULT(v, empty, fail); +Error, ADDCOEFFS_GF2VEC_GF2VEC_MULT: must be a finite field element (not\ + the value 'fail') + +# +# ADDCOEFFS_GF2VEC_GF2VEC +# +gap> v := V2([]);; ADDCOEFFS_GF2VEC_GF2VEC(v, empty); +0 +gap> v; + + +# bad arguments +gap> ADDCOEFFS_GF2VEC_GF2VEC(fail, empty); +Error, ADDCOEFFS_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail\ +') +gap> ADDCOEFFS_GF2VEC_GF2VEC(v, fail); +Error, ADDCOEFFS_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail\ +') + +# +# SHRINKCOEFFS_GF2VEC +# +gap> v := V2([o, z]);; SHRINKCOEFFS_GF2VEC(v); +1 +gap> v; + + +# bad arguments +gap> SHRINKCOEFFS_GF2VEC(fail); +Error, SHRINKCOEFFS_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# POSITION_NONZERO_GF2VEC +# +gap> POSITION_NONZERO_GF2VEC(empty, z); +1 +gap> POSITION_NONZERO_GF2VEC(one, z); +1 + +# bad arguments +gap> POSITION_NONZERO_GF2VEC(fail, z); +Error, POSITION_NONZERO_GF2VEC: must be a GF2 vector (not the value 'fai\ +l') +gap> POSITION_NONZERO_GF2VEC(empty, fail); +1 + +# +# POSITION_NONZERO_GF2VEC3 +# +gap> POSITION_NONZERO_GF2VEC3(empty, z, 1); +1 +gap> POSITION_NONZERO_GF2VEC3(V2([z, o]), z, 2); +3 + +# bad arguments +gap> POSITION_NONZERO_GF2VEC3(fail, z, 1); +Error, POSITION_NONZERO_GF2VEC3: must be a GF2 vector (not the value 'fa\ +il') +gap> POSITION_NONZERO_GF2VEC3(empty, fail, 1); +1 +gap> POSITION_NONZERO_GF2VEC3(empty, z, fail); +Error, POSITION_NONZERO_GF2VEC3: must be a non-negative small integer (\ +not the value 'fail') + +# +# MULT_VECTOR_GF2VECS_2 +# +gap> v := V2([o]);; MULT_VECTOR_GF2VECS_2(v, o);; v = one; +true + +# bad arguments +gap> MULT_VECTOR_GF2VECS_2(fail, o); +Error, MULT_VECTOR_GF2VECS_2: must be a GF2 vector (not the value 'fail') +gap> MULT_VECTOR_GF2VECS_2(v, fail); +Error, MULT_VECTOR_GF2VECS_2: must be a finite field element (not the va\ +lue 'fail') + +# +# APPEND_GF2VEC +# +gap> v := V2([]);; APPEND_GF2VEC(v, one);; v = one; +true + +# bad arguments +gap> APPEND_GF2VEC(fail, one); +Error, APPEND_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> APPEND_GF2VEC(v, fail); +Error, APPEND_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# SHALLOWCOPY_GF2VEC +# +gap> v := SHALLOWCOPY_GF2VEC(empty);; v = empty and not IsIdenticalObj(v, empty); +true + +# bad arguments +gap> SHALLOWCOPY_GF2VEC(fail); +Error, SHALLOWCOPY_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# NUMBER_GF2VEC +# +gap> NUMBER_GF2VEC(empty); +1 +gap> NUMBER_GF2VEC(one); +1 + +# bad arguments +gap> NUMBER_GF2VEC(fail); +Error, NUMBER_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# TRANSPOSED_GF2MAT +# +gap> TRANSPOSED_GF2MAT(Mx02(2)); +Error, row index 1 exceeds 0, the number of rows + +# bad arguments gap> TRANSPOSED_GF2MAT(fail); -Error, TRANSPOSED_GF2MAT: Need compressed matrix over GF(2) +Error, TRANSPOSED_GF2MAT: must be a GF2 matrix (not the value 'fail') + +# +# DIST_GF2VEC_GF2VEC +# +gap> DIST_GF2VEC_GF2VEC(empty, empty); +0 +gap> DIST_GF2VEC_GF2VEC(one, one); +0 + +# bad arguments +gap> DIST_GF2VEC_GF2VEC(fail, empty); +Error, DIST_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> DIST_GF2VEC_GF2VEC(empty, fail); +Error, DIST_GF2VEC_GF2VEC: must be a GF2 vector (not the value 'fail') + +# +# DIST_VEC_CLOS_VEC +# +gap> d := [0, 0];; DIST_VEC_CLOS_VEC(Veclis2([one]), oneZero, d);; d; +[ 1, 1 ] + +# bad arguments +gap> DIST_VEC_CLOS_VEC(fail, oneZero, d); +Error, DIST_VEC_CLOS_VEC: must be a plain list (not the value 'fail') +gap> DIST_VEC_CLOS_VEC(Veclis2([one]), fail, d); +Error, DIST_VEC_CLOS_VEC: must be a GF2 vector (not the value 'fail') +gap> DIST_VEC_CLOS_VEC(Veclis2([one]), oneZero, fail); +Error, DIST_VEC_CLOS_VEC: must be a plain list (not the value 'fail') + +# +# SUM_GF2MAT_GF2MAT +# +gap> SUM_GF2MAT_GF2MAT(Mx02(2), Mx02(2)) = Mx02(2); +true + +# bad arguments +gap> SUM_GF2MAT_GF2MAT(fail, Mx02(2)); +Error, SUM_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> SUM_GF2MAT_GF2MAT(Mx02(2), fail); +Error, SUM_GF2MAT_GF2MAT: must be a GF2 matrix (not the value 'fail') + +# +# A_CLOS_VEC +# +gap> A_CLOS_VEC(Veclis2([one]), one, 0, 0); + + +# bad arguments +gap> A_CLOS_VEC(fail, one, 0, 0); +Error, A_CLOS_VEC: must be a plain list (not the value 'fail') +gap> A_CLOS_VEC(Veclis2([one]), fail, 0, 0); +Error, A_CLOS_VEC: must be a GF2 vector (not the value 'fail') +gap> A_CLOS_VEC(Veclis2([one]), one, fail, 0); +Error, A_CLOS_VEC: must be a non-negative small integer (not the value '\ +fail') +gap> A_CLOS_VEC(Veclis2([one]), one, 0, fail); +Error, A_CLOS_VEC: must be a non-negative small integer (not the value \ +'fail') + +# +# A_CLOS_VEC_COORDS +# +gap> A_CLOS_VEC_COORDS(Veclis2([one]), one, 0, 0); +[ , [ 1 ] ] + +# bad arguments +gap> A_CLOS_VEC_COORDS(fail, one, 0, 0); +Error, A_CLOS_VEC_COORDS: must be a plain list (not the value 'fail') +gap> A_CLOS_VEC_COORDS(Veclis2([one]), fail, 0, 0); +Error, A_CLOS_VEC_COORDS: must be a GF2 vector (not the value 'fail') +gap> A_CLOS_VEC_COORDS(Veclis2([one]), one, fail, 0); +Error, A_CLOS_VEC_COORDS: must be a non-negative small integer (not the \ +value 'fail') +gap> A_CLOS_VEC_COORDS(Veclis2([one]), one, 0, fail); +Error, A_CLOS_VEC_COORDS: must be a non-negative small integer (not the\ + value 'fail') + +# +# COSET_LEADERS_INNER_GF2 +# +gap> leaders := [Immutable(oneZero)];; leaders[3] := false;; +gap> COSET_LEADERS_INNER_GF2(Veclis2([one]), 1, 1, leaders); +1 +gap> leaders[2]; + + +# bad arguments +gap> COSET_LEADERS_INNER_GF2(fail, 1, 1, leaders); +Error, COSET_LEADERS_INNER_GF2: must be a plain list (not the value '\ +fail') +gap> COSET_LEADERS_INNER_GF2(Veclis2([one]), fail, 1, leaders); +Error, COSET_LEADERS_INNER_GF2: must be a small integer (not the valu\ +e 'fail') +gap> COSET_LEADERS_INNER_GF2(Veclis2([one]), 1, fail, leaders); +Error, COSET_LEADERS_INNER_GF2: must be a small integer (not the valu\ +e 'fail') +gap> COSET_LEADERS_INNER_GF2(Veclis2([one]), 1, 1, fail); +Error, COSET_LEADERS_INNER_GF2: must be a plain list (not the value \ +'fail') + +# +# CONV_GF2MAT +# +gap> m := [V2([]), V2([])];; CONV_GF2MAT(m);; m = Mx02(2); +true + +# bad arguments +gap> CONV_GF2MAT(fail); +Error, CONV_GF2MAT: must be a small list (not the value 'fail') + +# +# PROD_GF2VEC_ANYMAT +# +gap> PROD_GF2VEC_ANYMAT(one, [fail]); +"TRY_NEXT_METHOD" +gap> PROD_GF2VEC_ANYMAT(one, [one]); + + +# bad arguments +gap> PROD_GF2VEC_ANYMAT(fail, [fail]); +Error, PROD_GF2VEC_ANYMAT: must be a GF2 vector (not the value 'fail') +gap> PROD_GF2VEC_ANYMAT(one, fail); +Error, PROD_GF2VEC_ANYMAT: must be a plain list (not the value 'fail') + +# +# RIGHTMOST_NONZERO_GF2VEC +# +gap> RIGHTMOST_NONZERO_GF2VEC(empty); +0 +gap> RIGHTMOST_NONZERO_GF2VEC(V2([z, o])); +2 + +# bad arguments +gap> RIGHTMOST_NONZERO_GF2VEC(fail); +Error, RIGHTMOST_NONZERO_GF2VEC: must be a GF2 vector (not the value 'fa\ +il') + +# +# RESIZE_GF2VEC +# +gap> v := V2([]);; RESIZE_GF2VEC(v, 2);; v = V2([z, z]); +true + +# bad arguments +gap> RESIZE_GF2VEC(fail, 2); +Error, RESIZE_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> RESIZE_GF2VEC(v, fail); +Error, RESIZE_GF2VEC: must be a non-negative small integer (not the v\ +alue 'fail') + +# +# SHIFT_LEFT_GF2VEC +# +gap> v := V2([]);; SHIFT_LEFT_GF2VEC(v, 3);; v = empty; +true + +# bad arguments +gap> SHIFT_LEFT_GF2VEC(fail, 3); +Error, SHIFT_LEFT_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> SHIFT_LEFT_GF2VEC(v, fail); +Error, SHIFT_LEFT_GF2VEC: must be a non-negative small integer (not t\ +he value 'fail') + +# +# SHIFT_RIGHT_GF2VEC +# +gap> v := V2([]);; SHIFT_RIGHT_GF2VEC(v, 3, z);; v = V2([z, z, z]); +true + +# bad arguments +gap> SHIFT_RIGHT_GF2VEC(fail, 3, z); +Error, SHIFT_RIGHT_GF2VEC: must be a GF2 vector (not the value 'fail') +gap> SHIFT_RIGHT_GF2VEC(v, fail, z); +Error, SHIFT_RIGHT_GF2VEC: must be a non-negative small integer (not \ +the value 'fail') +gap> SHIFT_RIGHT_GF2VEC(v, 3, fail); +Error, SHIFT_RIGHT_GF2VEC: must be a finite field element (not the valu\ +e 'fail') + +# +# ADD_GF2VEC_GF2VEC_SHIFTED +# +gap> v := V2([]);; ADD_GF2VEC_GF2VEC_SHIFTED(v, one, 0, 1);; v = oneZero; +true + +# bad arguments +gap> ADD_GF2VEC_GF2VEC_SHIFTED(fail, one, 0, 1); +Error, ADD_GF2VEC_GF2VEC_SHIFTED: must be a GF2 vector (not the value '\ +fail') +gap> ADD_GF2VEC_GF2VEC_SHIFTED(v, fail, 0, 1); +Error, ADD_GF2VEC_GF2VEC_SHIFTED: must be a GF2 vector (not the value '\ +fail') +gap> ADD_GF2VEC_GF2VEC_SHIFTED(v, one, fail, 1); +Error, ADD_GF2VEC_GF2VEC_SHIFTED: must be a non-negative small integer \ +(not the value 'fail') +gap> ADD_GF2VEC_GF2VEC_SHIFTED(v, one, 0, fail); +Error, ADD_GF2VEC_GF2VEC_SHIFTED: must be a non-negative small integer (\ +not the value 'fail') + +# +# PROD_COEFFS_GF2VEC +# +gap> PROD_COEFFS_GF2VEC(empty, 0, empty, 0); + +gap> PROD_COEFFS_GF2VEC(one, 1, one, 1); + + +# bad arguments +gap> PROD_COEFFS_GF2VEC(fail, 0, empty, 0); + +gap> PROD_COEFFS_GF2VEC(empty, fail, empty, 0); +Error, PROD_COEFFS_GF2VEC: must be a non-negative small integer (not th\ +e value 'fail') +gap> PROD_COEFFS_GF2VEC(empty, 0, fail, 0); + +gap> PROD_COEFFS_GF2VEC(empty, 0, empty, fail); +Error, PROD_COEFFS_GF2VEC: must be a non-negative small integer (not th\ +e value 'fail') + +# +# REDUCE_COEFFS_GF2VEC +# +gap> v := V2([o]);; w := V2([o, z]);; +gap> REDUCE_COEFFS_GF2VEC(v, 1, w, 1); +0 +gap> v; + + +# bad arguments +gap> REDUCE_COEFFS_GF2VEC(fail, 1, w, 1); +Error, REDUCE_COEFFS_GF2VEC: must be a GF2 vector (not the value 'fail'\ +) +gap> REDUCE_COEFFS_GF2VEC(v, fail, w, 1); +Error, REDUCE_COEFFS_GF2VEC: must be a non-negative small integer (not \ +the value 'fail') +gap> REDUCE_COEFFS_GF2VEC(v, 1, fail, 1); +Error, REDUCE_COEFFS_GF2VEC: must be a GF2 vector (not the value 'fail'\ +) +gap> REDUCE_COEFFS_GF2VEC(v, 1, w, fail); +Error, REDUCE_COEFFS_GF2VEC: must be a non-negative small integer (not \ +the value 'fail') + +# +# QUOTREM_COEFFS_GF2VEC +# +gap> QUOTREM_COEFFS_GF2VEC(empty, 0, w, 1); +[ , ] + +# bad arguments +gap> QUOTREM_COEFFS_GF2VEC(fail, 0, w, 1); +Error, QUOTREM_COEFFS_GF2VEC: must be a GF2 vector (not the value 'fail\ +') +gap> QUOTREM_COEFFS_GF2VEC(empty, fail, w, 1); +Error, QUOTREM_COEFFS_GF2VEC: must be a non-negative small integer (not\ + the value 'fail') +gap> QUOTREM_COEFFS_GF2VEC(empty, 0, fail, 1); +Error, QUOTREM_COEFFS_GF2VEC: must be a GF2 vector (not the value 'fail\ +') +gap> QUOTREM_COEFFS_GF2VEC(empty, 0, w, fail); +Error, QUOTREM_COEFFS_GF2VEC: must be a non-negative small integer (not\ + the value 'fail') + +# +# SEMIECHELON_LIST_GF2VECS +# +gap> s := SEMIECHELON_LIST_GF2VECS([one]);; s.heads = [1] and s.vectors = [one]; +true + +# bad arguments +gap> SEMIECHELON_LIST_GF2VECS(fail); +Error, SEMIECHELON_LIST_GF2VECS: must be a plain list (not the value 'fa\ +il') + +# +# SEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS +# +gap> s := SEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS([one]);; +gap> s.heads; +[ 1 ] +gap> s.vectors = [one]; +true +gap> s.coeffs = [one]; +true + +# bad arguments +gap> SEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS(fail); +Error, SEMIECHELON_LIST_GF2VECS_TRANSFORMATIONS: must be a plain list (n\ +ot the value 'fail') + +# +# TRIANGULIZE_LIST_GF2VECS +# +gap> m := [one];; TRIANGULIZE_LIST_GF2VECS(m);; m = [one]; +true + +# bad arguments +gap> TRIANGULIZE_LIST_GF2VECS(fail); +Error, TRIANGULIZE_LIST_GF2VECS: must be a plain list (not the value 'fa\ +il') + +# +# DETERMINANT_LIST_GF2VECS +# +gap> DETERMINANT_LIST_GF2VECS([one]); +Z(2)^0 + +# bad arguments +gap> DETERMINANT_LIST_GF2VECS(fail); +Error, DETERMINANT_LIST_GF2VECS: must be a plain list (not the value 'fa\ +il') + +# +# RANK_LIST_GF2VECS +# +gap> RANK_LIST_GF2VECS([one]); +1 + +# bad arguments +gap> RANK_LIST_GF2VECS(fail); +Error, RANK_LIST_GF2VECS: must be a plain list (not the value 'fail') + +# +# KRONECKERPRODUCT_GF2MAT_GF2MAT +# +gap> KRONECKERPRODUCT_GF2MAT_GF2MAT(Mx02(2), M2([[o]])) = Mx02(2); +true + +# bad arguments +gap> KRONECKERPRODUCT_GF2MAT_GF2MAT(fail, M2([[o]])); +Error, KRONECKERPRODUCT_GF2MAT_GF2MAT: must be a GF2 matrix (not the va\ +lue 'fail') +gap> KRONECKERPRODUCT_GF2MAT_GF2MAT(Mx02(2), fail); +Error, KRONECKERPRODUCT_GF2MAT_GF2MAT: must be a GF2 matrix (not the va\ +lue 'fail') + +# +# COPY_SECTION_GF2VECS +# +gap> src := V2([o, o]);; dst := V2([z, z, z]);; COPY_SECTION_GF2VECS(src, dst, 1, 2, 2);; dst = V2([z, o, o]); +true + +# bad arguments +gap> COPY_SECTION_GF2VECS(fail, dst, 1, 2, 2); +Error, COPY_SECTION_GF2VECS: must be a GF2 vector (not the value 'fail') +gap> COPY_SECTION_GF2VECS(src, fail, 1, 2, 2); +Error, COPY_SECTION_GF2VECS: must be a GF2 vector (not the value 'fail'\ +) +gap> COPY_SECTION_GF2VECS(src, dst, fail, 2, 2); +Error, COPY_SECTION_GF2VECS: must be a positive small integer (not the \ +value 'fail') +gap> COPY_SECTION_GF2VECS(src, dst, 1, fail, 2); +Error, COPY_SECTION_GF2VECS: must be a positive small integer (not the va\ +lue 'fail') +gap> COPY_SECTION_GF2VECS(src, dst, 1, 2, fail); +Error, COPY_SECTION_GF2VECS: must be a small integer (not the value \ +'fail') + +# +# MAT_ELM_GF2MAT +# +gap> MAT_ELM_GF2MAT(M2([[o]]), 1, 1); +Z(2)^0 + +# bad arguments +gap> MAT_ELM_GF2MAT(fail, 1, 1); +Error, MAT_ELM_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> MAT_ELM_GF2MAT(M2([[o]]), fail, 1); +Error, MAT_ELM_GF2MAT: must be a positive small integer (not the value '\ +fail') +gap> MAT_ELM_GF2MAT(M2([[o]]), 1, fail); +Error, MAT_ELM_GF2MAT: must be a positive small integer (not the value '\ +fail') + +# +# SET_MAT_ELM_GF2MAT +# +gap> m := M2([[z]]);; SET_MAT_ELM_GF2MAT(m, 1, 1, o);; m = M2([[o]]); +true + +# bad arguments +gap> SET_MAT_ELM_GF2MAT(fail, 1, 1, o); +Error, SET_MAT_ELM_GF2MAT: must be a GF2 matrix (not the value 'fail') +gap> SET_MAT_ELM_GF2MAT(m, fail, 1, o); +Error, SET_MAT_ELM_GF2MAT: must be a positive small integer (not the val\ +ue 'fail') +gap> SET_MAT_ELM_GF2MAT(m, 1, fail, o); +Error, SET_MAT_ELM_GF2MAT: must be a positive small integer (not the val\ +ue 'fail') +gap> SET_MAT_ELM_GF2MAT(m, 1, 1, fail); +Error, SET_MAT_ELM_GF2MAT: assigned element must be a GF(2) element (not the v\ +alue 'fail') # gap> STOP_TEST("kernel/vecgf2.tst"); From 6a23cecea37fda59396efb9e8643c8a72fca1e64 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 22 May 2026 09:49:46 +0200 Subject: [PATCH 079/123] Document SemiSimpleType field restriction (#6408) Resolves #2570 Co-authored-by: Codex --- lib/alglie.gd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/alglie.gd b/lib/alglie.gd index 31cc718ee0..7200f28451 100644 --- a/lib/alglie.gd +++ b/lib/alglie.gd @@ -514,6 +514,11 @@ DeclareAttribute( "LieSolvableRadical", IsAlgebra and IsLieAlgebra ); ## Lie algebras. ## Then returns the type of L, i.e., ## a string containing the types of the simple summands of L. +## The field of L must not have characteristic 2 or 3, and the +## Killing form of L must be nondegenerate. +## If L has characteristic 0, the structure constants of L +## must be rational numbers; Lie algebras over arbitrary characteristic +## 0 fields are not supported. ## L:= SimpleLieAlgebra( "E", 8, Rationals );; ## gap> b:= BasisVectors( Basis( L ) );; From c357f748d473fef1da58cd1d3ef9aa5fabac1665 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 22 May 2026 09:51:03 +0200 Subject: [PATCH 080/123] Clarify IsomorphismPcGroup docs (#6405) If input group is infinite or not solvable, fail is returned. --- lib/grp.gd | 8 ++++---- lib/grpfp.gi | 2 +- lib/pcgs.gd | 2 +- lib/pcgsspec.gi | 3 +++ tst/testinstall/grppc.tst | 25 +++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/grp.gd b/lib/grp.gd index f9127d72c0..2a83f80eba 100644 --- a/lib/grp.gd +++ b/lib/grp.gd @@ -4250,8 +4250,8 @@ DeclareGlobalFunction( "AllSmallNonabelianSimpleGroups" ); ## returns an isomorphism from G onto an isomorphic pc group. ## The series chosen for this pc representation depends on ## the method chosen. -## G must be a polycyclic group of any kind, for example a solvable -## permutation group. +## G must be a finite polycyclic group of any kind, for example a solvable +## permutation group. If G is finite but not solvable, fail is returned. ## G := Group( (1,2,3), (3,4,1) );; ## gap> iso := IsomorphismPcGroup( G ); @@ -4278,8 +4278,8 @@ DeclareAttribute( "IsomorphismPcGroup", IsGroup ); ## returns an isomorphism from G onto an isomorphic pc group ## whose family pcgs is a special pcgs. ## (This can be beneficial to the runtime of calculations.) -## G may be a polycyclic group of any kind, for example a solvable -## permutation group. +## G must be a finite polycyclic group of any kind, for example a solvable +## permutation group. If G is finite but not solvable, fail is returned. ## ## ## <#/GAPDoc> diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 8f9d97983b..b9fd266b29 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -4332,7 +4332,7 @@ local s, a, hom; fi; hom:=EpimorphismSolvableQuotient(G,s); if Size(Image(hom))<>s then - Error("group is not solvable"); + return fail; else SetIsInjective(hom, true); fi; diff --git a/lib/pcgs.gd b/lib/pcgs.gd index cf2c0a8338..e1cf7172d8 100644 --- a/lib/pcgs.gd +++ b/lib/pcgs.gd @@ -782,7 +782,7 @@ DeclareAttribute( "RefinedPcGroup", IsPcGroup ); ## ## ## isomorphic -## returns an isomorphism from G onto an isomorphic pc group +## returns an isomorphism from a pc group G onto an isomorphic pc group ## whose family pcgs is a prime order pcgs. ## ## diff --git a/lib/pcgsspec.gi b/lib/pcgsspec.gi index e8ff00d776..01cc3fdc62 100644 --- a/lib/pcgsspec.gi +++ b/lib/pcgsspec.gi @@ -752,6 +752,9 @@ InstallMethod( IsomorphismSpecialPcGroup, "generic method for groups", function(G) local iso; iso:=IsomorphismPcGroup(G); + if iso = fail then + return fail; + fi; return iso*IsomorphismSpecialPcGroup(Range(iso)); end); diff --git a/tst/testinstall/grppc.tst b/tst/testinstall/grppc.tst index 873257c589..b2501dfc65 100644 --- a/tst/testinstall/grppc.tst +++ b/tst/testinstall/grppc.tst @@ -1,17 +1,25 @@ #@local F,G,S,c,cl,f,g,g1,g10,g3,gens,h,hh,i,m,n,pcgs,r,rws,sys,u,v,x,y,iso gap> START_TEST("grppc.tst"); + +# gap> Display(TrivialGroup(IsPcGroup)); trivial pc-group + +# gap> Display(CyclicGroup(IsPcGroup, 10)); pc-group with 2 pc-generators and relations: g1^2 = g2 g2^5 = id all generators commute, the groups is abelian + +# gap> Display(SymmetricGroup(IsPcGroup, 3)); pc-group with 2 pc-generators and relations: g1^2 = id g2^3 = id g2^g1 = g2^2 + +# gap> h:=Group((1,2,3,4),(1,2));; gap> m:=IsomorphismPcGroup(h);; gap> hh:=Image(m,h);; @@ -30,6 +38,8 @@ all other pairs of generators commute gap> pcgs:=Pcgs(hh);; gap> ForAll(pcgs,i->PreImagesRepresentative(m,i) in h); true + +# gap> g:=WreathProduct(Group((1,2,3),(1,2)),Group((1,2,3,4,5,6,7)));; gap> i:=IsomorphismPcGroup(g);; gap> g:=Range(i);; @@ -183,6 +193,21 @@ true gap> IsIdenticalObj( Range( iso ), ImagesSource( iso ) ); true +# +gap> G:=AlternatingGroup(5);; +gap> IsomorphismPcGroup(G); +fail +gap> IsomorphismSpecialPcGroup(G); +fail +gap> G:=Range(IsomorphismFpGroup(G));; +gap> IsomorphismPcGroup(G); +fail +gap> IsomorphismSpecialPcGroup(G); +fail +gap> IsomorphismPcGroup(FreeGroup(1)); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 3rd choice method found for `IsomorphismPcGroup' on 1 arguments + # gap> G:= AbelianGroup( IsPcGroup, [ 3, 3, 3 ] );; gap> S:= AbelianGroup( IsPcGroup, [ 3, 3 ] );; From bb7c63b2b3f797b5a7444dfb8fb59900e6ac2a43 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 22 May 2026 09:54:23 +0200 Subject: [PATCH 081/123] Reformat and refactor StructureDescription code (#6403) Mostly avoid putting to many things on one line, for better readability and more accurate code coverage tracking. Also remove obsolete restrictions for perfect group orders 86016, 368640, 737280 --- lib/grpnames.gi | 229 ++++++++++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 104 deletions(-) diff --git a/lib/grpnames.gi b/lib/grpnames.gi index 8220d79e88..fe363a7b07 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -893,9 +893,11 @@ InstallMethod( DecompositionTypesOfGroup, # abelian special case if IsAbelian(G) then AG := AbelianInvariants(G); - if Length(AG) = 1 then DTypes := Set([AG[1]]); else + if Length(AG) = 1 then + DTypes := Set([AG[1]]); + else T := ["x"]; - for a in AG do Add(T,a); od; + Append(T, AG); DTypes := Set([T]); fi; return DTypes; @@ -942,7 +944,9 @@ InstallMethod( DecompositionTypesOfGroup, od; # default: a non-split extension - if Length(DTypes) = 0 then DTypes := Set([["non-split",Size(G)]]); fi; + if Length(DTypes) = 0 then + DTypes := Set([["non-split",Size(G)]]); + fi; return DTypes; end ); @@ -999,9 +1003,8 @@ function(G) gens := DoComputeDihedralGenerators(G); if gens = fail then return false; - else - SetDihedralGenerators(G, gens); fi; + SetDihedralGenerators(G, gens); return true; end); @@ -1198,27 +1201,31 @@ InstallMethod( IsAlternatingGroup, function ( G ) - local n, ids, info; + local info; if not IsFinite(G) then TryNextMethod(); fi; - if IsNaturalAlternatingGroup(G) then return true;fi; - if Size(G) < 60 then + if IsNaturalAlternatingGroup(G) then + return true; + elif Size(G) < 60 then if Size(G) = 1 then - SetAlternatingDegree(G,0); return true; + SetAlternatingDegree(G,0); + return true; elif Size(G) = 3 then - SetAlternatingDegree(G,3); return true; + SetAlternatingDegree(G,3); + return true; elif Size(G) = 12 and Size(DerivedSubgroup(G)) = 4 then - SetAlternatingDegree(G,4); return true; - else return false; fi; + SetAlternatingDegree(G,4); + return true; + fi; + elif IsSimpleGroup(G) then + info := IsomorphismTypeInfoFiniteSimpleGroup(G); + if info.series = "A" then + SetAlternatingDegree(G,info.parameter); + return true; + fi; fi; - - if not IsSimpleGroup(G) then return false; fi; - - info := IsomorphismTypeInfoFiniteSimpleGroup(G); - if info.series = "A" - then SetAlternatingDegree(G,info.parameter); return true; - else return false; fi; + return false; end ); ############################################################################# @@ -1272,7 +1279,9 @@ InstallMethod( IsSymmetricGroup, if not IsFinite(G) then TryNextMethod(); fi; # special treatment of small cases - if Size(G)<=2 then SetSymmetricDegree(G,Size(G)); return true; + if Size(G)<=2 then + SetSymmetricDegree(G,Size(G)); + return true; elif Size(G)=6 and not IsAbelian(G) then SetSymmetricDegree(G,3); return true; @@ -1407,15 +1416,15 @@ InstallGlobalFunction( LinearGroupParameters, if not IsPosInt(N) then Error(" must be positive integer"); fi; - # Formeln: + # Formulas: # |GL(n, q)| = Product(q^n - q^k : k in [0..n-1]) # |SL(n, q)| = |GL(n, q)| / (q - 1) # |PSL(n, q)| = |SL(n, q)| / gcd(n, q - 1) - # mit q = p^e f"ur p prim, e >= 1, n >= 1. + # where q = p^e for p prime, e >= 1, n >= 1. - # Betrachte N = |GL(n,q)|. Dann gilt f"ur n >= 2 - # (1) nu_p(N) = e * Binomial(n,2) und - # (2) (q - 1)^n teilt N. + # Consider N = |GL(n,q)|. Then we have for n >= 2 + # (1) nu_p(N) = e * Binomial(n,2) and + # (2) (q - 1)^n divides N. npeGL := [ ]; npeSL := [ ]; npePSL := [ ]; if N = 1 then return rec( npeGL := npeGL, npeSL := npeSL, npePSL := npePSL ); @@ -1470,8 +1479,9 @@ InstallMethod( IsPSL, # more than one npe-triple should only # occur in the cases |G| in [60, 168, 20160] - if Length(npes) > 1 and not( Size(G) in [60, 168, 20160] ) - then Error("algebraic panic! probably npe does not work"); fi; + if Length(npes) > 1 and not( Size(G) in [60, 168, 20160] ) then + Error("algebraic panic! probably npe does not work"); + fi; # set the parameters npe := npes[1]; @@ -1483,12 +1493,10 @@ InstallMethod( IsPSL, # PSL(2, 2) if npes[1] = [2, 2, 1] then if IsAbelian(G) then return false; fi; - SetParametersOfGroupViewedAsPSL(G,npe); return true; # PSL(2, 3) elif npes[1] = [2, 3, 1] then if Size(DerivedSubgroup(G)) <> 4 then return false; fi; - SetParametersOfGroupViewedAsPSL(G,npe); return true; # PSL(3, 4) / PSL(4, 2) \cong A_8 elif npes = [ [ 4, 2, 1 ], [ 3, 2, 2 ] ] then @@ -1497,13 +1505,13 @@ InstallMethod( IsPSL, else npe := npes[2]; fi; - SetParametersOfGroupViewedAsPSL(G,npe); return true; # other cases - else - if not IsSimpleGroup(G) then return false; fi; - SetParametersOfGroupViewedAsPSL(G,npe); return true; + elif not IsSimpleGroup(G) then + return false; fi; + SetParametersOfGroupViewedAsPSL(G,npe); + return true; end ); ############################################################################# @@ -1563,12 +1571,10 @@ InstallMethod( IsSL, # SL(2, 2) if npes = [2, 2, 1] then if IsAbelian(G) then return false; fi; - SetParametersOfGroupViewedAsSL(G,npes); return true; # SL(2, 3) elif npes = [2, 3, 1] then if Size(DerivedSubgroup(G)) <> 8 then return false; fi; - SetParametersOfGroupViewedAsSL(G,npes); return true; # other cases, in which the contained PSL is simple else @@ -1583,8 +1589,9 @@ InstallMethod( IsSL, then return false; fi; if IsomorphismGroups(G,SL(npes[1],npes[2]^npes[3])) = fail then return false; fi; - SetParametersOfGroupViewedAsSL(G,npes); return true; fi; + SetParametersOfGroupViewedAsSL(G,npes); + return true; end ); ############################################################################# @@ -1649,7 +1656,6 @@ InstallMethod( IsGL, # GL(2, 2) if npes = [2, 2, 1] then if IsAbelian(G) then return false; fi; - SetParametersOfGroupViewedAsGL(G,npes); return true; # GL(2, 3) elif npes = [2, 3, 1] then @@ -1668,7 +1674,6 @@ InstallMethod( IsGL, # elements of order 4 in one case, and 2 in the other; this is also # how e.g. IdGroup distinguishes them if Number(G, g -> Order(g) = 2) < 13 then return false; fi; - SetParametersOfGroupViewedAsGL(G,npes); return true; # other cases, in which contained PSL is simple else @@ -1687,8 +1692,9 @@ InstallMethod( IsGL, then return false; fi; if IsomorphismGroups(G,GL(npes[1],npes[2]^npes[3])) = fail then return false; fi; - SetParametersOfGroupViewedAsGL(G,npes); return true; fi; + SetParametersOfGroupViewedAsGL(G,npes); + return true; end ); ############################################################################# @@ -1728,23 +1734,21 @@ InstallMethod( GLUnderlyingField, BindGlobal( "SD_insertsep", # function to join parts of name function ( strs, sep, brack ) - local short, s, i; - - short := ValueOption("short") = true; + local s, i; if strs = [] then return ""; fi; strs := Filtered(strs,str->str<>""); if Length(strs) > 1 then for i in [1..Length(strs)] do - if Intersection(strs[i],brack) <> "" - then strs[i] := Concatenation("(",strs[i],")"); fi; + if Intersection(strs[i],brack) <> "" then + strs[i] := Concatenation("(",strs[i],")"); + fi; od; fi; - s := strs[1]; - for i in [2..Length(strs)] do - s := Concatenation(s,sep,strs[i]); - od; - if short then RemoveCharacters(s," "); fi; + s := JoinStringsWithSeparator(strs,sep); + if ValueOption("short") = true then + RemoveCharacters(s," "); + fi; return s; end); @@ -1759,27 +1763,29 @@ BindGlobal( "SD_cyclic", BindGlobal( "SD_cycsaspowers", # function to write C2 x C2 x C2 as 2^3, etc. function ( name, cycsizes ) - local short, g, d, k, j, n; + local g, d, k, j, n; - short := ValueOption("short") = true; - if not short then return name; fi; + if ValueOption("short") <> true then + return name; + fi; RemoveCharacters(name," "); - cycsizes := Collected(cycsizes); - for n in cycsizes do - d := n[1]; k := n[2]; - g := SD_cyclic(d); - if d = 0 then - d := "Z"; - else - d := String(d); - fi; - if k > 1 then - for j in Reversed([2..k]) do - name := ReplacedString(name,SD_insertsep(List([1..j],i->g),"x",""), - Concatenation(d,"^",String(j))); - od; - fi; - od; + cycsizes := Collected(cycsizes); + for n in cycsizes do + d := n[1]; + k := n[2]; + g := SD_cyclic(d); + if d = 0 then + d := "Z"; + else + d := String(d); + fi; + if k > 1 then + for j in Reversed([2..k]) do + name := ReplacedString(name,SD_insertsep(List([1..j],i->g),"x",""), + Concatenation(d,"^",String(j))); + od; + fi; + od; RemoveCharacters(name,"C"); return name; end); @@ -1810,11 +1816,14 @@ BindGlobal( "StructureDescriptionForFiniteSimpleGroups", # for simple groups parameter; # parameters of G in series # special case abelian group - if IsAbelian(G) then return StructureDescriptionForAbelianGroups(G); fi; + if IsAbelian(G) then + return StructureDescriptionForAbelianGroups(G); + fi; # special case alternating group - if IsAlternatingGroup(G) - then return Concatenation("A",String(AlternatingDegree(G))); fi; + if IsAlternatingGroup(G) then + return Concatenation("A",String(AlternatingDegree(G))); + fi; # special case PSL if IsPSL(G) then @@ -1913,30 +1922,39 @@ BindGlobal( "StructureDescriptionForFiniteGroups", # for finite groups fi; # special case trivial group - if IsTrivial(G) then return "1"; fi; + if IsTrivial(G) then + return "1"; + fi; # special case abelian group - if IsAbelian(G) then return StructureDescriptionForAbelianGroups(G); fi; + if IsAbelian(G) then + return StructureDescriptionForAbelianGroups(G); + fi; # special case alternating group - if IsAlternatingGroup(G) - then return Concatenation("A",String(AlternatingDegree(G))); fi; + if IsAlternatingGroup(G) then + return Concatenation("A",String(AlternatingDegree(G))); + fi; # special case symmetric group - if IsSymmetricGroup(G) - then return Concatenation("S",String(SymmetricDegree(G))); fi; + if IsSymmetricGroup(G) then + return Concatenation("S",String(SymmetricDegree(G))); + fi; # special case dihedral group - if IsDihedralGroup(G) and Size(G) > 6 - then return Concatenation("D",String(Size(G))); fi; + if IsDihedralGroup(G) and Size(G) > 6 then + return Concatenation("D",String(Size(G))); + fi; # special case quaternion group - if IsQuaternionGroup(G) - then return Concatenation("Q",String(Size(G))); fi; + if IsQuaternionGroup(G) then + return Concatenation("Q",String(Size(G))); + fi; # special case quasidihedral group - if IsQuasiDihedralGroup(G) - then return Concatenation("QD",String(Size(G))); fi; + if IsQuasiDihedralGroup(G) then + return Concatenation("QD",String(Size(G))); + fi; # special case PSL if IsPSL(G) then @@ -1975,7 +1993,9 @@ BindGlobal( "StructureDescriptionForFiniteGroups", # for finite groups cycsizes := Filtered(cycsizes,n->n<>1); cycname := SD_cycsaspowers(SD_insertsep(List(cycsizes, SD_cyclic), " x ",":."), cycsizes); - else cycname := ""; fi; + else + cycname := ""; + fi; noncyclics := Difference(Gs,cyclics); noncycname := SD_insertsep(List(noncyclics,StructureDescription), " x ",":."); @@ -2049,32 +2069,33 @@ BindGlobal( "StructureDescriptionForFiniteGroups", # for finite groups # non-splitting, non-simple group if not IsTrivial(Centre(G)) then cname := SD_insertsep([StructureDescription(Centre(G)), - StructureDescription(G/Centre(G))]," . ","x:."); + StructureDescription(G/Centre(G))], + " . ","x:."); fi; if not IsPerfectGroup(G) then dname := SD_insertsep([StructureDescription(DerivedSubgroup(G)), StructureDescription(G/DerivedSubgroup(G))], " . ","x:."); fi; - if IsBound(cname) and IsBound(dname) and cname <> dname - then return Concatenation(cname," = ",dname); - elif IsBound(cname) then return cname; - elif IsBound(dname) then return dname; - elif not IsTrivial(FrattiniSubgroup(G)) - then return SD_insertsep([StructureDescription(FrattiniSubgroup(G)), - StructureDescription(G/FrattiniSubgroup(G))], - " . ","x:."); - elif IsPosInt(NrPerfectGroups(Size(G))) - and not Size(G) in [ 86016, 368640, 737280 ] - # this does not happen for Size(G)<10^6 - then - id := PerfectIdentification(G); - return Concatenation("PerfectGroup(",String(id[1]),",", - String(id[2]),")"); - else return Concatenation(""); + if IsBound(cname) and IsBound(dname) and cname <> dname then + return Concatenation(cname," = ",dname); + elif IsBound(cname) then + return cname; + elif IsBound(dname) then + return dname; + elif not IsTrivial(FrattiniSubgroup(G)) then + return SD_insertsep([StructureDescription(FrattiniSubgroup(G)), + StructureDescription(G/FrattiniSubgroup(G))], + " . ","x:."); + elif IsPosInt(NrPerfectGroups(Size(G))) then + id := PerfectIdentification(G); + return Concatenation("PerfectGroup(",String(id[1]),",", + String(id[2]),")"); + else + return Concatenation(""); fi; end ); From cd113706e26c3efb8c973ef2154aaf7da5d76d60 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sat, 23 May 2026 11:43:07 +0100 Subject: [PATCH 082/123] Add new logo to banner (B&W) (#6357) --- lib/init.g | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/init.g b/lib/init.g index 03601c810a..a4b64c169d 100644 --- a/lib/init.g +++ b/lib/init.g @@ -434,7 +434,7 @@ function( prefix, values, suffix ) end); BindGlobal( "ShowKernelInformation", function() - local sysdate, btop, vert, bbot, config, str, gap; + local sysdate, btop, bmid, bbot, config, str, gap; if GAPInfo.Date <> "today" then sysdate := " of "; @@ -447,19 +447,24 @@ BindGlobal( "ShowKernelInformation", function() fi; if GAPInfo.TermEncoding = "UTF-8" then - btop := "┌───────┐\c"; vert := "│"; bbot := "└───────┘\c"; + btop := " ● G"; + bmid := "● ● A"; + bbot := " ● P"; else - btop := "*********"; vert := "*"; bbot := btop; + btop := " o G"; + bmid := "o o A"; + bbot := " o P"; fi; if IsHPCGAP then gap := "HPC-GAP"; else gap := "GAP"; fi; - Print( " ",btop," ",gap," ", GAPInfo.BuildVersion, + Print( " ",btop," ",gap," ", GAPInfo.BuildVersion, sysdate, "\n", - " ",vert," GAP ",vert," https://www.gap-system.org\n", - " ",bbot," Architecture: ", GAPInfo.Architecture, "\n" ); + " ",bmid," https://www.gap-system.org\n", + " ",bbot," Architecture: ", GAPInfo.Architecture, "\n", + "\n" ); if IsHPCGAP then Print( " Maximum concurrent threads: ", GAPInfo.KernelInfo.NUM_CPUS, "\n"); From 67f14936e00b1a85ac3344599e30064f1322aa2c Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 23 May 2026 12:45:10 +0200 Subject: [PATCH 083/123] Switch banner to fully compact mode ... as discussed on PR #6357 --- lib/init.g | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/init.g b/lib/init.g index a4b64c169d..82c828d242 100644 --- a/lib/init.g +++ b/lib/init.g @@ -463,8 +463,7 @@ BindGlobal( "ShowKernelInformation", function() Print( " ",btop," ",gap," ", GAPInfo.BuildVersion, sysdate, "\n", " ",bmid," https://www.gap-system.org\n", - " ",bbot," Architecture: ", GAPInfo.Architecture, "\n", - "\n" ); + " ",bbot," Architecture: ", GAPInfo.Architecture, "\n" ); if IsHPCGAP then Print( " Maximum concurrent threads: ", GAPInfo.KernelInfo.NUM_CPUS, "\n"); From 5963bb6486eda39023181aec4298a6ff432152da Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 26 May 2026 14:36:33 +0200 Subject: [PATCH 084/123] Turn LoadPackageDocumentation into a unary function (#6411) This undocumented function accepted more than one argument, but ignored any beyond the first. Apparently this was introduced in the GAP 4.5 days for compatibility reasons? But compatibility with what? No package known to me calls this. For reference in GAP 4.4 it had two arguments (but also was undocumented, and not called by any outside code). --- lib/package.gi | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/package.gi b/lib/package.gi index a4b404027e..b23272e685 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -1396,15 +1396,8 @@ InstallGlobalFunction( RereadPackage, function( arg ) ## #F LoadPackageDocumentation( ) ## -## In versions before 4.5, a second argument was required. -## For the sake of backwards compatibility, we do not forbid a second -## argument, but we ignore it. -## (In later versions, we may forbid the second argument.) -## -InstallGlobalFunction( LoadPackageDocumentation, function( arg ) - local info, short, pkgdoc, long, sixfile; - - info:= arg[1]; +InstallGlobalFunction( LoadPackageDocumentation, function( info ) + local short, pkgdoc, long, sixfile; # Load all books for the package. for pkgdoc in info.PackageDoc do From 8705a57d3b03855978988b43a3052b60ea94b88b Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Tue, 26 May 2026 05:37:37 -0700 Subject: [PATCH 085/123] doc: describe OrbitStabilizer return value (closes #6324) (#6410) The OrbitStabilizer entry in the reference manual only documented the algorithm, not what the operation returns. Adds: - A short sentence explicitly stating the return value is an immutable record with `orbit` (the orbit as a list) and `stabilizer` (the point stabilizer subgroup of G). - A small example block using the same `g:=Group((1,3,2),(2,4,3));;` setup already used by the adjacent `Stabilizer` example, so the rendered output is identical to verified output already in this file. --- lib/oprt.gd | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/oprt.gd b/lib/oprt.gd index 20bae46045..e75a76cc81 100644 --- a/lib/oprt.gd +++ b/lib/oprt.gd @@ -1550,8 +1550,22 @@ OrbitsishOperation( "OrbitLengthsDomain", OrbitsishReq, false, NewAttribute ); ## ## computes the orbit and the stabilizer of pnt simultaneously in a ## single orbit-stabilizer algorithm. +## Returns an immutable record with components orbit (the orbit as +## a list) and stabilizer (the point stabilizer, a subgroup of +## G). ##

## The stabilizer will have G as its parent. +## g:=Group((1,3,2),(2,4,3));; +## gap> orbstab:=OrbitStabilizer(g,[1,2],OnSets); +## rec( +## orbit := [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 2, 3 ], [ 3, 4 ], +## [ 2, 4 ] ], stabilizer := Group([ (1,2)(3,4) ]) ) +## gap> orbstab.orbit; +## [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 2, 3 ], [ 3, 4 ], [ 2, 4 ] ] +## gap> orbstab.stabilizer; +## Group([ (1,2)(3,4) ]) +## ]]> ## ## ## <#/GAPDoc> From d0340546fbb166bbff71acb14f9f555ed8f64b08 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 27 May 2026 08:07:19 +0200 Subject: [PATCH 086/123] Run --bare testinstall test in CI (#6354) --- .github/workflows/CI.yml | 2 +- dev/ci.sh | 4 ++++ tst/testinstall/maxsub.tst | 4 ++++ tst/testinstall/package.tst | 11 +++++++++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ca0f05b997..0159bdcfb8 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -47,7 +47,7 @@ jobs: test-suites: [ # base test: fast first test - "testinstall", + "testinstall-bare", "teststandard", diff --git a/dev/ci.sh b/dev/ci.sh index e45ca39268..170a346368 100755 --- a/dev/ci.sh +++ b/dev/ci.sh @@ -422,6 +422,10 @@ GAPInput ;; + testinstall-bare) + $GAP $(gap_cover_arg) --bare $SRCDIR/tst/testinstall.g + ;; + *) if [[ ! -f $SRCDIR/tst/${TEST_SUITE}.g ]] then diff --git a/tst/testinstall/maxsub.tst b/tst/testinstall/maxsub.tst index 036381d657..e04103b67b 100644 --- a/tst/testinstall/maxsub.tst +++ b/tst/testinstall/maxsub.tst @@ -9,12 +9,14 @@ gap> SortedList(List(msc, IndexInParent)); [ 2, 3, 4 ] # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> G := GL(2,4);; gap> msc:=MaximalSubgroupClassReps(G);; gap> ForAll(msc, H -> Parent(H) = G); true gap> SortedList(List(msc, IndexInParent)); [ 3, 5, 6, 10 ] +#@fi # gap> G := GL(2,5);; @@ -25,10 +27,12 @@ gap> SortedList(List(msc, IndexInParent)); [ 2, 5, 6, 10 ] # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> G := AlternatingGroup(5);; gap> msc := MaximalSubgroupClassReps(G);; gap> SortedList(List(msc, H -> Index(G, H))); [ 5, 6, 10 ] +#@fi # gap> STOP_TEST("maxsub.tst"); diff --git a/tst/testinstall/package.tst b/tst/testinstall/package.tst index 48df3fbf39..1ccd238478 100644 --- a/tst/testinstall/package.tst +++ b/tst/testinstall/package.tst @@ -435,9 +435,11 @@ false gap> IsPackageLoaded("mockpkg", ">=2.0"); false +# # instruct GAP to load the package, and record all its declarations # the help book of mockpkg might already have been loaded in other tests # -> we suppress a warning about this +#@if IsPackageMarkedForLoading( "gapdoc", "" ) gap> old_warning_level := InfoLevel( InfoWarning );; gap> SetInfoLevel( InfoWarning, 0 ); gap> PackageVariablesInfo("mockpkg", "0.1");; @@ -481,9 +483,14 @@ gap> IsDateFormatValid := function( datestring ) > end;; gap> IsDateFormatValid( GAPInfo.Date ); true +#@else +gap> LoadPackage("mockpkg", false); +oops, should not print here +true +#@fi # Test the Cite() command (output changed with GAPDoc 1.6.6 and again with 1.6.7) -#@if CompareVersionNumbers(InstalledPackageVersion("gapdoc"), "1.6.7") +#@if IsPackageMarkedForLoading( "gapdoc", "1.6.7" ) gap> Cite("mockpkg"); Please use one of the following samples to cite mockpkg version from this installation @@ -538,7 +545,7 @@ rg/}}}, } -#@else +#@elif IsPackageMarkedForLoading( "gapdoc", "" ) gap> Cite("mockpkg"); Please use one of the following samples to cite mockpkg version from this installation From aa8f2efc28abbcd370587a83488c4c5b5481e0b5 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 27 May 2026 15:34:33 +0200 Subject: [PATCH 087/123] Prepare release notes for GAP 4.16.0 (#6414) --- CHANGES.md | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 6f4c6c84a9..48c602ec6b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,194 @@ # GAP - history of changes +## GAP 4.16.0 (May 2026) + +The following gives an overview of the changes compared to the previous +release. This list is not complete, many more internal or minor changes +were made, but we tried to only list those changes which we think might +affect some users directly. + +### New features + +- [#6384](https://github.com/gap-system/gap/pull/6384) Add `EnumeratorOfPartitionsSet` enumerator +- [#6322](https://github.com/gap-system/gap/pull/6322) Add `IsGenericMatrixRep` matrix object type +- [#6311](https://github.com/gap-system/gap/pull/6311) Add `PositionNonZeroInRow` for matrices and matrix objects +- [#6277](https://github.com/gap-system/gap/pull/6277) Add `DirectSumGModule` +- [#6268](https://github.com/gap-system/gap/pull/6268) Add `IsSquareMat` and `IsAntisymmetricMat` +- [#6262](https://github.com/gap-system/gap/pull/6262) Add `UserHomeShorten` as counterpart of `UserHomeExpand` +- [#6261](https://github.com/gap-system/gap/pull/6261) Add `WhereDepth` user preference to control depth of initial stack trace in break loops +- [#6259](https://github.com/gap-system/gap/pull/6259) Add `IsSymmetricMatrix` (and `IsSymmetricMat` as a synonym) +- [#6232](https://github.com/gap-system/gap/pull/6232) Add `RandomMatrix`, `RandomInvertibleMatrix`; and fix a problem with a new feature for matrix groups +- [#6213](https://github.com/gap-system/gap/pull/6213) Add `ConformalSymplecticGroup` +- [#5980](https://github.com/gap-system/gap/pull/5980) Add `AddMatrix`, `MultMatrix` (plus explicit left/right side variants) for in-place modification of matrices +- [#3357](https://github.com/gap-system/gap/pull/3357) Add `FoldLeft`, `FoldLeftX`; and `ForAllX`, `ForAnyX`, `FilteredX`, `NumberX`, `PerformX` to complement `ListX`, `SetX`, `SumX`, `ProductX` + +### Performance improvements + +- [#6398](https://github.com/gap-system/gap/pull/6398) Speed up conversion from integers to finite field elements +- [#6329](https://github.com/gap-system/gap/pull/6329) Speed up `CopySubMatrix`, `CopySubVector`, `ExtractSubMatrix`, `ExtractSubVector` for plist matrices/vectors +- [#6289](https://github.com/gap-system/gap/pull/6289) Make the meataxe faster by using `AddMatrix`, `AddVector`, `MultMatrix`, `MultVector` +- [#6276](https://github.com/gap-system/gap/pull/6276) Faster high-level Meataxe functions for irreducible modules (e.g. `MTX.IsomorphismModules`, `MTX.Indecomposition`, `MTX.BasisModuleEndomorphisms`, `MTX.BasisModuleHomomorphisms`) +- [#6267](https://github.com/gap-system/gap/pull/6267) Improve conjugation test for subgroups with different orders +- [#6265](https://github.com/gap-system/gap/pull/6265) Speed up `IsSubset` for cyclotomic domains (such as `Integers`, `PositiveIntegers`, `GaussianRationals` etc.) +- [#6114](https://github.com/gap-system/gap/pull/6114) Enhance support for very long transversals in a permutation group by forcing down huge index steps through an intermediate subgroup + +### Improved and extended functionality + +- [#6357](https://github.com/gap-system/gap/pull/6357) Update the GAP banner to reflect the new GAP logo +- [#6338](https://github.com/gap-system/gap/pull/6338) Improve `CosetLeadersMatFFE` documentation +- [#6334](https://github.com/gap-system/gap/pull/6334) Translating a range by adding an integer now produces another range (instead of a plain list) when possible +- [#6320](https://github.com/gap-system/gap/pull/6320) Add a manual section on how to write code for matrix objects +- [#6309](https://github.com/gap-system/gap/pull/6309) Allow `CopySubVector` on plain row vectors, fix `CopySubMatrix` +- [#6292](https://github.com/gap-system/gap/pull/6292) Document new `PackageInfo.g` fields `Dependencies.TestPackages` and `Dependencies.NeededSystemPackages`, and teach `ValidatePackageInfo` about them +- [#6280](https://github.com/gap-system/gap/pull/6280) Implement `MultVectorRight` for lists +- [#6257](https://github.com/gap-system/gap/pull/6257) Improve break-loop stack traces to be more consistent, provide more information and to indicate the current environment selected via `DownEnv`/`UpEnv` +- [#6211](https://github.com/gap-system/gap/pull/6211) Improve documentation for nice monomorphisms +- [#6183](https://github.com/gap-system/gap/pull/6183) Transfer more properties (such as `IsNaturalSL`, `InvariantQuadraticForm` etc.) when conjugating matrix groups + +### Removed or obsolete functionality + +- [#6067](https://github.com/gap-system/gap/pull/6067) Deprecate `InstallValue` for anything but plain objects (i.e., plain GAP lists, records or strings) and warn if it is done anyway + +### Changes related to handling of packages + +- [#6191](https://github.com/gap-system/gap/pull/6191) Remove unused "PC STACK" variables for from the left collectors (this breaks compatibility with polycyclic version 2.16 and older; use 2.17 or newer instead) + +### Changes in the documentation + +- [#6410](https://github.com/gap-system/gap/pull/6410) Document `OrbitStabilizer` return value +- [#6408](https://github.com/gap-system/gap/pull/6408) Document `SemiSimpleType` field restriction +- [#6405](https://github.com/gap-system/gap/pull/6405) Clarify `IsomorphismPcGroup` docs +- [#6370](https://github.com/gap-system/gap/pull/6370) Improve documentation of `OnTuplesSets`, `OnSetsDisjointSets`, `OnSetsTuples` +- [#6361](https://github.com/gap-system/gap/pull/6361) Simplify the list of `Matrix` argument variants in the manual +- [#6348](https://github.com/gap-system/gap/pull/6348) Clarify `CompatiblePairs` documentation +- [#6337](https://github.com/gap-system/gap/pull/6337) Clarify `IrreducibleModules` description to say 'at most' dim +- [#6260](https://github.com/gap-system/gap/pull/6260) Document `DirectProductElement` +- [#6220](https://github.com/gap-system/gap/pull/6220) Correct the documentation of `NewFamily` +- [#6198](https://github.com/gap-system/gap/pull/6198) Document setter for mutable attributes +- [#6174](https://github.com/gap-system/gap/pull/6174) Document objects with memory +- [#6171](https://github.com/gap-system/gap/pull/6171) Improve documentation of `InverseGeneralMapping` +- [#6169](https://github.com/gap-system/gap/pull/6169) Fix the definition of `PClassPGroup` +- [#6162](https://github.com/gap-system/gap/pull/6162) Only show authors in `Cite`, not maintainers + +### Fixed bugs that could lead to incorrect results + +- [#6382](https://github.com/gap-system/gap/pull/6382) Fix `Irr` for natural symmetric groups when the conjugacy classes are ordered differently in the group and its character table +- [#6358](https://github.com/gap-system/gap/pull/6358) Fix `HexSHA256` to always return 64 hex digits and not drop leading zero digits +- [#6341](https://github.com/gap-system/gap/pull/6341) Fix return value of `PartitionsGreatestLE(0, m)` and improve its documentation +- [#6340](https://github.com/gap-system/gap/pull/6340) Fix `MinimalGeneratingSet` for pc groups which sometimes returned incorrect (non-minimal) results +- [#6325](https://github.com/gap-system/gap/pull/6325) Fix garbled result produced by `CosetLeadersMatFFE` +- [#6303](https://github.com/gap-system/gap/pull/6303) Fix `CopySubVector` for GF(2) vectors to not produce invalid results for certain inputs +- [#6253](https://github.com/gap-system/gap/pull/6253) Fix `ShortestVectors` with `"positive"` argument returning a potentially incomplete list +- [#6245](https://github.com/gap-system/gap/pull/6245) Fix `PreImagesRepresentative` for group homomorphisms with `OnLines` action +- [#6206](https://github.com/gap-system/gap/pull/6206) Fix two bugs in `IsomorphismPermGroupForMatrixGroup` +- [#6203](https://github.com/gap-system/gap/pull/6203) Fix `FieldOfMatrixGroup` for certain classical matrix groups in dimension up to 2, and fix related problems with their invariant forms +- [#6170](https://github.com/gap-system/gap/pull/6170) Fix `IsomorphismPermGroup` for trivial f. p. (sub)group +- [#6160](https://github.com/gap-system/gap/pull/6160) Fix a bug in `RepresentativesPerfectSubgroups` that could lead to the omission of subgroups + +### Fixed bugs that could lead to crashes + +- [#6326](https://github.com/gap-system/gap/pull/6326) Fix crash in `CosetLeadersMatFFE` + +### Fixed bugs that could lead to unexpected errors + +- [#6196](https://github.com/gap-system/gap/pull/6196) Fix an inconsistency problem in `IsFinite` for matrix groups over cycl. fields. +- [#6159](https://github.com/gap-system/gap/pull/6159) Fix a potential error message about data types when computing extensions + +### Other fixed bugs + +- [#6355](https://github.com/gap-system/gap/pull/6355) Reset the options stack after an error also when the break loop is disabled (`-T` command line option) +- [#6218](https://github.com/gap-system/gap/pull/6218) Change `CoverageLineByLine` to produce output compatible with that produced by the `--coverage` command line option + +### Other changes + +- [#6230](https://github.com/gap-system/gap/pull/6230) Make `RestrictedMapping` of a group homomorphism use the same `Range` as the original morphism + +### Package distribution + +#### New packages redistributed with GAP + +- [**ClassicalMaximals**](https://gap-packages.github.io/ClassicalMaximals/) 1.1: Maximal subgroups of classical groups, by Maximilian Hauck, Max Horn, Tristan Pfersdorff, Christian Seeger, Sergio Siccha +- [**LocalNR**](https://gap-packages.github.io/LocalNR) 2.1.0: Package of local nearrings, by Iryna Raievska, Maryna Raievska, Yaroslav Sysak +- [**ModularGroup**](https://ag-weitze-schmithusen.github.io/ModularGroup) 2.0.2: Finite-index subgroups of (P)SL(2,Integers), by Sebastian Engelhardt, Luca Leon Junk, Hannah Wagmann, Gabriela Weitze-Schmithüsen +- [**nofoma**](https://gap-packages.github.io/nofoma) 1.0.1: Normal forms of matrices, by Meinolf Geck, Alia Bonnet +- [**Origami**](https://AG-Weitze-Schmithusen.github.io/Origami/) 2.0.3: Computing Veech groups of origamis, by Leo Emmerich, Sebastian Engelhardt, Simon Ertl, Luca Leon Junk, Pascal Kattler, Alexander Rogovskyy, Pascal Schumann, Andrea Thevis, Hannah Wagmann, Gabriela Weitze-Schmithüsen +- [**PackageMaker**](https://gap-packages.github.io/PackageMaker) 1.0.1: A GAP package for creating new GAP packages, by Max Horn + +#### Updated packages redistributed with GAP + +The GAP 4.16.0 distribution contains 172 packages, of which 68 have been +updated since GAP 4.15.1. The full list of updated packages is given below: + +- [**4ti2Interface**](https://homalg-project.github.io/pkg/4ti2Interface): 2024.11-01 -> 2025.12-01 +- [**Alnuth**](https://gap-packages.github.io/alnuth): 3.2.1 -> 4.0.0 +- [**ANUPQ**](https://gap-packages.github.io/anupq/): 3.3.2 -> 3.3.3 +- [**AtlasRep**](https://www.math.rwth-aachen.de/~Thomas.Breuer/atlasrep): 2.1.9 -> 2.1.11 +- [**AutoDoc**](https://gap-packages.github.io/AutoDoc): 2025.10.16 -> 2026.05.11 +- [**AutPGrp**](https://gap-packages.github.io/autpgrp/): 1.11.1 -> 1.12.0 +- [**Browse**](https://www.math.rwth-aachen.de/~Browse): 1.8.21 -> 1.8.22 +- [**CAP**](https://homalg-project.github.io/pkg/CAP): 2025.09-04 -> 2026.05-08 +- [**CaratInterface**](https://www.math.uni-bielefeld.de/~gaehler/gap/packages.php): 2.3.7 -> 2.3.9 +- [**CddInterface**](https://homalg-project.github.io/CddInterface): 2025.06.24 -> 2026.03.02 +- [**Cryst**](https://www.math.uni-bielefeld.de/~gaehler/gap/packages.php): 4.1.30 -> 4.1.31 +- [**CrystCat**](https://www.math.uni-bielefeld.de/~gaehler/gap/packages.php): 1.1.10 -> 1.1.11 +- [**curlInterface**](https://gap-packages.github.io/curlInterface/): 2.4.2 -> 2.4.3 +- [**cvec**](https://gap-packages.github.io/cvec): 2.8.4 -> 2.8.5 +- [**datastructures**](https://gap-packages.github.io/datastructures): 0.4.0 -> 0.4.1 +- [**Digraphs**](https://digraphs.github.io/Digraphs): 1.13.1 -> 1.14.0 +- [**ExamplesForHomalg**](https://homalg-project.github.io/pkg/ExamplesForHomalg): 2023.10-01 -> 2025.12-01 +- [**ferret**](https://gap-packages.github.io/ferret/): 1.0.15 -> 1.0.16 +- [**FORMAT**](https://gap-packages.github.io/format/): 1.4.4 -> 1.4.5 +- [**Forms**](https://gap-packages.github.io/forms): 1.2.13 -> 1.3.0 +- [**FPLSA**](https://gap-packages.github.io/FPLSA): 1.2.7 -> 1.2.8 +- [**GAPDoc**](https://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc): 1.6.7 -> 1.6.10 +- [**Gauss**](https://homalg-project.github.io/pkg/Gauss): 2024.11-01 -> 2025.12-01 +- [**GaussForHomalg**](https://homalg-project.github.io/pkg/GaussForHomalg): 2024.08-01 -> 2026.04-01 +- [**GeneralizedMorphismsForCAP**](https://homalg-project.github.io/pkg/GeneralizedMorphismsForCAP): 2025.08-01 -> 2025.12-01 +- [**GradedModules**](https://homalg-project.github.io/pkg/GradedModules): 2024.12-01 -> 2026.04-01 +- [**GradedRingForHomalg**](https://homalg-project.github.io/pkg/GradedRingForHomalg): 2024.07-01 -> 2026.04-01 +- [**groupoids**](https://gap-packages.github.io/groupoids/): 1.79 -> 1.81 +- [**GUAVA**](https://gap-packages.github.io/guava): 3.20 -> 3.21 +- [**HAP**](https://gap-packages.github.io/hap): 1.70 -> 1.75 +- [**HAPcryst**](https://gap-packages.github.io/hapcryst/): 0.1.15 -> 0.2.0 +- [**HeLP**](https://gap-packages.github.io/HeLP): 4.0 -> 4.1 +- [**homalg**](https://homalg-project.github.io/pkg/homalg): 2024.01-01 -> 2025.12-01 +- [**HomalgToCAS**](https://homalg-project.github.io/pkg/HomalgToCAS): 2025.08-01 -> 2026.04-01 +- [**IBNP**](https://gap-packages.github.io/ibnp/): 0.17 -> 0.18 +- [**IO_ForHomalg**](https://homalg-project.github.io/pkg/IO_ForHomalg): 2023.02-04 -> 2025.12-01 +- [**json**](https://gap-packages.github.io/json/): 2.2.3 -> 2.4.0 +- [**LinearAlgebraForCAP**](https://homalg-project.github.io/pkg/LinearAlgebraForCAP): 2025.09-01 -> 2026.05-04 +- [**LocalizeRingForHomalg**](https://homalg-project.github.io/pkg/LocalizeRingForHomalg): 2023.10-01 -> 2026.04-01 +- [**lpres**](https://gap-packages.github.io/lpres): 1.1.1 -> 1.1.2 +- [**matgrp**](https://www.math.colostate.edu/~hulpke/matgrp): 0.72 -> 0.73 +- [**MatricesForHomalg**](https://homalg-project.github.io/pkg/MatricesForHomalg): 2025.09-01 -> 2026.04-01 +- [**ModIsom**](https://gap-packages.github.io/modisom/): 3.0.0 -> 3.1.0 +- [**ModulePresentationsForCAP**](https://homalg-project.github.io/pkg/ModulePresentationsForCAP): 2025.09-01 -> 2026.04-01 +- [**Modules**](https://homalg-project.github.io/pkg/Modules): 2024.12-01 -> 2026.04-01 +- [**MonoidalCategories**](https://homalg-project.github.io/pkg/MonoidalCategories): 2025.08-02 -> 2026.05-02 +- [**NConvex**](https://homalg-project.github.io/pkg/NConvex): 2024.12-01 -> 2025.12-02 +- [**NormalizInterface**](https://gap-packages.github.io/NormalizInterface): 1.4.1 -> 1.5.1 +- [**orb**](https://gap-packages.github.io/orb): 5.0.1 -> 5.1.0 +- [**Polycyclic**](https://gap-packages.github.io/polycyclic/): 2.17 -> 2.18 +- [**polymaking**](https://gap-packages.github.io/polymaking/): 0.8.7 -> 0.8.9 +- [**PrimGrp**](https://gap-packages.github.io/primgrp/): 4.0.1 -> 4.0.2 +- [**qpa**](https://gap-packages.github.io/qpa): 1.35 -> 1.37 +- [**RCWA**](https://gap-packages.github.io/rcwa/): 4.8.0 -> 4.9.0 +- [**recog**](https://gap-packages.github.io/recog): 1.4.4 -> 1.5.1 +- [**RingsForHomalg**](https://homalg-project.github.io/pkg/RingsForHomalg): 2024.11-02 -> 2025.12-01 +- [**SCO**](https://homalg-project.github.io/pkg/SCO): 2023.08-01 -> 2025.12-01 +- [**Semigroups**](https://semigroups.github.io/Semigroups): 5.5.4 -> 5.6.3 +- [**singular**](https://gap-packages.github.io/singular/): 2025.08.26 -> 2026.05.05 +- [**SmallClassNr**](https://stertooy.github.io/SmallClassNr): 1.4.2 -> 1.5.1 +- [**ToolsForHomalg**](https://homalg-project.github.io/pkg/ToolsForHomalg): 2025.05-01 -> 2026.04-01 +- [**TwistedConjugacy**](https://stertooy.github.io/TwistedConjugacy): 3.1.1 -> 3.3.2 +- [**typeset**](https://gap-packages.github.io/typeset/): 1.2.3 -> 1.2.4 +- [**utils**](https://gap-packages.github.io/utils): 0.92 -> 0.95 +- [**walrus**](https://gap-packages.github.io/walrus): 0.9991 -> 0.9992 +- [**Wedderga**](https://gap-packages.github.io/wedderga): 4.11.1 -> 4.11.3 +- [**XMod**](https://gap-packages.github.io/xmod/): 2.95 -> 2.98 +- [**ZeroMQInterface**](https://gap-packages.github.io/ZeroMQInterface/): 0.17 -> 0.18 + + ## GAP 4.15.1 (October 2025) The following gives an overview of the changes compared to the previous From 67273d9441063a20fb5df6333b158e56cc99dc4b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 27 May 2026 15:44:06 +0200 Subject: [PATCH 088/123] Start work on GAP 4.17 --- CITATION | 14 +++++++------- configure.ac | 2 +- doc/versiondata | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CITATION b/CITATION index 906d89e6a5..bcd784c127 100644 --- a/CITATION +++ b/CITATION @@ -2,23 +2,23 @@ Please use one of the following samples to cite GAP version from this installati Text: -[GAP] GAP – Groups, Algorithms, and Programming, Version 4.16dev, +[GAP] GAP – Groups, Algorithms, and Programming, Version 4.17dev, The GAP Group (this year), https://www.gap-system.org. HTML:

[GAP] - GAP – Groups, Algorithms, and Programming, Version 4.16dev, + GAP – Groups, Algorithms, and Programming, Version 4.17dev, The GAP Group (this year), https://www.gap-system.org.

BibXML: - + <C>GAP</C> – <C>G</C>roups, <C>A</C>lgorithms, - and <C>P</C>rogramming, <C>V</C>ersion 4.16dev + and Programming, Version 4.17dev https://www.gap-system.org this year GAP @@ -28,8 +28,8 @@ BibXML: BibTeX: -@misc{ GAP4.16dev, - title = {{GAP} {\textendash} {G}roups, {A}lgorithms, and {P}rogramming, {V}ersion 4.16dev}, +@misc{ GAP4.17dev, + title = {{GAP} {\textendash} {G}roups, {A}lgorithms, and {P}rogramming, {V}ersion 4.17dev}, organization = {The GAP {G}roup}, year = {this year}, howpublished = {\href{https://www.gap-system.org}{\texttt{https://www.gap-system.org}}}, @@ -41,7 +41,7 @@ If you are not using BibTeX, here is the bibliography entry produced by BibTeX (in bibliography style `alpha'): \bibitem[GAP]{GAP4} -\emph{GAP -- Groups, Algorithms, and Programming}, Version 4.16dev, +\emph{GAP -- Groups, Algorithms, and Programming}, Version 4.17dev, The GAP~Group (this year), \verb+https://www.gap-system.org+. If you have (predominantly) used one or more particular GAP packages, diff --git a/configure.ac b/configure.ac index 1c313ffb8a..9320f18ce0 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ dnl Setup autoconf dnl AC_PREREQ([2.68]) -m4_define([gap_version], [4.16dev]) +m4_define([gap_version], [4.17dev]) m4_define([gap_releaseday], [today]) m4_define([gap_releaseyear], [this year]) diff --git a/doc/versiondata b/doc/versiondata index 98c2758afa..a2eec48b00 100644 --- a/doc/versiondata +++ b/doc/versiondata @@ -4,7 +4,7 @@ Instead edit either the template file `doc/versiondata.in`, or edit `Makefile.rules` (which has code for generating this file), or edit `configure.ac` (where the value being substituted come from) --> - + - + From 619e1f5658b04cc7a0df0e698024bc87c024e21d Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Mon, 1 Jun 2026 19:40:53 +0800 Subject: [PATCH 089/123] emscripten: add Docker-based one-stop build and polish demo page (#6385) Rework the emscripten build into a reproducible flow inside a pinned container: etc/emscripten/build-in-docker.sh builds the image, runs the wasm build, and assembles a self-contained web-example/ that can be copied to any static host. Replaces the previous mix of shell, Ruby and Node helpers. The toolchain is pinned to emsdk 3.1.23 because both halves of the REPL are sensitive to the exact version: GASMAN's conservative GC, and xterm-pty's emscriptenHack() patching emscripten's TTY device so tcsetattr() reaches the line discipline. 3.1.23 is the version that works with the pinned xterm-pty 0.9.4; a newer emsdk leaves tcsetattr unhonoured and double- echoes typed input. See the Dockerfile for the full rationale. Build robustness fixes, independent of the toolchain version: - configure zlib with --static (newer wasm-ld rejects its shared .so test targets; GAP only needs libz.a); - remove the generated src/c_*.c and ffdata.* before the native build so reruns regenerate them instead of failing; - assemble-website.sh copies the data tree resiliently (some packages ship dangling .dSYM symlinks that aborted the copy and left lib/, grp/ uncopied, causing startup 404s), drops pkg/log/ test logs, ships gap.worker.js only if the build produced one, and asserts lib/init.g landed in the output. Also fix the outdated documentation links in the demo page and refresh startup_manifest.json. AI assistance: Claude Code (Opus 4.8) was used to make these changes. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 11 + etc/emscripten/Dockerfile | 50 + etc/emscripten/README.md | 127 +- etc/emscripten/assemble-website.sh | 64 + etc/emscripten/build-in-docker.sh | 80 ++ etc/emscripten/build.sh | 152 ++- etc/emscripten/build_startup_manifest.js | 71 - etc/emscripten/generate_gap_fs_json.py | 25 +- etc/emscripten/run-web-demo.sh | 13 - etc/emscripten/serve.py | 35 + etc/emscripten/server.rb | 15 - etc/emscripten/startup_manifest.json | 1521 ++++++++++++++++++++++ etc/emscripten/web-template/gap-fs.js | 51 +- etc/emscripten/web-template/index.html | 181 ++- src/gasman.c | 4 +- 15 files changed, 2191 insertions(+), 209 deletions(-) create mode 100644 etc/emscripten/Dockerfile create mode 100755 etc/emscripten/assemble-website.sh create mode 100755 etc/emscripten/build-in-docker.sh delete mode 100755 etc/emscripten/build_startup_manifest.js delete mode 100755 etc/emscripten/run-web-demo.sh create mode 100755 etc/emscripten/serve.py delete mode 100755 etc/emscripten/server.rb create mode 100644 etc/emscripten/startup_manifest.json diff --git a/.gitignore b/.gitignore index 5d67442b54..ca50cf4952 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,17 @@ /libgap*.dll* /libgap*.so* +# emscripten / wasm build outputs (etc/emscripten/build.sh and friends) +/native-build/ +/extern/emscripten/ +/web-example/ +/packages.tar.gz +/gap.html +/gap.js +/gap.wasm +/gap.worker.js +/gap-fs.json + /bin/gap*.sh /bin/*-*/ # Compiling the `xgap` package creates the file `xgap.sh` diff --git a/etc/emscripten/Dockerfile b/etc/emscripten/Dockerfile new file mode 100644 index 0000000000..9025dbaaa3 --- /dev/null +++ b/etc/emscripten/Dockerfile @@ -0,0 +1,50 @@ +# Build environment for compiling GAP to WebAssembly via Emscripten. +# +# Pinned to emsdk 3.1.23 for reproducibility. Both pieces of the in-browser +# REPL are sensitive to the exact toolchain version: +# +# - GASMAN, GAP's conservative garbage collector, scans the stack including +# pointers held in wasm registers, reached via emscripten_scan_registers() +# (see src/gasman.c). That path is now compiled correctly regardless of +# version, so the GC itself is no longer the constraint. +# +# - The terminal uses xterm-pty, whose emscriptenHack() monkey-patches +# emscripten's internal TTY device so GAP's tcsetattr() (turning off echo +# and canonical mode) reaches the line discipline. That patch is tied to +# emscripten's TTY internals: on 3.1.47 the ioctl no longer reaches +# xterm-pty, echo stays on, and every typed line is echoed twice. +# +# 3.1.23 is the version where the pinned xterm-pty (0.9.4) works. Bump both +# together and re-test the REPL -- including that typed input is not +# double-echoed -- before changing this. + +FROM emscripten/emsdk:3.1.23 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + autoconf \ + automake \ + libtool \ + make \ + python3 \ + ca-certificates \ + curl \ + bison \ + byacc \ + m4 \ + && rm -rf /var/lib/apt/lists/* + +# Allow running as a non-root host UID without breaking the emscripten cache. +RUN mkdir -p /emsdk/upstream/emscripten/cache \ + && chmod -R 0777 /emsdk/upstream/emscripten/cache + +# Cache the GAP package distribution tarball so container runs don't +# re-download it from GitHub each time. The URL pins to the "latest" +# release on the PackageDistro side, so this snapshot drifts as upstream +# tags new releases — rebuild the image (--no-cache) to refresh. +ARG GAP_PACKAGES_URL=https://github.com/gap-system/PackageDistro/releases/download/latest/packages.tar.gz +RUN curl --fail --location --silent --show-error \ + --output /opt/gap-packages.tar.gz \ + "$GAP_PACKAGES_URL" \ + && chmod 0644 /opt/gap-packages.tar.gz + +WORKDIR /gap diff --git a/etc/emscripten/README.md b/etc/emscripten/README.md index 5946302efe..083de668b6 100644 --- a/etc/emscripten/README.md +++ b/etc/emscripten/README.md @@ -1,26 +1,127 @@ -Code to allow building gap to WASM using Emscripten. +# GAP in the browser -Files: +Build GAP as a WebAssembly module and serve it as a self-contained website. +The terminal interface uses [xterm-pty](https://github.com/mame/xterm-pty), +so the resulting page behaves like a normal GAP REPL. -- `build.sh`: Run as `etc/emscripten/build.sh` from a fresh copy of GAP. +## Quick start -- `web-template`: Uses 'xterm-pty' to create a "nice" interface to the Wasm GAP. +From a fresh GAP checkout, with either Docker or Podman installed: -- `build_startup_manifest.js`: Run it in the web root directory to build `startup_manifest.json` that contains resources to preload. +```sh +etc/emscripten/build-in-docker.sh +cd web-example +../etc/emscripten/serve.py +``` + +Then open . The first build takes 10–30 minutes; the +docker image, the GAP package distribution, and the GMP/zlib builds are all +cached for subsequent runs. + +To pick up newer GAP packages from upstream, force a fresh image build: + +```sh +docker build --no-cache -t gap-emscripten-build:3.1.23 etc/emscripten/ +``` + +On Apple Silicon (and other non-amd64 hosts), the build runs `linux/amd64` +under emulation, since `emscripten/emsdk:3.1.23` is amd64-only on Docker +Hub. `build-in-docker.sh` pins the platform explicitly so the layer cache +holds across runs; set `BUILD_PLATFORM` to override. + +The output directory `web-example/` is fully self-contained — copy it to any +static host (see "Hosting" below for the headers it needs). + +## Building without Docker + +If you already have emsdk 3.1.23 sourced in your shell, you can run the +underlying build directly: + +```sh +etc/emscripten/build.sh +etc/emscripten/assemble-website.sh +``` + +emsdk 3.1.23 is the version we test against, paired with xterm-pty 0.9.4. +GAP relies on ASYNCIFY together with GASMAN's conservative GC, which scans +wasm registers via `emscripten_scan_registers()` (see `src/gasman.c`); and +the terminal relies on xterm-pty's `emscriptenHack()` patching emscripten's +TTY device so `tcsetattr()` reaches the line discipline. Both are sensitive +to the toolchain version (a newer emsdk leaves `tcsetattr` unhonoured, so +typed input is echoed twice), so re-test the REPL when changing emsdk. -See 'run-web-demo.sh' as an example on how to set up a working website. +## Hosting -Note that this demo uses xterm-pty, a library which provides a terminal interface -for emscripten-compiled programs. This uses a javascript feature called -"SharedArrayBuffer", which requires some headers are returned by the server: +The xterm-pty terminal uses `SharedArrayBuffer`, which browsers only allow +when the page is served with these two headers: ``` Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp ``` -For more details, see for [this article](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer). +`serve.py` is a 20-line stdlib-only Python server that adds them. For +GitHub Pages and other static hosts that don't let you set headers, +`web-template/coi-serviceworker.js` is included as a workaround (it +re-fetches resources through a service worker that adds the headers). + +## Files + +| File | Role | +| ---- | ---- | +| `build-in-docker.sh` | One-stop entry point. Builds the image, runs `build.sh` inside, then `assemble-website.sh`. | +| `Dockerfile` | Pinned `emscripten/emsdk:3.1.23` with autotools, python3, bison/byacc/m4, and a baked-in copy of the GAP package distribution tarball at `/opt/gap-packages.tar.gz`. | +| `build.sh` | Configures and builds GMP, zlib, and GAP itself for wasm. | +| `assemble-website.sh` | Copies the build outputs and data directories (`pkg`, `lib`, `grp`, …) into `web-example/`. | +| `generate_gap_fs_json.py` | Reads file paths on stdin, writes `gap-fs.json` (the manifest of every file in the virtual FS). | +| `startup_manifest.json` | List of files to fetch eagerly at startup, captured from a real GAP run. Anything not in this list is fetched lazily on first read. See "Updating the startup manifest" below for how to refresh it. | +| `serve.py` | Local server that adds the COOP/COEP headers. | +| `web-template/` | Static UI: `index.html`, the worker scripts, the FS init shim, and the COOP/COEP service worker for hosts where you can't set headers. | + +## Updating the startup manifest + +`startup_manifest.json` lists files (relative to the GAP root) that the FS +init shim downloads up front instead of lazily. The current list was +captured from a real GAP run reaching its prompt, so it includes both +the core library bootstrap (`lib/init.g`, `lib/read*.g`, …) and any +default-loaded packages. Entries that no longer exist in the build are +silently ignored, so it is safe to leave stale entries in place; it is +also safe to leave the list empty (every file becomes lazy). + +The manifest is a startup-time optimisation, not a correctness mechanism: +a wrong list never breaks the build, it only makes startup slower (files +GAP needs but the manifest omits get fetched lazily, one round-trip each) +or wastes bandwidth (files in the manifest that GAP doesn't actually +read are downloaded anyway). So it's worth refreshing when something +changes the set of files read at startup — most importantly when the +default loaded packages change, but also after large library reshuffles. + +To regenerate it after such changes: + +1. Build the website (`build-in-docker.sh`) and serve it (`serve.py`). +2. **Empty the served manifest before capturing.** Replace + `web-example/startup_manifest.json` with `[]` (or delete it). + Otherwise the existing entries are eagerly pre-fetched at startup, + appear in `fetchedUrls`, and you'll just round-trip the old list. + Editing the served file is enough — no rebuild is needed. +3. Open the page and wait for the GAP prompt to appear. Every file that + GAP actually reads now goes through the lazy `XHR` path and gets + captured. +4. Open devtools and read the captured URLs from the page's JS console: + `window.fetchedUrls` is an array of every unique URL the worker + requested. Chrome/Firefox provide a `copy()` console helper: + `copy(JSON.stringify(fetchedUrls))` puts the JSON on your clipboard. +5. Strip non-GAP-FS entries (`gap.js`, `gap.wasm`, `gap-fs.json`, the + xterm CDN URLs) and write the result to + `etc/emscripten/startup_manifest.json` (so it's checked in and gets + picked up by the next `assemble-website.sh`). A `jq` filter that + keeps just GAP filesystem paths: + + ```sh + jq '[.[] | select(test("^(pkg|lib|grp|tst|doc|hpcgap|dev|benchmark)/"))]' \ + fetched-urls.json > etc/emscripten/startup_manifest.json + ``` -The file "coi-serviceworker.js" works around this problem on Github pages. This won't -work locally, so "server.rb" is a simple ruby script, which just starts a web-server -which returns the required headers. \ No newline at end of file +The bookkeeping lives in `web-template/gap-fs.js` (wraps `fetch` and +`XMLHttpRequest.open` to report URLs to the main thread) and +`web-template/index.html` (accumulates them onto `window.fetchedUrls`). diff --git a/etc/emscripten/assemble-website.sh b/etc/emscripten/assemble-website.sh new file mode 100755 index 0000000000..12e6f6a83b --- /dev/null +++ b/etc/emscripten/assemble-website.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# +# Assemble a self-contained website from a completed wasm build. +# Outputs ./web-example/ relative to the GAP source root. +# +# Run after etc/emscripten/build.sh (or have build-in-docker.sh call it). + +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +ROOT_DIR=$(cd "$SCRIPT_DIR/../.." && pwd) +OUT_DIR="$ROOT_DIR/web-example" + +cd "$ROOT_DIR" + +for f in gap.js gap.wasm gap-fs.json; do + if [[ ! -f $f ]]; then + echo "Error: missing build output '$f'. Run etc/emscripten/build.sh first." >&2 + exit 1 + fi +done + +# Always start from a clean output directory. Merging into a previous +# web-example/ confuses cp when a tree has changed shape between runs +# (e.g. pkg/X switching between a symlink and a real directory). +rm -rf "$OUT_DIR" +mkdir -p "$OUT_DIR" + +cp "$SCRIPT_DIR"/web-template/* "$OUT_DIR"/ +cp "$SCRIPT_DIR"/startup_manifest.json "$OUT_DIR"/ +cp gap.js gap.wasm gap-fs.json "$OUT_DIR"/ +# Emscripten only emits a separate gap.worker.js for pthread builds; this +# single-threaded ASYNCIFY build doesn't use one (newer emscripten inlines +# the worker regardless). Copy it only if it was produced. +if [[ -f gap.worker.js ]]; then + cp gap.worker.js "$OUT_DIR"/ +fi +cp LICENSE COPYRIGHT "$OUT_DIR"/ + +# Data directories. These are referenced by gap-fs.json and either eagerly +# loaded (if listed in startup_manifest.json) or lazily fetched on first +# read by Emscripten's createLazyFile. +# +# -L dereferences symlinks so the output tree is self-contained (a setup +# where pkg/X is a symlink into a separate checkout still works). Some +# packages ship dangling symlinks as build artefacts (e.g. pkg/vole's +# rust/target/*.dSYM); cp prints those and exits non-zero but still copies +# everything else, so we don't let that abort the run. The assertion below +# catches a genuinely incomplete copy. +for d in pkg lib grp tst doc hpcgap dev benchmark; do + cp -RL "$d" "$OUT_DIR"/ 2>/dev/null || true +done + +# pkg/log holds package test logs (.log/.err/.out) that are never read at +# runtime; keep them out of the shipped site. +rm -rf "$OUT_DIR/pkg/log" + +# The library bootstrap must be present, or GAP 404s during startup. +if [[ ! -f "$OUT_DIR/lib/init.g" ]]; then + echo "Error: lib/init.g missing from $OUT_DIR after copy." >&2 + exit 1 +fi + +echo "Assembled website at $OUT_DIR" diff --git a/etc/emscripten/build-in-docker.sh b/etc/emscripten/build-in-docker.sh new file mode 100755 index 0000000000..ac7a7aa604 --- /dev/null +++ b/etc/emscripten/build-in-docker.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# +# One-stop shop: build GAP for the web inside a pinned container. +# +# Usage (run from the GAP source tree): +# etc/emscripten/build-in-docker.sh +# +# Output: ./web-example/ with a self-contained website. Copy it anywhere +# and serve with COOP/COEP headers (etc/emscripten/serve.py is one option). + +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +ROOT_DIR=$(cd "$SCRIPT_DIR/../.." && pwd) + +RUNTIME="${CONTAINER_RUNTIME:-}" +if [[ -z "$RUNTIME" ]]; then + if command -v podman >/dev/null 2>&1; then + RUNTIME=podman + elif command -v docker >/dev/null 2>&1; then + RUNTIME=docker + else + echo "Error: neither podman nor docker found in PATH." >&2 + echo "Install one, or set CONTAINER_RUNTIME explicitly." >&2 + exit 1 + fi +fi + +IMAGE_TAG="gap-emscripten-build:3.1.23" + +# Pin the platform. emscripten/emsdk:3.1.23 is amd64-only on Docker Hub, so on +# Apple Silicon (or any non-amd64 host) the runtime would otherwise renegotiate +# the platform on every build -- that mismatch invalidates the FROM layer's +# cache and cascades through the whole image, defeating the layer cache even +# with --layers. Override with BUILD_PLATFORM if needed. +PLATFORM="${BUILD_PLATFORM:-linux/amd64}" + +echo ">> Using container runtime: $RUNTIME (platform: $PLATFORM)" +echo ">> Building image $IMAGE_TAG (cached after first run)" + +# --layers is the podman/buildah flag for "use the layer cache"; older +# podman versions default it to false. Docker has caching on by default +# and rejects the flag, so only pass it for podman. +declare -a BUILD_ARGS=(--platform "$PLATFORM") +if [[ "$RUNTIME" != "docker" ]]; then + BUILD_ARGS+=(--layers) +fi +"$RUNTIME" build "${BUILD_ARGS[@]}" -t "$IMAGE_TAG" -f "$SCRIPT_DIR/Dockerfile" "$SCRIPT_DIR" + +# Run as the host user where possible so build outputs are not root-owned. +declare -a USER_ARGS=() +if [[ "$RUNTIME" == "docker" ]]; then + USER_ARGS=(--user "$(id -u):$(id -g)" -e HOME=/tmp) +else + # Rootless podman maps host UID to container root by default. + USER_ARGS=(--userns=keep-id) +fi + +echo ">> Building GAP inside container" +"$RUNTIME" run --platform "$PLATFORM" --rm \ + -v "$ROOT_DIR:/gap" \ + -w /gap \ + "${USER_ARGS[@]}" \ + "$IMAGE_TAG" \ + bash etc/emscripten/build.sh + +echo ">> Assembling website" +bash "$SCRIPT_DIR/assemble-website.sh" + +cat </dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) -if ! command -v emmake &> /dev/null; then - echo Please install, and source, emscripten - echo This script was tested with version 3.1.23 - echo See https://emscripten.org/docs/getting_started/downloads.html for install instructions +if ! command -v emmake >/dev/null 2>&1; then + echo "Please install and source emscripten." >&2 + echo "This script is tested with emsdk 3.1.23." >&2 + echo "See https://emscripten.org/docs/getting_started/downloads.html" >&2 exit 1 -fi; +fi # Build the configure script if this is a fresh git checkout if [[ ! -f ./configure ]]; then ./autogen.sh fi -# First build a standard GAP install, for some files -# we will need during building +# First build a standard GAP install: we need ffgen and gap-nocomp on the +# host to generate sources that the wasm build cannot run itself. +# +# We copy those generated sources (build/c_*.c, build/ffdata.*) into src/ +# further down, so the wasm build picks them up as overrides. GAP's +# Makefile.rules, however, also treats src/c_oper1.c, src/ffdata.c etc. as +# overrides during THIS native build -- so leftovers from a previous run +# would stop the native build regenerating them in native-build/build/, and +# the copy below would then fail. Remove any leftovers so the native build +# regenerates them cleanly (keeps the script idempotent across re-runs). +rm -f src/c_oper1.c src/c_type1.c src/ffdata.c src/ffdata.h ( mkdir -p native-build cd native-build if [[ ! -f config.status ]]; then ../configure fi - make -j8 + make -j"$JOBS" ) AUX_BUILD=$PWD/extern/emscripten/build AUX_PREFIX=$PWD/extern/emscripten/install -mkdir -p "$AUX_BUILD" -mkdir -p "$AUX_PREFIX" +mkdir -p "$AUX_BUILD" "$AUX_PREFIX" +# A 32-bit build is required by GAP's small-integer representation, so we +# pin --build to i686-pc-linux-gnu. This may need revisiting if GAP ever +# moves to a 64-bit-friendly small-integer encoding. ( mkdir -p "$AUX_BUILD/gmp" - cd "$AUX_BUILD/gmp" && + cd "$AUX_BUILD/gmp" if [[ ! -f config.status ]]; then CC_FOR_BUILD=/usr/bin/gcc ABI=standard \ - emconfigure $BASEDIR/extern/gmp/configure \ - --build i686-pc-linux-gnu --host none \ - --disable-assembly --enable-cxx \ - --prefix=$AUX_PREFIX - fi && - emmake make -j8 && + emconfigure "$BASEDIR/extern/gmp/configure" \ + --build i686-pc-linux-gnu --host none \ + --disable-assembly --enable-cxx \ + --prefix="$AUX_PREFIX" + fi + emmake make -j"$JOBS" emmake make install ) ( mkdir -p "$AUX_BUILD/zlib" - cd "$AUX_BUILD/zlib" && + cd "$AUX_BUILD/zlib" if [[ ! -f Makefile ]]; then - emconfigure $BASEDIR/extern/zlib/configure --prefix=$AUX_PREFIX - fi; - emmake make -j8 && + # --static: skip the shared library. Newer emscripten's wasm-ld + # rejects linking zlib's .so test programs (examplesh) with + # "unknown file type: libz.so"; GAP only needs the static libz.a. + emconfigure "$BASEDIR/extern/zlib/configure" --static --prefix="$AUX_PREFIX" + fi + emmake make -j"$JOBS" emmake make install ) -# There are two problems with building GAP -# 1) GAP builds some executables (ffgen and gap-nocomp), which it wants to -# execute while building. We get these files from 'native-build'. -# 2) 'configure' gets confused by some of the LDFLAGS we need, so we have to pass -# them in to 'make' +# Two quirks of building GAP under emscripten: +# 1) GAP runs ffgen and gap-nocomp during the build. We copy the host-built +# versions in from native-build/ further down. +# 2) configure rejects some LDFLAGS we need at link time, so we pass them +# only at make-time. # -# These options are: -# -sASYNCIFY -- we don't care about ASYNC, but this forces the compiler to output -# all variables onto the stack, which is required for GASMAN -# Note we could use 'ALLOW_MEMORY_GROWTH', both we don't currently, we instead set -# a big memory window. -# -O2 : Some optimisation -# EXEEXT=.html -- this is actually a GAP makefile option, it lets us make the -# output 'gap.html', which makes emscripten output a html page we can load -# --pre-js lazy_fs.js : Prepend lazy_fs.js that is generated for lazy loading - -# Run configure if we don't have a makefile, or someone configured this -# GAP for standard building (emscripten builds will use 'emcc') -if [[ ! -f GNUmakefile ]] || ! grep '/emcc' GNUmakefile > /dev/null; then +# Link-time flags worth noting: +# -sASYNCIFY forces variables onto the stack (required by GASMAN). +# -O2 enables some optimisation. +# EXEEXT=.html a GAP makefile knob that produces gap.html, the html +# shim emscripten generates for loading the wasm module. + +if [[ ! -f GNUmakefile ]] || ! grep -q '/emcc' GNUmakefile; then + # Wipe any in-tree state from a prior native (or mismatched) build. + # Stale build/deps/*.d files reference build/ffdata.h, which under + # emcc would be regenerated by a non-executable JS shim; stale .o + # files have the wrong architecture. Configure regenerates build/. + rm -rf build ffgen emconfigure ./configure ABI=32 \ - --with-gmp=$AUX_PREFIX \ - --with-zlib=$AUX_PREFIX \ - LDFLAGS="-s ASYNCIFY=1 -O2" -fi; + --with-gmp="$AUX_PREFIX" \ + --with-zlib="$AUX_PREFIX" \ + LDFLAGS="-s ASYNCIFY=1 -O2" +fi -# Get full required packages -emmake make bootstrap-pkg-full +# Provide the GAP package distribution without re-downloading it on every +# build. Preference order: +# 1. An existing pkg/ directory. +# 2. packages.tar.gz already on the host (carried in the source mount). +# 3. The tarball baked into the docker image at /opt/gap-packages.tar.gz. +# 4. As a last resort, GAP's own bootstrap-pkg-full target downloads it. +# Skipping straight to tar avoids `bootstrap-pkg-full`, which calls +# curl -L -O unconditionally and overwrites packages.tar.gz on every run. +if [[ ! -d pkg ]]; then + if [[ ! -f packages.tar.gz && -f /opt/gap-packages.tar.gz ]]; then + cp /opt/gap-packages.tar.gz packages.tar.gz + fi + if [[ -f packages.tar.gz ]]; then + mkdir pkg + (cd pkg && tar xzf ../packages.tar.gz) + else + emmake make bootstrap-pkg-full + fi +fi -# Copy in files from native_build +# Copy host-built generated sources into place cp native-build/build/c_*.c native-build/build/ffdata.* src/ -# Dynamically find and append ALL required files to the JS array -# The flag -type f is safe because the only symbolic link is 'tst/mockpkg/Makefile.gappkg', -# which is safe to ignore -find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/generate_gap_fs_json.py - -if [ $? -ne 0 ]; then - echo "Build aborted: generate_gap_fs_json.py failed." - exit 1 -fi +# Build the file list that will be served. -L follows symlinks so that +# users' local development setups (e.g. replacing pkg/foo with a symlink +# to a git checkout under git/foo) are picked up; -type f then drops any +# symlinks themselves. +find -L pkg lib grp tst doc hpcgap dev benchmark -type f ! -path 'pkg/log/*' \ + | python3 etc/emscripten/generate_gap_fs_json.py -# The EXEEXT is usually for windows, but here it lets us set GAP's extension, -# which lets us produce a html page to run GAP in. -emmake make -j8 LDFLAGS="-lidbfs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" +emmake make -j"$JOBS" \ + LDFLAGS="-lidbfs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" \ + EXEEXT=".html" diff --git a/etc/emscripten/build_startup_manifest.js b/etc/emscripten/build_startup_manifest.js deleted file mode 100755 index edb8594b10..0000000000 --- a/etc/emscripten/build_startup_manifest.js +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env node -"use strict"; - -const http = require('http'); -const fs = require('fs'); -const path = require('path'); - -const PORT = 9999; -const BASE_DIR = process.cwd(); -const LOG_FILE = path.join(BASE_DIR, 'startup_manifest.json'); - -const requestedFiles = new Set(); -fs.writeFileSync(LOG_FILE, '[\n]'); - -const server = http.createServer((req, res) => { - let urlPath = req.url.split('?')[0]; - if (urlPath === '/') { - urlPath = '/index.html'; - } - - let localDiskPath = urlPath; - try { - localDiskPath = decodeURIComponent(urlPath); - } catch (e) {} - - const filePath = path.join(BASE_DIR, localDiskPath); - - fs.readFile(filePath, (err, data) => { - if (err) { - console.error(`[404] Ignored missing file: ${localDiskPath}`); - res.writeHead(404); - res.end(`404: File not found`); - return; - } - - const ignored = ['/favicon.ico', '/index.html', '/startup_manifest.json', 'coi-serviceworker.js', 'gap-worker.js', 'gap-fs.js', 'gap.js', 'gap.wasm', 'gap-fs.json']; - if (!ignored.includes(localDiskPath)) { - let manifestPath = localDiskPath.startsWith('/') ? localDiskPath.substring(1) : localDiskPath; - - if (!requestedFiles.has(manifestPath)) { - requestedFiles.add(manifestPath); - - const manifest = Array.from(requestedFiles); - fs.writeFileSync(LOG_FILE, JSON.stringify(manifest, null, 4)); - - console.log(`[Loaded & Logged] ${manifestPath} (Total: ${requestedFiles.size})`); - } - } - - let contentType = 'application/octet-stream'; - if (urlPath.endsWith('.html')) contentType = 'text/html'; - else if (urlPath.endsWith('.js')) contentType = 'text/javascript'; - else if (urlPath.endsWith('.wasm')) contentType = 'application/wasm'; - else if (urlPath.endsWith('.css')) contentType = 'text/css'; - - res.writeHead(200, { - 'Content-Type': contentType, - 'Cross-Origin-Opener-Policy': 'same-origin', - 'Cross-Origin-Embedder-Policy': 'require-corp', - 'Access-Control-Allow-Origin': '*' - }); - - res.end(data); - }); -}); - -server.listen(PORT, '0.0.0.0', () => { - console.log(`\n Tracker running at http://localhost:${PORT}/`); - console.log(`Serving files from: ${BASE_DIR}`); - console.log(`Logging valid loaded files to: ${LOG_FILE}\n`); -}); diff --git a/etc/emscripten/generate_gap_fs_json.py b/etc/emscripten/generate_gap_fs_json.py index dbf5447bba..917f0a2a38 100755 --- a/etc/emscripten/generate_gap_fs_json.py +++ b/etc/emscripten/generate_gap_fs_json.py @@ -1,18 +1,11 @@ -import sys -import json -import os - -def main(): - paths = [line.strip() for line in sys.stdin if line.strip()] +#!/usr/bin/env python3 +"""Read a list of file paths from stdin (one per line) and write them as a +JSON array to gap-fs.json in the current directory.""" - try: - with open('gap-fs.json', 'w', encoding='utf-8') as f: - json.dump(paths, f, separators=(',', ':')) - - print(f"Successfully wrote {len(paths)} files to gap-fs.json", file=sys.stderr) - except Exception as e: - print(f"Failed to write gap-fs.json: {e}", file=sys.stderr) - sys.exit(1) +import json +import sys -if __name__ == "__main__": - main() +paths = [line.strip() for line in sys.stdin if line.strip()] +with open("gap-fs.json", "w", encoding="utf-8") as f: + json.dump(paths, f, separators=(",", ":")) +print(f"wrote {len(paths)} files to gap-fs.json", file=sys.stderr) diff --git a/etc/emscripten/run-web-demo.sh b/etc/emscripten/run-web-demo.sh deleted file mode 100755 index a82eb948a9..0000000000 --- a/etc/emscripten/run-web-demo.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -eux - -echo This script assumes you have already run 'build.sh' - -mkdir -p web-example -cp etc/emscripten/web-template/* web-example/ -cp gap.js gap.wasm gap.worker.js gap-fs.json web-example/ - -cp -r pkg lib grp tst doc hpcgap dev benchmark web-example/ -cd web-example -../etc/emscripten/server.rb diff --git a/etc/emscripten/serve.py b/etc/emscripten/serve.py new file mode 100755 index 0000000000..7d089f0c54 --- /dev/null +++ b/etc/emscripten/serve.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +"""Serve the current directory with the COOP/COEP headers required by +xterm-pty's SharedArrayBuffer usage. Run from the assembled web-example/ +(or any directory containing the gap.* artifacts). + + ./serve.py # listens on 8080 + ./serve.py 9000 # listens on 9000 +""" + +from __future__ import annotations + +import http.server +import socketserver +import sys + + +class CrossOriginIsolatedHandler(http.server.SimpleHTTPRequestHandler): + def end_headers(self): + self.send_header("Cross-Origin-Opener-Policy", "same-origin") + self.send_header("Cross-Origin-Embedder-Policy", "require-corp") + super().end_headers() + + +def main() -> None: + port = int(sys.argv[1]) if len(sys.argv) > 1 else 8080 + with socketserver.TCPServer(("", port), CrossOriginIsolatedHandler) as httpd: + print(f"Serving on http://localhost:{port}/ (Ctrl-C to stop)") + try: + httpd.serve_forever() + except KeyboardInterrupt: + print() + + +if __name__ == "__main__": + main() diff --git a/etc/emscripten/server.rb b/etc/emscripten/server.rb deleted file mode 100755 index 642c9ad167..0000000000 --- a/etc/emscripten/server.rb +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env ruby -# Taken from https://github.com/mame/xterm-pty/ - -require "webrick" - -class Server < WEBrick::HTTPServer - def service(req, res) - super - res["Cross-Origin-Opener-Policy"] = "same-origin" - res["Cross-Origin-Embedder-Policy"] = "require-corp" - end -end - -Server.new(Port: 8080, DocumentRoot: ".").start - diff --git a/etc/emscripten/startup_manifest.json b/etc/emscripten/startup_manifest.json new file mode 100644 index 0000000000..3ab701c269 --- /dev/null +++ b/etc/emscripten/startup_manifest.json @@ -0,0 +1,1521 @@ +[ + "lib/init.g", + "lib/kernel.g", + "lib/global.g", + "lib/system.g", + "lib/read1.g", + "lib/hpc/thread1.g", + "lib/filter.g", + "lib/oper.g", + "lib/oper1.g", + "lib/type.g", + "lib/type1.g", + "lib/methsel.g", + "lib/methsel2.g", + "lib/function.g", + "lib/cache.gd", + "lib/object.gd", + "lib/variable.g", + "lib/package.gd", + "lib/coll.gd", + "lib/list.gd", + "lib/wpobj.gd", + "lib/arith.gd", + "lib/ffe.gd", + "lib/domain.gd", + "lib/string.g", + "lib/cyclotom.g", + "lib/set.gd", + "lib/record.gd", + "lib/random.gd", + "lib/cache.gi", + "lib/coll.gi", + "lib/flag.g", + "lib/boolean.g", + "lib/ffe.g", + "lib/arith.gi", + "lib/list.g", + "lib/wpobj.g", + "lib/permutat.g", + "lib/trans.g", + "lib/pperm.g", + "lib/filter.gi", + "lib/object.gi", + "lib/listcoef.gd", + "lib/info.gd", + "lib/files.gd", + "lib/streams.gd", + "lib/record.gi", + "lib/matobj1.gd", + "lib/vecmat.gd", + "lib/vec8bit.gd", + "lib/mat8bit.gd", + "lib/global.gd", + "lib/info.gi", + "lib/global.gi", + "lib/options.gd", + "lib/options.gi", + "lib/attr.gd", + "lib/attr.gi", + "lib/string.gd", + "lib/userpref.g", + "lib/cmdledit.g", + "lib/cmdleditx.g", + "lib/objset.g", + "lib/float.gd", + "lib/macfloat.g", + "lib/hpc/tasks.g", + "lib/error.g", + "lib/session.g", + "lib/read2.g", + "lib/process.gd", + "lib/files.gi", + "lib/streams.gi", + "lib/process.gi", + "lib/read3.g", + "lib/type.gd", + "lib/tuples.gd", + "lib/rvecempt.gd", + "lib/extaset.gd", + "lib/extlset.gd", + "lib/extrset.gd", + "lib/extuset.gd", + "lib/dict.gd", + "lib/bitfields.gd", + "lib/mapping.gd", + "lib/mapphomo.gd", + "lib/relation.gd", + "lib/magma.gd", + "lib/mgmideal.gd", + "lib/mgmhom.gd", + "lib/mgmadj.gd", + "lib/mgmcong.gd", + "lib/semicong.gd", + "lib/semigrp.gd", + "lib/smgideal.gd", + "lib/monoid.gd", + "lib/grp.gd", + "lib/invsgp.gd", + "lib/addmagma.gd", + "lib/addcoset.gd", + "lib/semiring.gd", + "lib/ring.gd", + "lib/matrix.gd", + "lib/matint.gd", + "lib/matblock.gd", + "lib/ideal.gd", + "lib/module.gd", + "lib/basis.gd", + "lib/basismut.gd", + "lib/vspc.gd", + "lib/vspchom.gd", + "lib/zlattice.gd", + "lib/algebra.gd", + "lib/mgmring.gd", + "lib/algfp.gd", + "lib/alglie.gd", + "lib/algsc.gd", + "lib/alghom.gd", + "lib/liefam.gd", + "lib/algrep.gd", + "lib/lierep.gd", + "lib/integer.gd", + "lib/gaussian.gd", + "lib/numtheor.gd", + "lib/dlog.gd", + "lib/primality.gd", + "lib/contfrac.gd", + "lib/ringsc.gd", + "lib/ringhom.gd", + "lib/combinat.gd", + "lib/ratfun.gd", + "lib/fampred.g", + "lib/list.gi", + "lib/set.gi", + "lib/wpobj.gi", + "lib/random.gi", + "lib/field.gd", + "lib/zmodnz.gd", + "lib/zmodnze.gd", + "lib/cyclotom.gd", + "lib/fldabnum.gd", + "lib/padics.gd", + "lib/ringpoly.gd", + "lib/upoly.gd", + "lib/polyfinf.gd", + "lib/polyrat.gd", + "lib/polyconw.gd", + "lib/algfld.gd", + "lib/meataxe.gd", + "lib/unknown.gd", + "lib/word.gd", + "lib/wordass.gd", + "lib/matobj2.gd", + "lib/matobjplist.gd", + "lib/matobjnz.gd", + "lib/rws.gd", + "lib/rwspcclt.gd", + "lib/rwsgrp.gd", + "lib/rwspcgrp.gd", + "lib/groebner.gd", + "lib/pcgs.gd", + "lib/pcgsind.gd", + "lib/pcgspcg.gd", + "lib/pcgsmodu.gd", + "lib/pcgsperm.gd", + "lib/pcgsspec.gd", + "lib/grppc.gd", + "lib/grppcnrm.gd", + "lib/grptbl.gd", + "lib/grpperm.gd", + "lib/grpprmcs.gd", + "lib/stbcbckt.gd", + "lib/ghom.gd", + "lib/ghompcgs.gd", + "lib/gprd.gd", + "lib/ghomperm.gd", + "lib/gpprmsya.gd", + "lib/addgphom.gd", + "lib/grpnames.g", + "lib/grpnames.gd", + "lib/quotsys.gd", + "lib/pquot.gd", + "lib/oprt.gd", + "lib/partitio.gd", + "lib/stbc.gd", + "lib/clas.gd", + "lib/clashom.gd", + "lib/permdeco.gd", + "lib/csetgrp.gd", + "lib/factgrp.gd", + "lib/grpreps.gd", + "lib/grppcrep.gd", + "lib/onecohom.gd", + "lib/grppccom.gd", + "lib/twocohom.gd", + "lib/grppcext.gd", + "lib/grppcfp.gd", + "lib/randiso.gd", + "lib/schur.gd", + "lib/schursym.gd", + "lib/grplatt.gd", + "lib/oprtglat.gd", + "lib/grppclat.gd", + "lib/grppcaut.gd", + "lib/straight.gd", + "lib/memory.gd", + "lib/grpfp.gd", + "lib/grpfree.gd", + "lib/sgpres.gd", + "lib/tietze.gd", + "lib/ghomfp.gd", + "lib/dt.g", + "lib/integer.gi", + "lib/grpnice.gd", + "lib/morpheus.gd", + "lib/grpmat.gd", + "lib/fitfree.gd", + "lib/grpffmat.gd", + "lib/grpramat.gd", + "grp/basic.gd", + "grp/classic.gd", + "grp/conformal.gd", + "grp/perf.gd", + "grp/suzuki.gd", + "grp/ree.gd", + "grp/simple.gd", + "grp/imf.gd", + "grp/glzmodmz.gd", + "grp/clasmax.grp", + "lib/orders.gd", + "lib/trans.gd", + "lib/pperm.gd", + "lib/fastendo.gd", + "lib/fpsemi.gd", + "lib/fpmon.gd", + "lib/rwssmg.gd", + "lib/kbsemi.gd", + "lib/tcsemi.gd", + "lib/adjoin.gd", + "lib/semirel.gd", + "lib/semitran.gd", + "lib/reesmat.gd", + "lib/semiquo.gd", + "lib/semipperm.gd", + "lib/pager.gd", + "lib/helpbase.gd", + "lib/helpview.gd", + "lib/helpt2t.gd", + "lib/helpdef.gd", + "lib/ctbl.gd", + "lib/ctblfuns.gd", + "lib/ctblmaps.gd", + "lib/ctblauto.gd", + "lib/ctbllatt.gd", + "lib/ctblsymm.gd", + "lib/ctblsolv.gd", + "lib/ctblpope.gd", + "lib/ctblmoli.gd", + "lib/ctblmono.gd", + "lib/ctblgrp.gd", + "lib/tom.gd", + "lib/proto.gd", + "lib/gasman.gd", + "lib/memusage.gd", + "lib/read4.g", + "lib/profile.g", + "lib/newprofile.g", + "lib/methwhy.g", + "lib/pager.gi", + "lib/helpbase.gi", + "lib/helpview.gi", + "lib/helpt2t.gi", + "lib/helpdef.gi", + "lib/reread.g", + "lib/package.gi", + "lib/string.gi", + "lib/test.gd", + "lib/test.gi", + "lib/galois.gd", + "lib/galois.gi", + "lib/transatl.g", + "lib/obsolete.g", + "lib/obsolete.gd", + "lib/read.g", + "lib/read5.g", + "lib/type.gi", + "lib/rvecempt.gi", + "lib/ratfun1.gi", + "lib/matrix.gi", + "lib/matint.gi", + "lib/matblock.gi", + "lib/tuples.gi", + "lib/domain.gi", + "lib/mapping1.gi", + "lib/mapping.gi", + "lib/mapprep.gi", + "lib/mapphomo.gi", + "lib/relation.gi", + "lib/magma.gi", + "lib/mgmideal.gi", + "lib/mgmhom.gi", + "lib/mgmadj.gi", + "lib/mgmcong.gi", + "lib/semigrp.gi", + "lib/semicong.gi", + "lib/smgideal.gi", + "lib/monoid.gi", + "lib/grp.gi", + "lib/invsgp.gi", + "lib/addmagma.gi", + "lib/addcoset.gi", + "lib/ring.gi", + "lib/ideal.gi", + "lib/module.gi", + "lib/modfree.gi", + "lib/modulrow.gi", + "lib/modulmat.gi", + "lib/basis.gi", + "lib/basismut.gi", + "lib/vspc.gi", + "lib/vspcrow.gi", + "lib/vspcmat.gi", + "lib/vspchom.gi", + "lib/zlattice.gi", + "lib/mgmring.gi", + "lib/algebra.gi", + "lib/idealalg.gi", + "lib/alghom.gi", + "lib/algfp.gi", + "lib/alglie.gi", + "lib/algliess.gi", + "lib/algsc.gi", + "lib/algmat.gi", + "lib/liefam.gi", + "lib/algrep.gi", + "lib/lierep.gi", + "lib/numtheor.gi", + "lib/dlog.gi", + "lib/primality.gi", + "lib/contfrac.gi", + "lib/ringsc.gi", + "lib/ringhom.gi", + "lib/combinat.gi", + "lib/ratfun.gi", + "lib/ratfunul.gi", + "lib/ringpoly.gi", + "lib/upoly.gi", + "lib/upolyirr.gi", + "lib/polyfinf.gi", + "lib/polyrat.gi", + "lib/polyconw.gi", + "lib/listcoef.gi", + "lib/algfld.gi", + "lib/groebner.gi", + "lib/unknown.gi", + "lib/field.gi", + "lib/fieldfin.gi", + "lib/zmodnz.gi", + "lib/zmodnze.gi", + "lib/ffe.gi", + "lib/ffeconway.gi", + "lib/rational.gi", + "lib/gaussian.gi", + "lib/cyclotom.gi", + "lib/fldabnum.gi", + "lib/padics.gi", + "lib/matobj.gi", + "lib/matobjrowlist.gi", + "lib/vecmat.gi", + "lib/vec8bit.gi", + "lib/mat8bit.gi", + "lib/matobjplist.gi", + "lib/matobjnz.gi", + "lib/meataxe.gi", + "lib/meatauto.gi", + "lib/word.gi", + "lib/wordass.gi", + "lib/wordrep.gi", + "lib/wordlett.gi", + "lib/mgmfree.gi", + "lib/smgrpfre.gi", + "lib/monofree.gi", + "lib/grpfree.gi", + "lib/rws.gi", + "lib/rwspcclt.gi", + "lib/rwspcsng.gi", + "lib/rwspccoc.gi", + "lib/rwsgrp.gi", + "lib/rwspcgrp.gi", + "lib/rwsdt.gi", + "lib/nilpquot.gi", + "lib/pquot.gi", + "lib/pcgs.gi", + "lib/pcgsind.gi", + "lib/pcgsmodu.gi", + "lib/pcgspcg.gi", + "lib/pcgscomp.gi", + "lib/pcgsperm.gi", + "lib/pcgsnice.gi", + "lib/pcgsspec.gi", + "lib/grppc.gi", + "lib/grppcint.gi", + "lib/grppcprp.gi", + "lib/grppcatr.gi", + "lib/grppcnrm.gi", + "lib/bitfields.gi", + "lib/dict.gi", + "lib/dicthf.gi", + "lib/grptbl.gi", + "lib/ghom.gi", + "lib/ghompcgs.gi", + "lib/gprd.gi", + "lib/ghomperm.gi", + "lib/grpperm.gi", + "lib/gpprmsya.gi", + "lib/gprdperm.gi", + "lib/gprdpc.gi", + "lib/gprdmat.gi", + "lib/oprt.gi", + "lib/oprtperm.gi", + "lib/oprtpcgs.gi", + "lib/partitio.gi", + "lib/stbc.gi", + "lib/stbcbckt.gi", + "lib/stbcrand.gi", + "lib/clas.gi", + "lib/claspcgs.gi", + "lib/csetgrp.gi", + "lib/csetperm.gi", + "lib/csetpc.gi", + "lib/factgrp.gi", + "lib/grpreps.gi", + "lib/grppcrep.gi", + "lib/grpprmcs.gi", + "lib/grpnames.gi", + "lib/onecohom.gi", + "lib/grppccom.gi", + "lib/grpcompl.gi", + "lib/twocohom.gi", + "lib/grppcext.gi", + "lib/randiso.gi", + "lib/randiso2.gi", + "lib/grppcfp.gi", + "lib/schur.gi", + "lib/schursym.gi", + "lib/grpnice.gi", + "lib/fitfree.gi", + "lib/permdeco.gi", + "lib/clashom.gi", + "lib/clasperm.gi", + "lib/maxsub.gi", + "lib/norad.gi", + "lib/autsr.gi", + "lib/morpheus.gi", + "lib/grplatt.gi", + "lib/oprtglat.gi", + "lib/grppclat.gi", + "lib/grppcaut.gi", + "lib/grpmat.gi", + "lib/grpffmat.gi", + "lib/grpramat.gi", + "lib/grpfp.gi", + "lib/gpfpiso.gi", + "lib/sgpres.gi", + "lib/tietze.gi", + "lib/ghomfp.gi", + "lib/addgphom.gi", + "lib/trans.gi", + "lib/pperm.gi", + "lib/fastendo.gi", + "lib/fpsemi.gi", + "lib/fpmon.gi", + "lib/rwssmg.gi", + "lib/kbsemi.gi", + "lib/tcsemi.gi", + "lib/adjoin.gi", + "lib/semirel.gi", + "lib/semitran.gi", + "lib/reesmat.gi", + "lib/semiquo.gi", + "lib/semipperm.gi", + "lib/proto.gi", + "lib/orders.gi", + "lib/gasman.gi", + "lib/memusage.gi", + "lib/function.gi", + "lib/float.gi", + "lib/ieee754.g", + "lib/read6.g", + "grp/basicpcg.gi", + "grp/basicprm.gi", + "grp/basicmat.gi", + "grp/basicfp.gi", + "grp/perf.grp", + "grp/classic.gi", + "grp/conformal.gi", + "grp/suzuki.gi", + "grp/ree.gi", + "grp/simple.gi", + "grp/imf.grp", + "grp/imf.gi", + "grp/glzmodmz.gi", + "lib/read7.g", + "lib/ctbl.gi", + "lib/ctblfuns.gi", + "lib/ctblmaps.gi", + "lib/ctblauto.gi", + "lib/ctbllatt.gi", + "lib/ctblsymm.gi", + "lib/ctblsolv.gi", + "lib/ctblpope.gi", + "lib/ctblmoli.gi", + "lib/ctblmono.gi", + "lib/ctblgrp.gi", + "lib/ctblperm.gi", + "lib/ctblpc.gi", + "lib/tom.gi", + "lib/straight.gi", + "lib/memory.gi", + "lib/read8.g", + "lib/overload.g", + "lib/syntaxtree.gd", + "lib/syntaxtree.gi", + "lib/teaching.g", + "lib/teachm2.g", + "lib/operdebug.g", + "lib/colorprompt.g", + "pkg/4ti2interface/PackageInfo.g", + "pkg/ace/PackageInfo.g", + "pkg/aclib/PackageInfo.g", + "pkg/agt/PackageInfo.g", + "pkg/alco/PackageInfo.g", + "pkg/alnuth/PackageInfo.g", + "pkg/anupq/PackageInfo.g", + "pkg/atlasrep/PackageInfo.g", + "pkg/autodoc/PackageInfo.g", + "pkg/automata/PackageInfo.g", + "pkg/automgrp/PackageInfo.g", + "pkg/autpgrp/PackageInfo.g", + "pkg/browse/PackageInfo.g", + "pkg/cap/PackageInfo.g", + "pkg/caratinterface/PackageInfo.g", + "pkg/cddinterface/PackageInfo.g", + "pkg/circle/PackageInfo.g", + "pkg/classicalmaximals/PackageInfo.g", + "pkg/classicpres/PackageInfo.g", + "pkg/cohomolo/PackageInfo.g", + "pkg/congruence/PackageInfo.g", + "pkg/corefreesub/PackageInfo.g", + "pkg/corelg/PackageInfo.g", + "pkg/crime/PackageInfo.g", + "pkg/crisp/PackageInfo.g", + "pkg/crypting/PackageInfo.g", + "pkg/cryst/PackageInfo.g", + "pkg/crystcat/PackageInfo.g", + "pkg/ctbllib/PackageInfo.g", + "pkg/cubefree/PackageInfo.g", + "pkg/curlinterface/PackageInfo.g", + "pkg/cvec/PackageInfo.g", + "pkg/datastructures/PackageInfo.g", + "pkg/deepthought/PackageInfo.g", + "pkg/design/PackageInfo.g", + "pkg/difsets/PackageInfo.g", + "pkg/digraphs/PackageInfo.g", + "pkg/edim/PackageInfo.g", + "pkg/example/PackageInfo.g", + "pkg/examplesforhomalg/PackageInfo.g", + "pkg/factint/PackageInfo.g", + "pkg/ferret/PackageInfo.g", + "pkg/fga/PackageInfo.g", + "pkg/fining/PackageInfo.g", + "pkg/float/PackageInfo.g", + "pkg/format/PackageInfo.g", + "pkg/forms/PackageInfo.g", + "pkg/fplsa/PackageInfo.g", + "pkg/fr/PackageInfo.g", + "pkg/francy/PackageInfo.g", + "pkg/fwtree/PackageInfo.g", + "pkg/gapdoc/PackageInfo.g", + "pkg/gauss/PackageInfo.g", + "pkg/gaussforhomalg/PackageInfo.g", + "pkg/gbnp/PackageInfo.g", + "pkg/generalizedmorphismsforcap/PackageInfo.g", + "pkg/genss/PackageInfo.g", + "pkg/gradedmodules/PackageInfo.g", + "pkg/gradedringforhomalg/PackageInfo.g", + "pkg/grape/PackageInfo.g", + "pkg/groupoids/PackageInfo.g", + "pkg/grpconst/PackageInfo.g", + "pkg/guarana/PackageInfo.g", + "pkg/guava/PackageInfo.g", + "pkg/hap/PackageInfo.g", + "pkg/hapcryst/PackageInfo.g", + "pkg/hecke/PackageInfo.g", + "pkg/help/PackageInfo.g", + "pkg/homalg/PackageInfo.g", + "pkg/homalgtocas/PackageInfo.g", + "pkg/ibnp/PackageInfo.g", + "pkg/idrel/PackageInfo.g", + "pkg/images/PackageInfo.g", + "pkg/inducereduce/PackageInfo.g", + "pkg/intpic/PackageInfo.g", + "pkg/io/PackageInfo.g", + "pkg/io_forhomalg/PackageInfo.g", + "pkg/irredsol/PackageInfo.g", + "pkg/itc/PackageInfo.g", + "pkg/json/PackageInfo.g", + "pkg/jupyterkernel/PackageInfo.g", + "pkg/jupyterviz/PackageInfo.g", + "pkg/kan/PackageInfo.g", + "pkg/kbmag/PackageInfo.g", + "pkg/laguna/PackageInfo.g", + "pkg/liealgdb/PackageInfo.g", + "pkg/liepring/PackageInfo.g", + "pkg/liering/PackageInfo.g", + "pkg/linearalgebraforcap/PackageInfo.g", + "pkg/lins/PackageInfo.g", + "pkg/localizeringforhomalg/PackageInfo.g", + "pkg/localnr/PackageInfo.g", + "pkg/loops/PackageInfo.g", + "pkg/lpres/PackageInfo.g", + "pkg/majoranaalgebras/PackageInfo.g", + "pkg/mapclass/PackageInfo.g", + "pkg/matgrp/PackageInfo.g", + "pkg/matricesforhomalg/PackageInfo.g", + "pkg/modisom/PackageInfo.g", + "pkg/modulargroup/PackageInfo.g", + "pkg/modulepresentationsforcap/PackageInfo.g", + "pkg/modules/PackageInfo.g", + "pkg/monoidalcategories/PackageInfo.g", + "pkg/nconvex/PackageInfo.g", + "pkg/nilmat/PackageInfo.g", + "pkg/nock/PackageInfo.g", + "pkg/nofoma/PackageInfo.g", + "pkg/normalizinterface/PackageInfo.g", + "pkg/nq/PackageInfo.g", + "pkg/numericalsgps/PackageInfo.g", + "pkg/openmath/PackageInfo.g", + "pkg/orb/PackageInfo.g", + "pkg/origami/PackageInfo.g", + "pkg/packagemaker/PackageInfo.g", + "pkg/packagemanager/PackageInfo.g", + "pkg/patternclass/PackageInfo.g", + "pkg/permut/PackageInfo.g", + "pkg/polenta/PackageInfo.g", + "pkg/polycyclic/PackageInfo.g", + "pkg/polymaking/PackageInfo.g", + "pkg/primgrp/PackageInfo.g", + "pkg/profiling/PackageInfo.g", + "pkg/qdistrnd/PackageInfo.g", + "pkg/qpa/PackageInfo.g", + "pkg/quagroup/PackageInfo.g", + "pkg/radiroot/PackageInfo.g", + "pkg/rcwa/PackageInfo.g", + "pkg/rds/PackageInfo.g", + "pkg/recog/PackageInfo.g", + "pkg/repndecomp/PackageInfo.g", + "pkg/repsn/PackageInfo.g", + "pkg/resclasses/PackageInfo.g", + "pkg/ringsforhomalg/PackageInfo.g", + "pkg/sco/PackageInfo.g", + "pkg/scscp/PackageInfo.g", + "pkg/semigroups/PackageInfo.g", + "pkg/sglppow/PackageInfo.g", + "pkg/sgpviz/PackageInfo.g", + "pkg/simpcomp/PackageInfo.g", + "pkg/singular/PackageInfo.g", + "pkg/sl2reps/PackageInfo.g", + "pkg/sla/PackageInfo.g", + "pkg/smallantimagmas/PackageInfo.g", + "pkg/smallclassnr/PackageInfo.g", + "pkg/smallgrp/PackageInfo.g", + "pkg/smallsemi/PackageInfo.g", + "pkg/sonata/PackageInfo.g", + "pkg/sophus/PackageInfo.g", + "pkg/sotgrps/PackageInfo.g", + "pkg/spinsym/PackageInfo.g", + "pkg/standardff/PackageInfo.g", + "pkg/symbcompcc/PackageInfo.g", + "pkg/thelma/PackageInfo.g", + "pkg/tomlib/PackageInfo.g", + "pkg/toolsforhomalg/PackageInfo.g", + "pkg/toric/PackageInfo.g", + "pkg/transgrp/PackageInfo.g", + "pkg/twistedconjugacy/PackageInfo.g", + "pkg/typeset/PackageInfo.g", + "pkg/ugaly/PackageInfo.g", + "pkg/unipot/PackageInfo.g", + "pkg/unitlib/PackageInfo.g", + "pkg/utils/PackageInfo.g", + "pkg/uuid/PackageInfo.g", + "pkg/walrus/PackageInfo.g", + "pkg/wedderga/PackageInfo.g", + "pkg/wpe/PackageInfo.g", + "pkg/xgap/PackageInfo.g", + "pkg/xmod/PackageInfo.g", + "pkg/xmodalg/PackageInfo.g", + "pkg/yangbaxter/PackageInfo.g", + "pkg/zeromqinterface/PackageInfo.g", + "pkg/gapdoc/init.g", + "pkg/gapdoc/lib/UnicodeTools.gd", + "pkg/gapdoc/lib/PrintUtil.gd", + "pkg/gapdoc/lib/Text.gd", + "pkg/gapdoc/lib/ComposeXML.gd", + "pkg/gapdoc/lib/XMLParser.gd", + "pkg/gapdoc/lib/GAPDoc.gd", + "pkg/gapdoc/lib/BibTeX.gd", + "pkg/gapdoc/lib/BibXMLextTools.gd", + "pkg/gapdoc/lib/GAPDoc2LaTeX.gd", + "pkg/gapdoc/lib/GAPDoc2Text.gd", + "pkg/gapdoc/lib/GAPDoc2HTML.gd", + "pkg/gapdoc/lib/Make.g", + "pkg/gapdoc/lib/Examples.gd", + "pkg/gapdoc/read.g", + "pkg/gapdoc/lib/UnicodeTools.gi", + "pkg/gapdoc/lib/UnicodeTabs.g", + "pkg/gapdoc/lib/PrintUtil.gi", + "pkg/gapdoc/lib/Text.gi", + "pkg/gapdoc/lib/ComposeXML.gi", + "pkg/gapdoc/lib/XMLParser.gi", + "pkg/gapdoc/lib/gapdocdtdinfo.g", + "pkg/gapdoc/lib/GAPDoc.gi", + "pkg/gapdoc/lib/BibTeX.gi", + "pkg/gapdoc/lib/bibxmlextinfo.g", + "pkg/gapdoc/lib/BibXMLextTools.gi", + "pkg/gapdoc/lib/GAPDoc2LaTeX.gi", + "pkg/gapdoc/lib/latexhead.tex", + "pkg/gapdoc/lib/GAPDoc2Text.gi", + "pkg/gapdoc/lib/TextThemes.g", + "pkg/gapdoc/lib/GAPDoc2HTML.gi", + "pkg/gapdoc/lib/Examples.gi", + "pkg/gapdoc/lib/HelpBookHandler.g", + "pkg/primgrp/init.g", + "pkg/primgrp/lib/primitiv.gd", + "pkg/primgrp/lib/irredsol.gd", + "pkg/primgrp/read.g", + "pkg/primgrp/lib/primitiv.grp", + "pkg/primgrp/lib/primitiv.gi", + "pkg/primgrp/lib/irredsol.grp", + "pkg/primgrp/lib/irredsol.gi", + "pkg/primgrp/lib/cohorts.grp", + "pkg/smallgrp/init.g", + "pkg/smallgrp/gap/small.gd", + "pkg/smallgrp/read.g", + "pkg/smallgrp/gap/small.gi", + "pkg/smallgrp/gap/smlgp1.g", + "pkg/smallgrp/gap/idgrp1.g", + "pkg/smallgrp/gap/smlinfo.gi", + "pkg/smallgrp/small2/smlgp2.g.gz", + "pkg/smallgrp/small3/smlgp3.g.gz", + "pkg/smallgrp/small4/smlgp4.g.gz", + "pkg/smallgrp/small5/smlgp5.g.gz", + "pkg/smallgrp/small6/smlgp6.g.gz", + "pkg/smallgrp/small7/smlgp7.g.gz", + "pkg/smallgrp/small8/smlgp8.g.gz", + "pkg/smallgrp/small9/smlgp9.g.gz", + "pkg/smallgrp/small10/smlgp10.g.gz", + "pkg/smallgrp/small11/smlgp11.g.gz", + "pkg/smallgrp/id2/idgrp2.g.gz", + "pkg/smallgrp/id3/idgrp3.g.gz", + "pkg/smallgrp/id4/idgrp4.g.gz", + "pkg/smallgrp/id5/idgrp5.g.gz", + "pkg/smallgrp/id6/idgrp6.g.gz", + "pkg/smallgrp/id9/idgrp9.g.gz", + "pkg/smallgrp/id10/idgrp10.g.gz", + "pkg/transgrp/init.g", + "pkg/transgrp/lib/trans.gd", + "pkg/transgrp/read.g", + "pkg/transgrp/lib/trans.grp", + "pkg/transgrp/lib/trans.gi", + "pkg/autpgrp/init.g", + "pkg/autpgrp/gap/autos.gd", + "pkg/autpgrp/read.g", + "pkg/autpgrp/gap/general.gi", + "pkg/autpgrp/gap/autoops.gi", + "pkg/autpgrp/gap/matrix.gi", + "pkg/autpgrp/gap/nicestab.gi", + "pkg/autpgrp/gap/initmat.gi", + "pkg/autpgrp/gap/initperm.gi", + "pkg/autpgrp/gap/hybrstab.gi", + "pkg/autpgrp/gap/matrstab.gi", + "pkg/autpgrp/gap/orbstab.gi", + "pkg/autpgrp/gap/autos.gi", + "pkg/autpgrp/gap/pcpres.gi", + "pkg/autpgrp/gap/countcl.gi", + "pkg/alnuth/init.g", + "pkg/alnuth/gap/setup.gd", + "pkg/alnuth/gap/factors.gd", + "pkg/alnuth/gap/field.gd", + "pkg/polycyclic/init.g", + "pkg/polycyclic/gap/matrix/matrix.gd", + "pkg/polycyclic/gap/basic/infos.gd", + "pkg/polycyclic/gap/basic/collect.gd", + "pkg/polycyclic/gap/basic/pcpelms.gd", + "pkg/polycyclic/gap/basic/pcpgrps.gd", + "pkg/polycyclic/gap/basic/pcppcps.gd", + "pkg/polycyclic/gap/basic/grphoms.gd", + "pkg/polycyclic/gap/basic/basic.gd", + "pkg/polycyclic/gap/cohom/cohom.gd", + "pkg/polycyclic/gap/matrep/matrep.gd", + "pkg/polycyclic/gap/matrep/unitri.gd", + "pkg/polycyclic/gap/pcpgrp/pcpgrp.gd", + "pkg/polycyclic/gap/pcpgrp/torsion.gd", + "pkg/polycyclic/gap/exam/exam.gd", + "pkg/polycyclic/gap/obsolete.gd", + "pkg/alnuth/read.g", + "pkg/alnuth/gap/userpref.gi", + "pkg/alnuth/gap/setup.gi", + "pkg/alnuth/gap/pari.gi", + "pkg/alnuth/gap/factors.gi", + "pkg/alnuth/gap/matfield.gi", + "pkg/alnuth/gap/polfield.gi", + "pkg/alnuth/gap/field.gi", + "pkg/alnuth/gap/unithom.gi", + "pkg/alnuth/gap/matunits.gi", + "pkg/alnuth/gap/rels.gi", + "pkg/alnuth/gap/present.gi", + "pkg/alnuth/gap/isom.gi", + "pkg/alnuth/gap/rationals.gi", + "pkg/alnuth/exam/unimod.gi", + "pkg/alnuth/exam/rationals.gi", + "pkg/alnuth/exam/fields.gi", + "pkg/polycyclic/read.g", + "pkg/polycyclic/gap/matrix/rowbases.gi", + "pkg/polycyclic/gap/matrix/latbases.gi", + "pkg/polycyclic/gap/matrix/lattices.gi", + "pkg/polycyclic/gap/matrix/modules.gi", + "pkg/polycyclic/gap/matrix/triangle.gi", + "pkg/polycyclic/gap/matrix/hnf.gi", + "pkg/polycyclic/gap/basic/collect.gi", + "pkg/polycyclic/gap/basic/colftl.gi", + "pkg/polycyclic/gap/basic/colcom.gi", + "pkg/polycyclic/gap/basic/coldt.gi", + "pkg/polycyclic/gap/basic/colsave.gi", + "pkg/polycyclic/gap/basic/pcpelms.gi", + "pkg/polycyclic/gap/basic/pcppcps.gi", + "pkg/polycyclic/gap/basic/pcpgrps.gi", + "pkg/polycyclic/gap/basic/pcppara.gi", + "pkg/polycyclic/gap/basic/pcpexpo.gi", + "pkg/polycyclic/gap/basic/pcpsers.gi", + "pkg/polycyclic/gap/basic/grphoms.gi", + "pkg/polycyclic/gap/basic/pcpfact.gi", + "pkg/polycyclic/gap/basic/chngpcp.gi", + "pkg/polycyclic/gap/basic/convert.gi", + "pkg/polycyclic/gap/basic/orbstab.gi", + "pkg/polycyclic/gap/basic/construct.gi", + "pkg/polycyclic/gap/cohom/cohom.gi", + "pkg/polycyclic/gap/cohom/addgrp.gi", + "pkg/polycyclic/gap/cohom/general.gi", + "pkg/polycyclic/gap/cohom/solabel.gi", + "pkg/polycyclic/gap/cohom/solcohom.gi", + "pkg/polycyclic/gap/cohom/twocohom.gi", + "pkg/polycyclic/gap/cohom/intcohom.gi", + "pkg/polycyclic/gap/cohom/onecohom.gi", + "pkg/polycyclic/gap/cohom/grpext.gi", + "pkg/polycyclic/gap/cohom/grpcom.gi", + "pkg/polycyclic/gap/cohom/norcom.gi", + "pkg/polycyclic/gap/action/extend.gi", + "pkg/polycyclic/gap/action/basepcgs.gi", + "pkg/polycyclic/gap/action/freegens.gi", + "pkg/polycyclic/gap/action/dixon.gi", + "pkg/polycyclic/gap/action/kernels.gi", + "pkg/polycyclic/gap/action/orbstab.gi", + "pkg/polycyclic/gap/action/orbnorm.gi", + "pkg/polycyclic/gap/pcpgrp/general.gi", + "pkg/polycyclic/gap/pcpgrp/inters.gi", + "pkg/polycyclic/gap/pcpgrp/grpinva.gi", + "pkg/polycyclic/gap/pcpgrp/torsion.gi", + "pkg/polycyclic/gap/pcpgrp/maxsub.gi", + "pkg/polycyclic/gap/pcpgrp/findex.gi", + "pkg/polycyclic/gap/pcpgrp/nindex.gi", + "pkg/polycyclic/gap/pcpgrp/nilpot.gi", + "pkg/polycyclic/gap/pcpgrp/polyz.gi", + "pkg/polycyclic/gap/pcpgrp/pcpattr.gi", + "pkg/polycyclic/gap/pcpgrp/wreath.gi", + "pkg/polycyclic/gap/pcpgrp/fitting.gi", + "pkg/polycyclic/gap/pcpgrp/centcon.gi", + "pkg/polycyclic/gap/pcpgrp/normcon.gi", + "pkg/polycyclic/gap/pcpgrp/schur.gi", + "pkg/polycyclic/gap/pcpgrp/tensor.gi", + "pkg/polycyclic/gap/matrep/matrep.gi", + "pkg/polycyclic/gap/matrep/affine.gi", + "pkg/polycyclic/gap/matrep/unitri.gi", + "pkg/polycyclic/gap/exam/pcplib.gi", + "pkg/polycyclic/gap/exam/matlib.gi", + "pkg/polycyclic/gap/exam/nqlib.gi", + "pkg/polycyclic/gap/exam/generic.gi", + "pkg/polycyclic/gap/exam/bgnilp.gi", + "pkg/polycyclic/gap/exam/metacyc.gi", + "pkg/polycyclic/gap/exam/metagrp.gi", + "pkg/polycyclic/gap/cover/const/bas.gi", + "pkg/polycyclic/gap/cover/const/orb.gi", + "pkg/polycyclic/gap/cover/const/aut.gi", + "pkg/polycyclic/gap/cover/const/com.gi", + "pkg/polycyclic/gap/cover/const/cov.gi", + "pkg/crisp/init.g", + "pkg/crisp/lib/classes.gd", + "pkg/crisp/lib/grpclass.gd", + "pkg/crisp/lib/fitting.gd", + "pkg/crisp/lib/schunck.gd", + "pkg/crisp/lib/form.gd", + "pkg/crisp/lib/projector.gd", + "pkg/crisp/lib/injector.gd", + "pkg/crisp/lib/normpro.gd", + "pkg/crisp/lib/solveeq.gd", + "pkg/crisp/lib/compl.gd", + "pkg/crisp/lib/radical.gd", + "pkg/crisp/lib/residual.gd", + "pkg/crisp/lib/util.gd", + "pkg/crisp/lib/samples.gd", + "pkg/crisp/lib/socle.gd", + "pkg/crisp/read.g", + "pkg/crisp/lib/classes.gi", + "pkg/crisp/lib/grpclass.gi", + "pkg/crisp/lib/fitting.gi", + "pkg/crisp/lib/schunck.gi", + "pkg/crisp/lib/form.gi", + "pkg/crisp/lib/projector.gi", + "pkg/crisp/lib/injector.gi", + "pkg/crisp/lib/normpro.gi", + "pkg/crisp/lib/solveeq.gi", + "pkg/crisp/lib/compl.gi", + "pkg/crisp/lib/radical.gi", + "pkg/crisp/lib/residual.gi", + "pkg/crisp/lib/util.gi", + "pkg/crisp/lib/samples.gi", + "pkg/crisp/lib/socle.gi", + "pkg/factint/init.g", + "pkg/factint/lib/factint.gd", + "pkg/factint/read.g", + "pkg/factint/tables/3k2k.g", + "pkg/factint/tables/akbk.g", + "pkg/factint/tables/factorial.g", + "pkg/factint/tables/fibo.g", + "pkg/factint/tables/primorial.g", + "pkg/factint/lib/general.gi", + "pkg/factint/lib/pminus1.gi", + "pkg/factint/lib/pplus1.gi", + "pkg/factint/lib/ecm.gi", + "pkg/factint/lib/cfrac.gi", + "pkg/factint/lib/mpqs.gi", + "pkg/forms/init.g", + "pkg/forms/lib/forms.gd", + "pkg/forms/lib/recognition.gd", + "pkg/forms/lib/conformal.gd", + "pkg/forms/read.g", + "pkg/forms/lib/forms.gi", + "pkg/forms/lib/recognition.gi", + "pkg/forms/lib/classic.gi", + "pkg/forms/lib/recognition_new.gi", + "pkg/forms/lib/conformal.gi", + "pkg/orb/init.g", + "pkg/orb/gap/homwdata.gd", + "pkg/orb/gap/avltree.gd", + "pkg/orb/gap/hash.gd", + "pkg/orb/gap/cache.gd", + "pkg/orb/gap/orbits.gd", + "pkg/orb/gap/search.gd", + "pkg/orb/gap/bysuborbit.gd", + "pkg/orb/read.g", + "pkg/orb/gap/homwdata.gi", + "pkg/orb/gap/avltree.gi", + "pkg/orb/gap/hash.gi", + "pkg/orb/gap/cache.gi", + "pkg/orb/gap/orbits.gi", + "pkg/orb/gap/search.gi", + "pkg/orb/gap/bysuborbit.gi", + "pkg/utils/init.g", + "pkg/utils/lib/start.gd", + "pkg/utils/lib/files.gd", + "pkg/utils/lib/groups.gd", + "pkg/utils/lib/iterator.gd", + "pkg/utils/lib/latex.gd", + "pkg/utils/lib/lcset.gd", + "pkg/utils/lib/lists.gd", + "pkg/utils/lib/magma.gd", + "pkg/utils/lib/maps.gd", + "pkg/utils/lib/matrix.gd", + "pkg/utils/lib/number.gd", + "pkg/utils/lib/print.gd", + "pkg/utils/lib/record.gd", + "pkg/utils/lib/string.gd", + "pkg/utils/lib/gslp.gd", + "pkg/utils/lib/download.gd", + "pkg/utils/read.g", + "pkg/utils/lib/files.gi", + "pkg/utils/lib/groups.gi", + "pkg/utils/lib/iterator.gi", + "pkg/utils/lib/latex.gi", + "pkg/utils/lib/lcset.gi", + "pkg/utils/lib/lists.gi", + "pkg/utils/lib/magma.gi", + "pkg/utils/lib/maps.gi", + "pkg/utils/lib/matrix.gi", + "pkg/utils/lib/number.gi", + "pkg/utils/lib/print.gi", + "pkg/utils/lib/record.gi", + "pkg/utils/lib/string.gi", + "pkg/utils/lib/gslp.gi", + "pkg/utils/lib/download.gi", + "pkg/genss/init.g", + "pkg/genss/gap/genss.gd", + "pkg/genss/gap/setwise.gd", + "pkg/genss/read.g", + "pkg/genss/gap/genss.gi", + "pkg/genss/gap/setwise.gi", + "pkg/atlasrep/init.g", + "pkg/atlasrep/gap/userpref.g", + "pkg/atlasrep/gap/bbox.gd", + "pkg/atlasrep/gap/access.gd", + "pkg/atlasrep/gap/scanmtx.gd", + "pkg/atlasrep/gap/scanmtx.gi", + "pkg/atlasrep/gap/types.gd", + "pkg/atlasrep/gap/interfac.gd", + "pkg/atlasrep/gap/mindeg.gd", + "pkg/atlasrep/gap/utils.gd", + "pkg/ctbllib/init.g", + "pkg/ctbllib/gap4/ctadmin.gd", + "pkg/ctbllib/gap4/construc.gd", + "pkg/ctbllib/gap4/ctblothe.gd", + "pkg/ctbllib/dlnames/dlnames.gd", + "pkg/ctbllib/gap4/obsolete.gd", + "pkg/ctbllib/gap4/brdbattrX.gd", + "pkg/ctbllib/gap4/brdbattrX.gi", + "pkg/recog/init.g", + "pkg/recog/gap/base/hack.g", + "pkg/recog/gap/base/methods.gd", + "pkg/recog/gap/base/methsel.gd", + "pkg/recog/gap/base/recognition.gd", + "pkg/recog/gap/base/kernel.gd", + "pkg/recog/gap/base/projective.gd", + "pkg/recog/gap/matrix/ppd.gd", + "pkg/recog/gap/matrix/classical.gd", + "pkg/recog/gap/projective/almostsimple.gd", + "pkg/recog/gap/projective/findnormal.gd", + "pkg/recog/gap/projective/AnSnOnFDPM.gd", + "pkg/spinsym/init.g", + "pkg/spinsym/gap/mtx.gd", + "pkg/spinsym/gap/fus.gd", + "pkg/spinsym/gap/young.gd", + "pkg/standardff/init.g", + "pkg/standardff/lib/Util.gd", + "pkg/standardff/lib/IsIrred.gd", + "pkg/standardff/lib/StandardFF.gd", + "pkg/standardff/lib/StandardCyc.gd", + "pkg/tomlib/init.g", + "pkg/tomlib/gap/tmadmin.tmd", + "pkg/tomlib/gap/stdgen.gd", + "pkg/atlasrep/read.g", + "pkg/atlasrep/gap/bbox.gi", + "pkg/atlasrep/gap/access.gi", + "pkg/atlasrep/gap/types.gi", + "pkg/atlasrep/gap/interfac.gi", + "pkg/atlasrep/gap/mindeg.gi", + "pkg/atlasrep/gap/utlmrkup.g", + "pkg/atlasrep/gap/utils.gi", + "pkg/atlasrep/gap/test.g", + "pkg/atlasrep/gap/json.g", + "pkg/atlasrep/gap/obsolete.gd", + "pkg/atlasrep/gap/obsolete.gi", + "pkg/ctbllib/read.g", + "pkg/ctbllib/gap4/ctadmin.gi", + "pkg/ctbllib/gap4/ctprimar.g", + "pkg/ctbllib/data/firstnames.json", + "pkg/ctbllib/data/othernames.json", + "pkg/ctbllib/data/fusionsources.json", + "pkg/ctbllib/data/extinfo.json", + "pkg/ctbllib/data/ctgeneri.tbl", + "pkg/ctbllib/data/version", + "pkg/ctbllib/data/namerepl.json", + "pkg/ctbllib/gap4/construc.gi", + "pkg/ctbllib/gap4/ctblothe.gi", + "pkg/ctbllib/gap4/test.g", + "pkg/ctbllib/dlnames/dlnames.gi", + "pkg/ctbllib/gap4/ctbltoct.g", + "pkg/ctbllib/gap4/ctdbattr.g", + "pkg/ctbllib/gap4/od.g", + "pkg/ctbllib/data/odresults.json", + "pkg/ctbllib/gap4/atlasstr.g", + "pkg/ctbllib/gap4/atlasirr.g", + "pkg/recog/read.g", + "pkg/recog/gap/base/methods.gi", + "pkg/recog/gap/base/methsel.gi", + "pkg/recog/gap/base/recognition.gi", + "pkg/recog/gap/base/kernel.gi", + "pkg/recog/gap/base/projective.gi", + "pkg/recog/gap/utils.gi", + "pkg/recog/gap/generic/TrivialGroup.gi", + "pkg/recog/gap/generic/FewGensAbelian.gi", + "pkg/recog/gap/generic/KnownNilpotent.gi", + "pkg/recog/gap/perm/giant.gi", + "pkg/recog/gap/perm/largebase.gi", + "pkg/recog/gap/SnAnBB.gi", + "pkg/recog/gap/generic/SnAnUnknownDegree.gi", + "pkg/recog/gap/matrix/matimpr.gi", + "pkg/recog/gap/matrix/blocks.gi", + "pkg/recog/gap/matrix/ppd.gi", + "pkg/recog/gap/matrix/classical.gi", + "pkg/recog/gap/matrix/slconstr.gi", + "pkg/recog/gap/projective/findnormal.gi", + "pkg/recog/gap/projective/c6.gi", + "pkg/recog/gap/projective/tensor.gi", + "pkg/recog/gap/projective/c3c5.gi", + "pkg/recog/gap/projective/d247.gi", + "pkg/recog/gap/projective/almostsimple/threeelorders.gi", + "pkg/recog/gap/projective/almostsimple.gi", + "pkg/recog/gap/projective/almostsimple/lietype.gi", + "pkg/recog/gap/projective/almostsimple/hints.gi", + "pkg/recog/gap/projective/classicalnatural.gi", + "pkg/recog/gap/projective/sl2_natural.gi", + "pkg/recog/gap/projective/sl.gi", + "pkg/recog/gap/projective/AnSnOnFDPM.gi", + "pkg/recog/gap/perm.gi", + "pkg/recog/gap/matrix.gi", + "pkg/recog/gap/projective.gi", + "pkg/spinsym/read.g", + "pkg/spinsym/gap/mtx.gi", + "pkg/spinsym/gap/fus.gi", + "pkg/spinsym/gap/young.gi", + "pkg/standardff/read.g", + "pkg/standardff/lib/Util.gi", + "pkg/standardff/lib/IsIrred.gi", + "pkg/standardff/lib/StandardFF.gi", + "pkg/standardff/lib/StandardCyc.gi", + "pkg/standardff/lib/CANFACT.g", + "pkg/standardff/lib/TestFuncs.g", + "pkg/tomlib/read.g", + "pkg/tomlib/gap/tmstdrd.tom", + "pkg/tomlib/gap/tmadmin.tmi", + "pkg/tomlib/gap/stdgen.gi", + "pkg/atlasrep/gap/ctbllib_only.g", + "pkg/ctbllib/gap4/atlasrep_only.g", + "pkg/ctbllib/gap4/tomlib_only.g", + "pkg/ctbllib/data/tom_tbl.json", + "pkg/ctbllib/gap4/spinsym_only.g", + "pkg/ctbllib/data/grp_atlas.json", + "pkg/ctbllib/data/attr_nccl.json", + "pkg/ctbllib/data/grp_small.json", + "pkg/ctbllib/data/grp_tom.json", + "pkg/ctbllib/data/grp_trans.json", + "pkg/ctbllib/data/grp_prim.json", + "pkg/ctbllib/data/grp_perf.json", + "pkg/fga/init.g", + "pkg/fga/lib/util.gd", + "pkg/fga/lib/Iterated.gd", + "pkg/fga/lib/Autom.gd", + "pkg/fga/lib/FreeGrps.gd", + "pkg/fga/lib/ReprAct.gd", + "pkg/fga/lib/Normal.gd", + "pkg/fga/lib/ExtAutom.gd", + "pkg/fga/lib/Hom.gd", + "pkg/fga/lib/AutGrp.gd", + "pkg/fga/lib/Intsect.gd", + "pkg/fga/lib/Whitehd.gd", + "pkg/fga/read.g", + "pkg/fga/lib/util.gi", + "pkg/fga/lib/Iterated.gi", + "pkg/fga/lib/Autom.gi", + "pkg/fga/lib/FreeGrps.gi", + "pkg/fga/lib/ReprAct.gi", + "pkg/fga/lib/Normal.gi", + "pkg/fga/lib/Central.gi", + "pkg/fga/lib/Index.gi", + "pkg/fga/lib/ExtAutom.gi", + "pkg/fga/lib/Hom.gi", + "pkg/fga/lib/AutGrp.gi", + "pkg/fga/lib/Intsect.gi", + "pkg/fga/lib/ReprActT.gi", + "pkg/fga/lib/Whitehd.gi", + "pkg/irredsol/init.g", + "pkg/irredsol/lib/util.g", + "pkg/irredsol/lib/util.gd", + "pkg/irredsol/lib/matmeths.gd", + "pkg/irredsol/lib/loading.gd", + "pkg/irredsol/lib/loadfp.gd", + "pkg/irredsol/lib/access.gd", + "pkg/irredsol/lib/iterators.gd", + "pkg/irredsol/lib/recognize.gd", + "pkg/irredsol/lib/primitive.gd", + "pkg/irredsol/lib/recognizeprim.gd", + "pkg/irredsol/lib/obsolete.gd", + "pkg/irredsol/read.g", + "pkg/irredsol/lib/matmeths.gi", + "pkg/irredsol/lib/loading.gi", + "pkg/irredsol/lib/loadfp.gi", + "pkg/irredsol/lib/access.gi", + "pkg/irredsol/lib/iterators.gi", + "pkg/irredsol/lib/recognize.gi", + "pkg/irredsol/lib/primitive.gi", + "pkg/irredsol/lib/recognizeprim.gi", + "pkg/irredsol/lib/util.gi", + "pkg/irredsol/lib/obsolete.gi", + "pkg/sophus/init.g", + "pkg/sophus/gap/sophus.gd", + "pkg/sophus/read.g", + "pkg/sophus/gap/general.gi", + "pkg/sophus/gap/lienp.gi", + "pkg/sophus/gap/liesct.gi", + "pkg/sophus/gap/liecover.gi", + "pkg/sophus/gap/nicestab.gi", + "pkg/sophus/gap/lieautoops.gi", + "pkg/sophus/gap/initauts.gi", + "pkg/sophus/gap/lieautgrp.gi", + "pkg/sophus/gap/allowable.gi", + "pkg/sophus/gap/descendant.gi", + "pkg/sophus/gap/lieisom.gi", + "pkg/sophus/gap/io.gi", + "pkg/laguna/init.g", + "pkg/laguna/lib/laguna.gd", + "pkg/laguna/lib/laguna.g", + "pkg/laguna/read.g", + "pkg/laguna/lib/laguna.gi", + "pkg/autodoc/init.g", + "pkg/autodoc/gap/DocumentationTree.gd", + "pkg/autodoc/gap/Parser.gd", + "pkg/autodoc/gap/AutoDocMainFunction.gd", + "pkg/autodoc/gap/ToolFunctions.gd", + "pkg/autodoc/gap/Magic.gd", + "pkg/autodoc/gap/Markdown.gd", + "pkg/autodoc/read.g", + "pkg/autodoc/gap/ToolFunctions.gi", + "pkg/autodoc/gap/DocumentationTree.gi", + "pkg/autodoc/gap/Parser.gi", + "pkg/autodoc/gap/AutoDocMainFunction.gi", + "pkg/autodoc/gap/Magic.gi", + "pkg/autodoc/gap/Markdown.gi", + "pkg/packagemanager/init.g", + "pkg/packagemanager/gap/PackageManager.gd", + "pkg/packagemanager/gap/archive.gd", + "pkg/packagemanager/gap/compile.gd", + "pkg/packagemanager/gap/directories.gd", + "pkg/packagemanager/gap/distro.gd", + "pkg/packagemanager/gap/doc.gd", + "pkg/packagemanager/gap/download.gd", + "pkg/packagemanager/gap/git.gd", + "pkg/packagemanager/gap/hg.gd", + "pkg/packagemanager/gap/interactive.gd", + "pkg/packagemanager/gap/packageinfo.gd", + "pkg/packagemanager/read.g", + "pkg/packagemanager/gap/PackageManager.gi", + "pkg/packagemanager/gap/archive.gi", + "pkg/packagemanager/gap/compile.gi", + "pkg/packagemanager/gap/directories.gi", + "pkg/packagemanager/gap/distro.gi", + "pkg/packagemanager/gap/doc.gi", + "pkg/packagemanager/gap/download.gi", + "pkg/packagemanager/gap/git.gi", + "pkg/packagemanager/gap/hg.gi", + "pkg/packagemanager/gap/interactive.gi", + "pkg/packagemanager/gap/packageinfo.gi", + "pkg/radiroot/init.g", + "pkg/radiroot/lib/Radicals.gd", + "pkg/radiroot/lib/SplittField.gd", + "pkg/radiroot/lib/Manipulations.gd", + "pkg/radiroot/lib/Strings.gd", + "pkg/radiroot/lib/Maple.gd", + "pkg/radiroot/read.g", + "pkg/radiroot/lib/Radicals.gi", + "pkg/radiroot/lib/SplittField.gi", + "pkg/radiroot/lib/Manipulations.gi", + "pkg/radiroot/lib/Strings.gi", + "pkg/radiroot/lib/Maple.gi", + "pkg/aclib/init.g", + "pkg/aclib/gap/groups.gd", + "pkg/cryst/init.g", + "pkg/cryst/gap/common.gd", + "pkg/cryst/gap/cryst.gd", + "pkg/cryst/gap/hom.gd", + "pkg/cryst/gap/wyckoff.gd", + "pkg/cryst/gap/zass.gd", + "pkg/cryst/gap/max.gd", + "pkg/cryst/gap/color.gd", + "pkg/cryst/gap/equiv.gd", + "pkg/cryst/grp/spacegrp.gd", + "pkg/crystcat/init.g", + "pkg/crystcat/lib/crystcat.gd", + "pkg/polenta/init.g", + "pkg/polenta/lib/finite.gd", + "pkg/polenta/lib/info.gd", + "pkg/polenta/lib/basic.gd", + "pkg/polenta/exam/test.gd", + "pkg/polenta/lib/cpcs.gd", + "pkg/polenta/lib/present.gd", + "pkg/polenta/lib/solvable.gd", + "pkg/polenta/lib/series.gd", + "pkg/polenta/lib/subgroups.gd", + "pkg/polenta/lib/ispolyz.gd", + "pkg/aclib/read.g", + "pkg/aclib/gap/matgrp3.gi", + "pkg/aclib/gap/matgrp4.gi", + "pkg/aclib/gap/matgrp.gi", + "pkg/aclib/gap/pcpgrp3.gi", + "pkg/aclib/gap/pcpgrp4.gi", + "pkg/aclib/gap/pcpgrp.gi", + "pkg/aclib/gap/betti.gi", + "pkg/aclib/gap/union.gi", + "pkg/aclib/gap/extend.gi", + "pkg/aclib/gap/crystgrp.gi", + "pkg/cryst/read.g", + "pkg/cryst/gap/common.gi", + "pkg/cryst/gap/hom.gi", + "pkg/cryst/gap/cryst.gi", + "pkg/cryst/gap/cryst2.gi", + "pkg/cryst/gap/fpgrp.gi", + "pkg/cryst/gap/zass.gi", + "pkg/cryst/gap/max.gi", + "pkg/cryst/gap/wyckoff.gi", + "pkg/cryst/gap/color.gi", + "pkg/cryst/gap/noxgap.gi", + "pkg/cryst/gap/pcpgrp.gi", + "pkg/cryst/gap/orbstab.gi", + "pkg/cryst/gap/equiv.gi", + "pkg/cryst/grp/spacegrp.grp", + "pkg/cryst/grp/spacegrp.gi", + "pkg/crystcat/read.g", + "pkg/crystcat/grp/crystcat.grp", + "pkg/crystcat/lib/crystcat.gi", + "pkg/crystcat/lib/normalizer.gi", + "pkg/polenta/read.g", + "pkg/polenta/lib/finite.gi", + "pkg/polenta/lib/basic.gi", + "pkg/polenta/lib/unipo.gi", + "pkg/polenta/lib/series.gi", + "pkg/polenta/lib/semi.gi", + "pkg/polenta/lib/ispoly.gi", + "pkg/polenta/lib/cpcs.gi", + "pkg/polenta/lib/present.gi", + "pkg/polenta/lib/isom.gi", + "pkg/polenta/lib/solvable.gi", + "pkg/polenta/exam/exam.gi", + "pkg/polenta/exam/test.gi", + "pkg/polenta/lib/subgroups.gi", + "pkg/polenta/lib/ispolyz.gi", + "pkg/resclasses/init.g", + "pkg/resclasses/lib/general.gd", + "pkg/resclasses/lib/z_pi.gd", + "pkg/resclasses/lib/resclass.gd", + "pkg/resclasses/lib/fixedrep.gd", + "pkg/resclasses/read.g", + "pkg/resclasses/lib/general.gi", + "pkg/resclasses/lib/resclaux.g", + "pkg/resclasses/lib/z_pi.gi", + "pkg/resclasses/lib/resclass.gi", + "pkg/resclasses/lib/fixedrep.gi", + "lib/obsolete.gi", + "pkg/4ti2interface/doc/manual.six", + "pkg/ace/doc/manual.six", + "pkg/aclib/doc/manual.six", + "pkg/agt/doc/manual.six", + "pkg/alco/doc/manual.six", + "pkg/alnuth/doc/manual.six", + "pkg/anupq/doc/manual.six", + "pkg/atlasrep/doc/manual.six", + "pkg/autodoc/doc/manual.six", + "pkg/automata/doc/manual.six", + "pkg/automgrp/doc/manual.six", + "pkg/autpgrp/doc/manual.six", + "pkg/browse/doc/manual.six", + "pkg/cap/doc/manual.six", + "pkg/caratinterface/doc/manual.six", + "pkg/cddinterface/doc/manual.six", + "pkg/circle/doc/manual.six", + "pkg/classicalmaximals/doc/manual.six", + "pkg/classicpres/doc/manual.six", + "pkg/cohomolo/doc/manual.six", + "pkg/congruence/doc/manual.six", + "pkg/corefreesub/doc/manual.six", + "pkg/corelg/doc/manual.six", + "pkg/crime/doc/manual.six", + "pkg/crisp/doc/manual.six", + "pkg/crypting/doc/manual.six", + "pkg/cryst/doc/manual.six", + "pkg/crystcat/doc/manual.six", + "pkg/ctbllib/doc/manual.six", + "pkg/ctbllib/doc2/manual.six", + "pkg/cubefree/doc/manual.six", + "pkg/curlinterface/doc/manual.six", + "pkg/cvec/doc/manual.six", + "pkg/datastructures/doc/manual.six", + "pkg/deepthought/doc/manual.six", + "pkg/design/doc/manual.six", + "pkg/difsets/doc/manual.six", + "pkg/digraphs/doc/manual.six", + "pkg/edim/doc/manual.six", + "pkg/example/doc/manual.six", + "pkg/examplesforhomalg/doc/manual.six", + "pkg/factint/doc/manual.six", + "pkg/ferret/doc/manual.six", + "pkg/fga/doc/manual.six", + "pkg/fining/doc/manual.six", + "pkg/float/doc/manual.six", + "pkg/format/doc/manual.six", + "pkg/forms/doc/manual.six", + "pkg/fplsa/doc/manual.six", + "pkg/fr/doc/manual.six", + "pkg/francy/doc/manual.six", + "pkg/fwtree/doc/manual.six", + "pkg/gapdoc/doc/manual.six", + "pkg/gapdoc/example/manual.six", + "pkg/gauss/doc/manual.six", + "pkg/gaussforhomalg/doc/manual.six", + "pkg/gbnp/doc/manual.six", + "pkg/generalizedmorphismsforcap/doc/manual.six", + "pkg/genss/doc/manual.six", + "pkg/gradedmodules/doc/manual.six", + "pkg/gradedringforhomalg/doc/manual.six", + "pkg/grape/doc/manual.six", + "pkg/groupoids/doc/manual.six", + "pkg/grpconst/doc/manual.six", + "pkg/guarana/doc/manual.six", + "pkg/guava/doc/manual.six", + "pkg/hap/doc/manual.six", + "pkg/hapcryst/doc/manual.six", + "pkg/hecke/doc/manual.six", + "pkg/help/doc/manual.six", + "pkg/homalg/doc/manual.six", + "pkg/homalgtocas/doc/manual.six", + "pkg/ibnp/doc/manual.six", + "pkg/idrel/doc/manual.six", + "pkg/images/doc/manual.six", + "pkg/inducereduce/doc/manual.six", + "pkg/intpic/doc/manual.six", + "pkg/io/doc/manual.six", + "pkg/io_forhomalg/doc/manual.six", + "pkg/irredsol/doc/manual.six", + "pkg/itc/doc/manual.six", + "pkg/json/doc/manual.six", + "pkg/jupyterkernel/doc/manual.six", + "pkg/jupyterviz/doc/manual.six", + "pkg/kan/doc/manual.six", + "pkg/kbmag/doc/manual.six", + "pkg/laguna/doc/manual.six", + "pkg/liealgdb/doc/manual.six", + "pkg/liepring/doc/manual.six", + "pkg/liering/doc/manual.six", + "pkg/linearalgebraforcap/doc/manual.six", + "pkg/lins/doc/manual.six", + "pkg/localizeringforhomalg/doc/manual.six", + "pkg/localnr/doc/manual.six", + "pkg/loops/doc/manual.six", + "pkg/lpres/doc/manual.six", + "pkg/majoranaalgebras/doc/manual.six", + "pkg/mapclass/doc/manual.six", + "pkg/matgrp/doc/manual.six", + "pkg/matricesforhomalg/doc/manual.six", + "pkg/modisom/doc/manual.six", + "pkg/modulargroup/doc/manual.six", + "pkg/modulepresentationsforcap/doc/manual.six", + "pkg/modules/doc/manual.six", + "pkg/monoidalcategories/doc/manual.six", + "pkg/nconvex/doc/manual.six", + "pkg/nilmat/doc/manual.six", + "pkg/nock/doc/manual.six", + "pkg/nofoma/doc/manual.six", + "pkg/normalizinterface/doc/manual.six", + "pkg/nq/doc/manual.six", + "pkg/numericalsgps/doc/manual.six", + "pkg/openmath/doc/manual.six", + "pkg/orb/doc/manual.six", + "pkg/origami/doc/manual.six", + "pkg/packagemaker/doc/manual.six", + "pkg/packagemanager/doc/manual.six", + "pkg/patternclass/doc/manual.six", + "pkg/permut/doc/manual.six", + "pkg/polenta/doc/manual.six", + "pkg/polycyclic/doc/manual.six", + "pkg/polymaking/doc/manual.six", + "pkg/primgrp/doc/manual.six", + "pkg/profiling/doc/manual.six", + "pkg/qdistrnd/doc/manual.six", + "pkg/qpa/doc/manual.six", + "pkg/quagroup/doc/manual.six", + "pkg/radiroot/doc/manual.six", + "pkg/rcwa/doc/manual.six", + "pkg/rds/doc/manual.six", + "pkg/recog/doc/manual.six", + "pkg/repndecomp/doc/manual.six", + "pkg/repsn/doc/manual.six", + "pkg/resclasses/doc/manual.six", + "pkg/ringsforhomalg/doc/manual.six", + "pkg/sco/doc/manual.six", + "pkg/scscp/doc/manual.six", + "pkg/semigroups/doc/manual.six", + "pkg/sglppow/doc/manual.six", + "pkg/sgpviz/doc/manual.six", + "pkg/simpcomp/doc/manual.six", + "pkg/singular/doc/manual.six", + "pkg/sl2reps/doc/manual.six", + "pkg/sla/doc/manual.six", + "pkg/smallantimagmas/doc/manual.six", + "pkg/smallclassnr/doc/manual.six", + "pkg/smallgrp/doc/manual.six", + "pkg/smallsemi/doc/manual.six", + "pkg/sonata/doc/ref/manual.six", + "pkg/sonata/doc/tut/manual.six", + "pkg/sophus/doc/manual.six", + "pkg/sotgrps/doc/manual.six", + "pkg/spinsym/doc/manual.six", + "pkg/standardff/doc/manual.six", + "pkg/symbcompcc/doc/manual.six", + "pkg/thelma/doc/manual.six", + "pkg/tomlib/doc/manual.six", + "pkg/toolsforhomalg/doc/manual.six", + "pkg/toric/doc/manual.six", + "pkg/transgrp/doc/manual.six", + "pkg/twistedconjugacy/doc/manual.six", + "pkg/typeset/doc/manual.six", + "pkg/ugaly/doc/manual.six", + "pkg/unipot/doc/manual.six", + "pkg/unitlib/doc/manual.six", + "pkg/utils/doc/manual.six", + "pkg/uuid/doc/manual.six", + "pkg/walrus/doc/manual.six", + "pkg/wedderga/doc/manual.six", + "pkg/wpe/doc/manual.six", + "pkg/xgap/doc/manual.six", + "pkg/xmod/doc/manual.six", + "pkg/xmodalg/doc/manual.six", + "pkg/yangbaxter/doc/manual.six", + "pkg/zeromqinterface/doc/manual.six" +] diff --git a/etc/emscripten/web-template/gap-fs.js b/etc/emscripten/web-template/gap-fs.js index f3a1467d42..ca8ea4f23d 100644 --- a/etc/emscripten/web-template/gap-fs.js +++ b/etc/emscripten/web-template/gap-fs.js @@ -1,3 +1,29 @@ +// Instrument fetch and XMLHttpRequest so the page can collect the list of +// URLs the worker actually requests, for rebuilding startup_manifest.json +// without scraping the browser network panel. Each unique URL is posted +// to the main thread as { type: "gap-fetched", url: ... }. +(function instrumentFetches() { + const seen = new Set(); + const report = (raw) => { + if (typeof raw !== "string") return; + if (seen.has(raw)) return; + seen.add(raw); + self.postMessage({ type: "gap-fetched", url: raw }); + }; + + const origFetch = self.fetch; + self.fetch = function(input, init) { + report(typeof input === "string" ? input : input && input.url); + return origFetch.apply(this, arguments); + }; + + const origOpen = XMLHttpRequest.prototype.open; + XMLHttpRequest.prototype.open = function(method, url) { + report(url); + return origOpen.apply(this, arguments); + }; +})(); + self.Module = self.Module || {}; self.Module.preRun = self.Module.preRun || []; @@ -43,8 +69,12 @@ self.Module.preRun.push(function() { if (p.startsWith('/')) p = p.substring(1); startupSet.add(p); }); + } else { + console.info("startup_manifest.json not present; falling back to fully lazy loading"); } - } catch (e) {} + } catch (e) { + console.warn("Failed to load startup_manifest.json:", e); + } var fetchPromises = fileList.map(async function(appPath) { var fetchRelativePath = appPath.split('/').map(encodeURIComponent).join('/'); @@ -58,16 +88,15 @@ self.Module.preRun.push(function() { FS.stat(idbfsPath); FS.writeFile(finalAppPath, FS.readFile(idbfsPath)); } catch (e) { - try { - const response = await fetch(fetchPath); - if (response.ok) { - const buffer = await response.arrayBuffer(); - const data = new Uint8Array(buffer); - FS.writeFile(finalAppPath, data); - FS.writeFile(idbfsPath, data); - needsSave = true; - } - } catch (fetchErr) {} + const response = await fetch(fetchPath); + if (!response.ok) { + throw new Error("Failed to fetch startup file " + fetchPath + ": " + response.status); + } + const buffer = await response.arrayBuffer(); + const data = new Uint8Array(buffer); + FS.writeFile(finalAppPath, data); + FS.writeFile(idbfsPath, data); + needsSave = true; } } else { var parts = appPath.split('/'); diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index b51df45fb8..d5f1bec759 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -1,22 +1,185 @@ - + + - gap-wasm + + + GAP in the browser + -
+
+

GAP in the browser

+

+ A WebAssembly build of GAP + running entirely in your browser — useful for trying things out + without installing. Not all packages work, working memory is + capped, and performance is reduced compared to a native build. + For real work, install GAP from + www.gap-system.org. +

+
+ +
+ What is this? · Licensing +

+ GAP is a system for + computational discrete algebra, with particular emphasis on + computational group theory. This page is a self-contained + WebAssembly build, served as a static site and run inside a + Web Worker; you interact with it through an + xterm-pty + terminal in the page below. +

+

+ To get started, try 1+1;, + Factorial(20);, or SymmetricGroup(5);. + The full GAP + manuals apply, with two caveats: some packages won't load + (anything that needs a native compiler or system library), and + anything that wants the local filesystem won't work. +

+

+ Files downloaded on first visit are cached in your browser's + IndexedDB, so subsequent visits start much faster. Clear the + site data to reset the cache. +

+

+ GAP is free software, distributed under the + GNU General Public License (version 2 or + later). See the copyright notice for + the full statement. +

+
+ +
+ Loading GAP… The first visit downloads several tens of megabytes; + subsequent visits are cached in your browser and load much faster. +
+ +
+ This page needs SharedArrayBuffer, which is only + available when the page is served with the headers + Cross-Origin-Opener-Policy: same-origin and + Cross-Origin-Embedder-Policy: require-corp. The + bundled service worker handles this on hosts where you can't set + headers (e.g. GitHub Pages); for local hosting use + etc/emscripten/serve.py. +
+ +
+
+
+ + + diff --git a/src/gasman.c b/src/gasman.c index 6712ebec79..7a616d6eb6 100644 --- a/src/gasman.c +++ b/src/gasman.c @@ -129,7 +129,7 @@ #include #include -#ifdef EMSCRIPTEN +#ifdef __EMSCRIPTEN__ #include #endif @@ -1957,7 +1957,7 @@ static NOINLINE void GenStackFuncBags(void) DisableMarkBagValidation = 1; #endif -#ifdef EMSCRIPTEN +#ifdef __EMSCRIPTEN__ emscripten_scan_stack(ScanRange); emscripten_scan_registers(ScanRange); // The standard scanning may not be required with From 2a86fd1a8a71afa8c3f6e36593587bed1c1f5053 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 1 Jun 2026 13:41:50 +0200 Subject: [PATCH 090/123] Update COPYRIGHT --- COPYRIGHT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COPYRIGHT b/COPYRIGHT index 6a58d3bd37..b144b05166 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with GAP; if not, see . -Copyright (C) 1988-2025 by its authors, which include: +Copyright (C) 1988-2026 by its authors, which include: * Ákos Seress * Alex Wegner From f6f18ce7504a61a50a8456b5d1e52d3d31f28a60 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 1 Jun 2026 22:34:43 +0200 Subject: [PATCH 091/123] Fix RingGeneralMappingByImages for non-SCRing (#6418) A filter was computed but not used. The filter that was used instead always implied IsSCRingGeneralMappingByImagesDefaultRep which is too broad. As a result, inappropriate methods were applied to some ring homomorphisms. Also add an example for using RingByStructureConstants. --- lib/ringhom.gi | 7 +------ lib/ringsc.gd | 8 ++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/ringhom.gi b/lib/ringhom.gi index 21791f48a8..9b3c908705 100644 --- a/lib/ringhom.gi +++ b/lib/ringhom.gi @@ -52,12 +52,7 @@ function( S, R, gens, imgs ) fi; # Make the general mapping. - map:= Objectify( TypeOfDefaultGeneralMapping( S, R, - IsSPGeneralMapping - and IsRingGeneralMapping - and IsSCRingGeneralMappingByImagesDefaultRep ), - rec( - ) ); + map:= Objectify( TypeOfDefaultGeneralMapping( S, R, filter ), rec( ) ); SetMappingGeneratorsImages(map,[Immutable(gens),Immutable(imgs)]); # return the general mapping diff --git a/lib/ringsc.gd b/lib/ringsc.gd index bd2116bcd7..9871317d71 100644 --- a/lib/ringsc.gd +++ b/lib/ringsc.gd @@ -47,6 +47,14 @@ DeclareSynonym("IsSubringSCRing",IsRing and IsSCRingObjCollection); ## it can be either a string name ## (then name1, name2 etc. are chosen) ## or a list of strings which are then chosen. +## T:=EmptySCTable( 1, 0 );; +## gap> SetEntrySCTable( T, 1, 1, [ 1, 1 ] ); +## gap> R:=RingByStructureConstants([9], T); # Z/9Z +## +## gap> Elements(R); +## [ 0*r.1, r.1, 2*r.1, 3*r.1, 4*r.1, 5*r.1, 6*r.1, 7*r.1, -r.1 ] +## ]]> ##
##
## <#/GAPDoc> From cb52dc767b353511c540e2d70508e108b2bc3625 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 1 Jun 2026 22:41:56 +0200 Subject: [PATCH 092/123] Update CHANGES.md --- CHANGES.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 48c602ec6b..a2e9050afa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ # GAP - history of changes -## GAP 4.16.0 (May 2026) +## GAP 4.16.0 (June 2026) The following gives an overview of the changes compared to the previous release. This list is not complete, many more internal or minor changes @@ -91,6 +91,7 @@ affect some users directly. ### Fixed bugs that could lead to unexpected errors +- [#6418](https://github.com/gap-system/gap/pull/6418) Fix `RingGeneralMappingByImages` for non-SCRing - [#6196](https://github.com/gap-system/gap/pull/6196) Fix an inconsistency problem in `IsFinite` for matrix groups over cycl. fields. - [#6159](https://github.com/gap-system/gap/pull/6159) Fix a potential error message about data types when computing extensions @@ -116,10 +117,10 @@ affect some users directly. #### Updated packages redistributed with GAP -The GAP 4.16.0 distribution contains 172 packages, of which 68 have been +The GAP 4.16.0 distribution contains 172 packages, of which 69 have been updated since GAP 4.15.1. The full list of updated packages is given below: -- [**4ti2Interface**](https://homalg-project.github.io/pkg/4ti2Interface): 2024.11-01 -> 2025.12-01 +- [**4ti2Interface**](https://homalg-project.github.io/pkg/4ti2Interface): 2024.11-01 -> 2026.05-01 - [**Alnuth**](https://gap-packages.github.io/alnuth): 3.2.1 -> 4.0.0 - [**ANUPQ**](https://gap-packages.github.io/anupq/): 3.3.2 -> 3.3.3 - [**AtlasRep**](https://www.math.rwth-aachen.de/~Thomas.Breuer/atlasrep): 2.1.9 -> 2.1.11 @@ -137,6 +138,7 @@ updated since GAP 4.15.1. The full list of updated packages is given below: - [**Digraphs**](https://digraphs.github.io/Digraphs): 1.13.1 -> 1.14.0 - [**ExamplesForHomalg**](https://homalg-project.github.io/pkg/ExamplesForHomalg): 2023.10-01 -> 2025.12-01 - [**ferret**](https://gap-packages.github.io/ferret/): 1.0.15 -> 1.0.16 +- [**float**](https://gap-packages.github.io/float/): 1.0.9 -> 1.0.10 - [**FORMAT**](https://gap-packages.github.io/format/): 1.4.4 -> 1.4.5 - [**Forms**](https://gap-packages.github.io/forms): 1.2.13 -> 1.3.0 - [**FPLSA**](https://gap-packages.github.io/FPLSA): 1.2.7 -> 1.2.8 @@ -157,7 +159,7 @@ updated since GAP 4.15.1. The full list of updated packages is given below: - [**IO_ForHomalg**](https://homalg-project.github.io/pkg/IO_ForHomalg): 2023.02-04 -> 2025.12-01 - [**json**](https://gap-packages.github.io/json/): 2.2.3 -> 2.4.0 - [**LinearAlgebraForCAP**](https://homalg-project.github.io/pkg/LinearAlgebraForCAP): 2025.09-01 -> 2026.05-04 -- [**LocalizeRingForHomalg**](https://homalg-project.github.io/pkg/LocalizeRingForHomalg): 2023.10-01 -> 2026.04-01 +- [**LocalizeRingForHomalg**](https://homalg-project.github.io/pkg/LocalizeRingForHomalg): 2023.10-01 -> 2026.05-01 - [**lpres**](https://gap-packages.github.io/lpres): 1.1.1 -> 1.1.2 - [**matgrp**](https://www.math.colostate.edu/~hulpke/matgrp): 0.72 -> 0.73 - [**MatricesForHomalg**](https://homalg-project.github.io/pkg/MatricesForHomalg): 2025.09-01 -> 2026.04-01 @@ -174,7 +176,7 @@ updated since GAP 4.15.1. The full list of updated packages is given below: - [**qpa**](https://gap-packages.github.io/qpa): 1.35 -> 1.37 - [**RCWA**](https://gap-packages.github.io/rcwa/): 4.8.0 -> 4.9.0 - [**recog**](https://gap-packages.github.io/recog): 1.4.4 -> 1.5.1 -- [**RingsForHomalg**](https://homalg-project.github.io/pkg/RingsForHomalg): 2024.11-02 -> 2025.12-01 +- [**RingsForHomalg**](https://homalg-project.github.io/pkg/RingsForHomalg): 2024.11-02 -> 2026.05-01 - [**SCO**](https://homalg-project.github.io/pkg/SCO): 2023.08-01 -> 2025.12-01 - [**Semigroups**](https://semigroups.github.io/Semigroups): 5.5.4 -> 5.6.3 - [**singular**](https://gap-packages.github.io/singular/): 2025.08.26 -> 2026.05.05 From 34c914b9d3d8865190a157758f1a7d5948b469b5 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 2 Jun 2026 00:03:15 +0200 Subject: [PATCH 093/123] Normalize release archive permissions (#6420) Remove group and other write bits before creating release archives. Keep package contents readable while preserving and normalizing executable bits. Co-authored-by: Codex --- .github/workflows/release.yml | 2 +- Makefile.rules | 7 ++++-- dev/releases/make_archives.py | 11 +++++---- dev/releases/test_archive_utils.py | 39 ++++++++++++++++++++++++++++++ dev/releases/utils.py | 24 ++++++++++++++++++ 5 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 dev/releases/test_archive_utils.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 36867a212c..eb4ce3c91b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,7 +57,7 @@ jobs: # run: python -m mypy --disallow-untyped-calls --disallow-untyped-defs dev/releases/*.py - name: "Run tests" - run: cd dev/releases && python -m pytest test_release_notes.py + run: cd dev/releases && python -m pytest unix: name: "Create Unix archives and data" diff --git a/Makefile.rules b/Makefile.rules index ffe22eb1ba..e2512739ec 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -24,8 +24,11 @@ default: all ######################################################################## # Developer helper targets ######################################################################## -test_release_notes: - cd dev/releases && python3 -m pytest test_release_notes.py +test_release_scripts: + cd dev/releases && python3 -m pytest +.PHONY: test_release_scripts + +test_release_notes: test_release_scripts .PHONY: test_release_notes diff --git a/dev/releases/make_archives.py b/dev/releases/make_archives.py index 5b06f8e0f3..33fe219c1b 100755 --- a/dev/releases/make_archives.py +++ b/dev/releases/make_archives.py @@ -29,6 +29,7 @@ from utils import ( download_with_sha256, error, + normalize_archive_permissions, notice, patchfile, verify_command_available, @@ -211,14 +212,11 @@ def run_with_log(args: List[str], name: str, msg: Optional[str] = None) -> None: notice("Extracting package tarballs") with tarfile.open(tmpdir + "/" + all_packages_tarball) as tar: tar.extractall(path="pkg") - # for some reason pkg sometimes ends up with permission 0700 so - # we make sure to fix that here - subprocess.run(["chmod", "0755", "pkg"], check=True) - # ensure all files are at readable by everyone - subprocess.run(["chmod", "-R", "a+r", "."], check=True) with tarfile.open(tmpdir + "/" + req_packages_tarball) as tar: tar.extractall(path=tmpdir + "/" + req_packages) + notice("Normalizing permissions in required packages") + normalize_archive_permissions(tmpdir + "/" + req_packages) notice("Building GAP's manuals") run_with_log(["make", "doc"], "gapdoc", "building the manuals") @@ -278,6 +276,9 @@ def run_with_log(args: List[str], name: str, msg: Optional[str] = None) -> None: notice("Removing generated files we don't want to distribute") run_with_log(["make", "distclean"], "make-distclean", "make distclean") + notice("Normalizing permissions in GAP archive tree") + normalize_archive_permissions(".") + # Create an archive in the current directory with shutil.make_archive, and # record the filename of the new archive in . diff --git a/dev/releases/test_archive_utils.py b/dev/releases/test_archive_utils.py new file mode 100644 index 0000000000..ef05608a4a --- /dev/null +++ b/dev/releases/test_archive_utils.py @@ -0,0 +1,39 @@ +import os +import stat + +from utils import normalize_archive_permissions + + +def mode(path): + return stat.S_IMODE(os.stat(path).st_mode) + + +def test_normalize_archive_permissions_removes_group_and_other_write_bits(tmp_path): + package_dir = tmp_path / "pkg" + package_dir.mkdir() + private_dir = package_dir / "private" + private_dir.mkdir() + unreadable_dir = package_dir / "unreadable" + unreadable_dir.mkdir() + world_writable_file = package_dir / "data.g" + world_writable_file.write_text("data", encoding="utf-8") + executable_file = package_dir / "script.sh" + executable_file.write_text("#!/bin/sh\n", encoding="utf-8") + oddly_executable_file = package_dir / "odd.g" + oddly_executable_file.write_text("data", encoding="utf-8") + + os.chmod(package_dir, 0o777) + os.chmod(private_dir, 0o700) + os.chmod(unreadable_dir, 0o600) + os.chmod(world_writable_file, 0o666) + os.chmod(executable_file, 0o777) + os.chmod(oddly_executable_file, 0o654) + + normalize_archive_permissions(tmp_path) + + assert mode(package_dir) == 0o755 + assert mode(private_dir) == 0o755 + assert mode(unreadable_dir) == 0o755 + assert mode(world_writable_file) == 0o644 + assert mode(executable_file) == 0o755 + assert mode(oddly_executable_file) == 0o644 diff --git a/dev/releases/utils.py b/dev/releases/utils.py index e38c0ba72f..c14420f7c6 100644 --- a/dev/releases/utils.py +++ b/dev/releases/utils.py @@ -12,6 +12,7 @@ import os import re import shutil +import stat import subprocess import sys from typing import Iterator, NoReturn @@ -74,6 +75,29 @@ def working_directory(path: str) -> Iterator[None]: os.chdir(prev_cwd) +def normalize_archive_permissions(root: str) -> None: + """Apply the archive permission policy recursively below ``root``. + + This mirrors ``chmod -R g-w,o-w,g+r,o+r`` for regular files and also makes + directories searchable by group and others. File executable bits are + normalized from the owner's executable bit, so scripts remain executable + without making ordinary data files executable. Symlinks are left untouched. + """ + for dirpath, dirnames, filenames in os.walk(root): + for name in [dirpath, *dirnames, *filenames]: + path = os.path.join(dirpath, name) if name != dirpath else dirpath + if os.path.islink(path): + continue + mode = stat.S_IMODE(os.stat(path).st_mode) + mode |= stat.S_IRGRP | stat.S_IROTH + mode &= ~(stat.S_IWGRP | stat.S_IWOTH) + if os.path.isdir(path) or mode & stat.S_IXUSR: + mode |= stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH + else: + mode &= ~(stat.S_IXGRP | stat.S_IXOTH) + os.chmod(path, mode) + + # compute the sha256 checksum of a file def sha256file(path: str) -> str: h = hashlib.sha256() From 82b1bc7822cf66e66c5ced2f82f8c3e10e257071 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 5 Jun 2026 17:51:53 +0200 Subject: [PATCH 094/123] julia-gc: introduce DISABLE_STACK_SCAN (#6421) Useful for debugging, and future work on alternative GC integration. --- src/julia_gc.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/julia_gc.c b/src/julia_gc.c index 568b567b1e..f04d51e918 100644 --- a/src/julia_gc.c +++ b/src/julia_gc.c @@ -67,6 +67,8 @@ // should not be enabled by default. // #define VALIDATE_MARKING +// if DISABLE_STACK_SCAN is defined, all stack scanning is disabled +// #define DISABLE_STACK_SCAN // if USE_GAP_INSIDE_JULIA is defined, then some hacks which are needed // to make julia-inside-gap work are disabled. This is mainly for use in @@ -166,13 +168,15 @@ static jl_datatype_t * DatatypeGapObj; static jl_datatype_t * DatatypeSmallBag; static jl_datatype_t * DatatypeLargeBag; +#ifndef DISABLE_STACK_SCAN static jl_task_t * ScannedRootTask; +#endif static size_t MaxPoolObjSize; static int FullGC; static UInt StartTime, TotalTime; -#if !defined(USE_GAP_INSIDE_JULIA) +#if !defined(USE_GAP_INSIDE_JULIA) && !defined(DISABLE_STACK_SCAN) static Bag * GapStackBottom; static jl_task_t * RootTaskOfMainThread; #endif @@ -184,8 +188,10 @@ static TNumFreeFuncBags TabFreeFuncBags[NUM_TYPES]; // HACK: TabMarkFuncBags is accessed by MarkCopyingSubBags in src/objects.c TNumMarkFuncBags TabMarkFuncBags[NUM_TYPES]; +#ifndef DISABLE_STACK_SCAN static TaskInfoTree * TaskStacks; static pthread_mutex_t TaskStacksMutex; +#endif // // global bags @@ -325,6 +331,8 @@ void MarkJuliaWeakRef(void * p, void * ref) } +#ifndef DISABLE_STACK_SCAN + // Overview of conservative stack scanning // // A key aspect of conservative marking is that we need to determine whether a @@ -627,6 +635,8 @@ static void GapTaskScanner(jl_task_t * task, int root_task) } } +#endif // DISABLE_STACK_SCAN + // Julia callback static void PreGCHook(int full) { @@ -653,7 +663,9 @@ static void PreGCHook(int full) // Julia callback static void PostGCHook(int full) { +#ifndef DISABLE_STACK_SCAN ScannedRootTask = 0; +#endif TotalTime += SyTime() - StartTime; #ifdef COLLECT_MARK_CACHE_STATS /* printf("\n>>>Attempts: %ld\nHit rate: %lf\nCollision rate: %lf\n", @@ -758,6 +770,7 @@ void GAP_InitJuliaMemoryInterface(jl_module_t * module, jl_init(); #endif +#ifndef DISABLE_STACK_SCAN if (jl_n_gcthreads > 1) pthread_mutex_init(&TaskStacksMutex, NULL); TaskStacks = TaskInfoTreeMake(); @@ -766,6 +779,7 @@ void GAP_InitJuliaMemoryInterface(jl_module_t * module, // TLS and thus need to be installed after initialization. jl_gc_set_cb_root_scanner(GapRootScanner, 1); jl_gc_set_cb_task_scanner(GapTaskScanner, 1); +#endif jl_gc_set_cb_pre_gc(PreGCHook, 1); jl_gc_set_cb_post_gc(PostGCHook, 1); // jl_gc_enable(0); /// DEBUGGING @@ -816,7 +830,7 @@ void InitBags(UInt initial_size, Bag * stack_bottom) { TotalTime = 0; -#if !defined(USE_GAP_INSIDE_JULIA) +#if !defined(USE_GAP_INSIDE_JULIA) && !defined(DISABLE_STACK_SCAN) // initialize Julia memory interface. Note that this is only necessary // when we run standalone. In contrast, when GAP is loaded from GAP.jl // then GAP.jl invokes `GAP_InitJuliaMemoryInterface` at an appropriate From e4acd39883e13362282480486806e60a72aadb9d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 6 Jun 2026 08:35:18 +0200 Subject: [PATCH 095/123] Miscellaneous kernel tweaks (#6422) * kernel: fix typo in src/gasman.c * CREATE_PTY_IOSTREAM: require args as plist * ExecuteProcess: require args as plist * kernel: change AUTO to require plain list --- lib/streams.gi | 3 +++ src/gasman.c | 4 ++-- src/gvars.c | 11 ++++++++--- src/iostream.c | 12 +++++++----- tst/testinstall/kernel/streams.tst | 2 +- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/streams.gi b/lib/streams.gi index 5f0f44aa73..f105a1c635 100644 --- a/lib/streams.gi +++ b/lib/streams.gi @@ -1367,6 +1367,9 @@ InstallGlobalFunction( InputOutputLocalProcess, Error("Can't handle new rep for directories"); fi; dirname := cdir![1]; + if not IsPlistRep(argts) then + argts := PlainListCopy(argts); + fi; ptynum := CREATE_PTY_IOSTREAM( dirname, exec, argts); if ptynum = fail then return fail; diff --git a/src/gasman.c b/src/gasman.c index 7a616d6eb6..0575a384b7 100644 --- a/src/gasman.c +++ b/src/gasman.c @@ -2026,7 +2026,7 @@ static UInt CollectBags_Mark(UInt FullBags) // For old bags, we invoke the marking function for bags with the // given TNUM. // Young bags normally are never put onto the changed list, because - // CHANGED_BAGS ignores young bags. However, it can happen if we + // CHANGED_BAG ignores young bags. However, it can happen if we // resize an old bag and it needs to be moved as a result, or if we // swap the masterpointers of an old and a young bag. In that case, // we must be careful to not collect the young bag (which was old @@ -2566,7 +2566,7 @@ void CheckMasterPointers( void ) // we must make sure to mark the new bag2 as changed, too (and vice-versa). // // 2. Both bags are young. Then they typically will not be on the list of -// changed bags, as CHANGED_BAGS just skips them. +// changed bags, as CHANGED_BAG just skips them. // However, while CHANGED_BAG will never put a young bag on the list of // changed bags, young bags can still be put on the ChangedBags list in // step 3, so we need to do something similar as in step 1. diff --git a/src/gvars.c b/src/gvars.c index e705d8e885..5232cd2d21 100644 --- a/src/gvars.c +++ b/src/gvars.c @@ -832,19 +832,24 @@ static Obj FuncAUTO(Obj self, Obj args) UInt gvar; // one global variable UInt i; // loop variable + RequirePlainList(SELF_NAME, args); + RequireDenseList(SELF_NAME, args); + RequireArgumentCondition(SELF_NAME, args, LEN_PLIST(args) >= 2, + "must be a list of length at least 2"); + // get and check the function - func = ELM_LIST( args, 1 ); + func = ELM_PLIST( args, 1 ); RequireFunction(SELF_NAME, func); // get the argument - arg = ELM_LIST( args, 2 ); + arg = ELM_PLIST( args, 2 ); // make the list of function and argument list = NewPlistFromArgs(func, arg); // make the global variables automatic for ( i = 3; i <= LEN_LIST(args); i++ ) { - name = ELM_LIST( args, i ); + name = ELM_PLIST( args, i ); RequireStringRep(SELF_NAME, name); gvar = GVarName( CONST_CSTR_STRING(name) ); SET_ELM_GVAR_LIST( ValGVars, gvar, 0 ); diff --git a/src/iostream.c b/src/iostream.c index c108389724..3773f4b3a3 100644 --- a/src/iostream.c +++ b/src/iostream.c @@ -30,6 +30,7 @@ #include "io.h" #include "lists.h" #include "modules.h" +#include "plist.h" #include "stringobj.h" #include "sysenv.h" #include "sysfiles.h" @@ -858,13 +859,14 @@ static Obj FuncCREATE_PTY_IOSTREAM(Obj self, Obj dir, Obj prog, Obj args) Char * argv[MAX_ARGS + 2]; UInt i, len; Int pty; - len = LEN_LIST(args); + RequirePlainList(SELF_NAME, args); + len = LEN_PLIST(args); if (len > MAX_ARGS) ErrorQuit("Too many arguments", 0, 0); ConvString(dir); ConvString(prog); for (i = 1; i <= len; i++) { - allargs[i] = ELM_LIST(args, i); + allargs[i] = ELM_PLIST(args, i); ConvString(allargs[i]); } // From here we cannot afford to have a garbage collection @@ -1098,13 +1100,13 @@ FuncExecuteProcess(Obj self, Obj dir, Obj prg, Obj in, Obj out, Obj args) RequireStringRep(SELF_NAME, prg); Int iin = GetSmallInt(SELF_NAME, in); Int iout = GetSmallInt(SELF_NAME, out); - RequireSmallList(SELF_NAME, args); + RequirePlainList(SELF_NAME, args); // create an argument array - for (i = 1; i <= LEN_LIST(args); i++) { + for (i = 1; i <= LEN_PLIST(args); i++) { if (i == 1023) break; - tmp = ELM_LIST(args, i); + tmp = ELM_PLIST(args, i); RequireStringRep(SELF_NAME, tmp); ExecArgs[i] = tmp; } diff --git a/tst/testinstall/kernel/streams.tst b/tst/testinstall/kernel/streams.tst index ebf5349ae6..12a3859cf5 100644 --- a/tst/testinstall/kernel/streams.tst +++ b/tst/testinstall/kernel/streams.tst @@ -293,7 +293,7 @@ Error, ExecuteProcess: must be a small integer (not the value 'fail') gap> ExecuteProcess("","",0,fail,fail); Error, ExecuteProcess: must be a small integer (not the value 'fail') gap> ExecuteProcess("","",0,0,fail); -Error, ExecuteProcess: must be a small list (not the value 'fail') +Error, ExecuteProcess: must be a plain list (not the value 'fail') gap> ExecuteProcess("","",0,0,[1]); Error, ExecuteProcess: must be a string (not the integer 1) From 54e3cbe1f60c9820ff022c61a3191fc7bf00e0cf Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 6 Jun 2026 13:06:11 +0200 Subject: [PATCH 096/123] More kernel tweaks (#6428) * kernel: drop unused return value of UseTmpPerm * kernel: use BOOL in more places * kernel: init buffer with memset * kernel: use size_t in some places * kernel: explain certain uses of 'extern inline' * kernel: update some comments --- src/code.c | 1 + src/collectors.cc | 25 ++++++------- src/cyclotom.c | 1 + src/exprs.c | 1 + src/funcs.c | 1 + src/gaptime.c | 8 ++--- src/gvars.c | 16 ++++----- src/io.c | 2 +- src/lists.c | 56 ++++++++++++++--------------- src/main.c | 3 +- src/objcftl.c | 1 + src/objset.c | 8 ++--- src/opers.cc | 25 ++++++------- src/permutat.cc | 3 +- src/plist.c | 92 +++++++++++++++++++++++------------------------ src/profile.c | 2 +- src/read.c | 10 +++--- src/records.c | 2 +- src/scanner.c | 2 +- src/sortbase.h | 9 ++--- src/sysfiles.c | 24 ++++++------- src/sysstr.h | 13 +++---- src/tietze.c | 34 +++++++++--------- src/trans.cc | 13 +++---- src/weakptr.c | 4 +-- 25 files changed, 183 insertions(+), 173 deletions(-) diff --git a/src/code.c b/src/code.c index 5ff2315c98..40268f9de8 100644 --- a/src/code.c +++ b/src/code.c @@ -57,6 +57,7 @@ DECL_MODULE_STATE Int CountExpr; static ModuleStateOffset CodeStateOffset = -1; +// for debugging from GDB / lldb, we mark this as extern inline extern inline struct CodeModuleState * CShelper(void) { return (struct CodeModuleState *)StateSlotsAtOffset(CodeStateOffset); diff --git a/src/collectors.cc b/src/collectors.cc index 3a8f37b314..c3561ea8db 100644 --- a/src/collectors.cc +++ b/src/collectors.cc @@ -63,6 +63,7 @@ DECL_MODULE_STATE UInt SC_MAX_STACK_SIZE; static ModuleStateOffset CollectorsStateOffset = -1; +// for debugging from GDB / lldb, we mark this as extern inline extern inline struct CollectorsState_ * CollectorsState(void) { return (struct CollectorsState_ *)StateSlotsAtOffset(CollectorsStateOffset); @@ -380,7 +381,7 @@ static Int SingleCollectWord(Obj sc, Obj vv, Obj w) Obj tmp; // temporary obj for power - Int resized = 0;// indicates whether a Resize() happened + BOOL resized = FALSE;// indicates whether a Resize() happened // is the first non-trivial entry in start = SC_NUMBER_RWS_GENERATORS(sc); @@ -421,23 +422,23 @@ static Int SingleCollectWord(Obj sc, Obj vv, Obj w) const UInt desiredStackSize = sizeof(Obj) * (max + 2); if ( SIZE_OBJ(vnw) < desiredStackSize ) { ResizeBag( vnw, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vlw) < desiredStackSize ) { ResizeBag( vlw, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vpw) < desiredStackSize ) { ResizeBag( vpw, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vew) < desiredStackSize ) { ResizeBag( vew, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vge) < desiredStackSize ) { ResizeBag( vge, desiredStackSize ); - resized = 1; + resized = TRUE; } if( resized ) return -1; @@ -891,7 +892,7 @@ static Int CombiCollectWord(Obj sc, Obj vv, Obj w) Obj tmp; // temporary obj for power - Int resized = 0;// indicates whether a Resize() happened + BOOL resized = FALSE;// indicates whether a Resize() happened // if is the identity return now if ( NPAIRS_WORD(w) == 0 ) { @@ -929,23 +930,23 @@ static Int CombiCollectWord(Obj sc, Obj vv, Obj w) const UInt desiredStackSize = sizeof(Obj) * (max + 2); if ( SIZE_OBJ(vnw) < desiredStackSize ) { ResizeBag( vnw, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vlw) < desiredStackSize ) { ResizeBag( vlw, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vpw) < desiredStackSize ) { ResizeBag( vpw, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vew) < desiredStackSize ) { ResizeBag( vew, desiredStackSize ); - resized = 1; + resized = TRUE; } if ( SIZE_OBJ(vge) < desiredStackSize ) { ResizeBag( vge, desiredStackSize ); - resized = 1; + resized = TRUE; } if( resized ) return -1; diff --git a/src/cyclotom.c b/src/cyclotom.c index 3025530f94..e626946916 100644 --- a/src/cyclotom.c +++ b/src/cyclotom.c @@ -185,6 +185,7 @@ DECL_MODULE_STATE UInt LastNCyc; #ifdef HPCGAP }; // end of struct CycModuleState +// for debugging from GDB / lldb, we mark this as extern inline extern inline struct CycModuleState *CycState(void) { return (struct CycModuleState *)StateSlotsAtOffset(CycStateOffset); diff --git a/src/exprs.c b/src/exprs.c index 2c234633ad..840d2d709b 100644 --- a/src/exprs.c +++ b/src/exprs.c @@ -66,6 +66,7 @@ DECL_MODULE_STATE UInt OldPrintPrecedence; static ModuleStateOffset ExprsStateOffset = -1; +// for debugging from GDB / lldb, we mark this as extern inline extern inline struct ExprsState * ExprsState(void) { return (struct ExprsState *)StateSlotsAtOffset(ExprsStateOffset); diff --git a/src/funcs.c b/src/funcs.c index 62919177f5..16acf1fb93 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -50,6 +50,7 @@ struct FuncsModuleState { #ifdef HPCGAP }; +// for debugging from GDB / lldb, we mark this as extern inline extern inline struct FuncsModuleState *FuncsState(void) { return (struct FuncsModuleState *)StateSlotsAtOffset(FuncsStateOffset); diff --git a/src/gaptime.c b/src/gaptime.c index c0fe220192..affa0895ac 100644 --- a/src/gaptime.c +++ b/src/gaptime.c @@ -267,17 +267,17 @@ static Obj FuncNanosecondsSinceEpochInfo(Obj self) Obj res, tmp; Int8 resolution; const char * method = "unsupported"; - Int monotonic = 0; + BOOL monotonic = FALSE; #if defined(__APPLE__) && defined(__MACH__) method = "mach_absolute_time"; - monotonic = 1; + monotonic = TRUE; #elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) method = "clock_gettime"; - monotonic = 1; + monotonic = TRUE; #elif defined(HAVE_GETTIMEOFDAY) method = "gettimeofday"; - monotonic = 0; + monotonic = FALSE; #endif res = NEW_PREC(4); diff --git a/src/gvars.c b/src/gvars.c index 5232cd2d21..76d2746c9b 100644 --- a/src/gvars.c +++ b/src/gvars.c @@ -675,7 +675,7 @@ void MakeThreadLocalVar ( if (IS_INTOBJ(ExprGVar(gvar))) value = (Obj) 0; SET_ELM_GVAR_LIST( ExprGVars, gvar, INTOBJ_INT(rnam) ); - SetHasExprCopiesFopies(gvar, 1); + SetHasExprCopiesFopies(gvar, TRUE); CHANGED_GVAR_LIST( ExprGVars, gvar ); if (value && TLVars) SetTLDefault(TLVars, rnam, value); @@ -690,7 +690,7 @@ void MakeThreadLocalVar ( Obj FuncDeclareGlobalName(Obj self, Obj name) { RequireStringRep("DeclareGlobalName", name); - SetIsDeclaredName(GVarName(CONST_CSTR_STRING(name)), 1); + SetIsDeclaredName(GVarName(CONST_CSTR_STRING(name)), TRUE); return 0; } @@ -854,7 +854,7 @@ static Obj FuncAUTO(Obj self, Obj args) gvar = GVarName( CONST_CSTR_STRING(name) ); SET_ELM_GVAR_LIST( ValGVars, gvar, 0 ); SET_ELM_GVAR_LIST( ExprGVars, gvar, list ); - SetHasExprCopiesFopies(gvar, 1); + SetHasExprCopiesFopies(gvar, TRUE); CHANGED_GVAR_LIST( ExprGVars, gvar ); } @@ -1063,7 +1063,7 @@ static Obj FuncUNB_GVAR(Obj self, Obj gvar) */ typedef struct { Obj * copy; - UInt isFopy; + BOOL isFopy; const Char * name; } StructCopyGVar; @@ -1105,7 +1105,7 @@ void InitCopyGVar ( Panic("no room to record CopyGVar"); } CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy; - CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 0; + CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = FALSE; CopyAndFopyGVars[NCopyAndFopyGVars].name = name; NCopyAndFopyGVars++; #ifdef HPCGAP @@ -1142,7 +1142,7 @@ void InitFopyGVar ( Panic("no room to record FopyGVar"); } CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy; - CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 1; + CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = TRUE; CopyAndFopyGVars[NCopyAndFopyGVars].name = name; NCopyAndFopyGVars++; #ifdef HPCGAP @@ -1186,7 +1186,7 @@ void UpdateCopyFopyInfo ( void ) MakeBagPublic(cops); #endif SET_ELM_GVAR_LIST( FopiesGVars, gvar, cops ); - SetHasExprCopiesFopies(gvar, 1); + SetHasExprCopiesFopies(gvar, TRUE); CHANGED_GVAR_LIST( FopiesGVars, gvar ); } } @@ -1198,7 +1198,7 @@ void UpdateCopyFopyInfo ( void ) MakeBagPublic(cops); #endif SET_ELM_GVAR_LIST( CopiesGVars, gvar, cops ); - SetHasExprCopiesFopies(gvar, 1); + SetHasExprCopiesFopies(gvar, TRUE); CHANGED_GVAR_LIST( CopiesGVars, gvar ); } } diff --git a/src/io.c b/src/io.c index f17e34e606..9484c39a01 100644 --- a/src/io.c +++ b/src/io.c @@ -471,7 +471,7 @@ UInt CloseInput(TypInputFile * input) // if the input stream supports seeking, update its position to // reflect the actual state of things: we may have read and buffered // more bytes than we actually processed - int offset = strlen(input->ptr); + size_t offset = strlen(input->ptr); // check for EOF if (input->ptr[0] == '\377' && input->ptr[1] == '\0') offset = 0; diff --git a/src/lists.c b/src/lists.c index feb5c1584c..969d82573e 100644 --- a/src/lists.c +++ b/src/lists.c @@ -2415,7 +2415,7 @@ static Int CheckInit ( { Int i; // loop variable Int j; // loop variable - Int success = 1; + BOOL success = TRUE; Int fnums[] = { FN_IS_DENSE, FN_IS_NDENSE, FN_IS_HOMOG, FN_IS_NHOMOG, @@ -2453,7 +2453,7 @@ static Int CheckInit ( if ( ClearFiltsTNums[i] == 0 ) { Pr( "#W ClearFiltsListTNums [%s] missing\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } @@ -2464,7 +2464,7 @@ static Int CheckInit ( if ( HasFiltListTNums[i][fnums[j]] == -1 ) { Pr( "#W HasFiltListTNums [%s] [%s] missing\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; HasFiltListTNums[i][fnums[j]] = 0; } } @@ -2477,7 +2477,7 @@ static Int CheckInit ( if ( SetFiltListTNums[i][fnums[j]] == 0 ) { Pr( "#W SetFiltListTNums [%s] [%s] missing\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; } } } @@ -2489,7 +2489,7 @@ static Int CheckInit ( if ( ResetFiltListTNums[i][fnums[j]] == 0 ) { Pr( "#W ResetFiltListTNums [%s] [%s] missing\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; } } } @@ -2508,7 +2508,7 @@ static Int CheckInit ( Pr( "#W ResetFiltListTNums [%s] [%s] failed to reset\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; } } } @@ -2524,7 +2524,7 @@ static Int CheckInit ( Pr( "#W SetFiltListTNums [%s] [%s] must not change\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; } } } @@ -2537,7 +2537,7 @@ static Int CheckInit ( if ( ClearFiltsTNums[i]+IMMUTABLE != ClearFiltsTNums[i+IMMUTABLE]) { Pr( "#W ClearFiltsTNums [%s] mismatch between mutable and immutable\n", (Int)TNAM_TNUM(i), 0 ); - success = 0; + success = FALSE; } for ( j = 0; j < ARRAY_SIZE(fnums); j++ ) { @@ -2545,21 +2545,21 @@ static Int CheckInit ( HasFiltListTNums[i+IMMUTABLE][fnums[j]]) { Pr( "#W HasFiltListTNums [%s] [%s] mismatch between mutable and immutable\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; } if ( (SetFiltListTNums[i][fnums[j]] | IMMUTABLE) != SetFiltListTNums[i+IMMUTABLE][fnums[j]]) { Pr( "#W SetFiltListTNums [%s] [%s] mismatch between mutable and immutable\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; } if ( (ResetFiltListTNums[i][fnums[j]] | IMMUTABLE) != ResetFiltListTNums[i+IMMUTABLE][fnums[j]]) { Pr( "#W ResetFiltListTNums [%s] [%s] mismatch between mutable and immutable\n", (Int)TNAM_TNUM(i), (Int)fnams[j] ); - success = 0; + success = FALSE; } } @@ -2570,43 +2570,43 @@ static Int CheckInit ( Pr( "#W HasFiltListTNums [%s] [ empty -> dense ] missing\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( HasFiltListTNums[i][FN_IS_NDENSE] ) { Pr( "#W HasFiltListTNums [%s] [ empty + ndense ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( ! HasFiltListTNums[i][FN_IS_HOMOG] ) { Pr( "#W HasFiltListTNums [%s] [ empty -> homog ] missing\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( HasFiltListTNums[i][FN_IS_NHOMOG] ) { Pr( "#W HasFiltListTNums [%s] [ empty + nhomog ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( ! HasFiltListTNums[i][FN_IS_SSORT] ) { Pr( "#W HasFiltListTNums [%s] [ empty -> ssort ] missing\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( HasFiltListTNums[i][FN_IS_NSORT] ) { Pr( "#W HasFiltListTNums [%s] [ empty + nsort ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( HasFiltListTNums[i][FN_IS_TABLE] ) { Pr( "#W HasFiltListTNums [%s] [ empty + table ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } @@ -2615,7 +2615,7 @@ static Int CheckInit ( Pr( "#W HasFiltListTNums [%s] [ dense + ndense ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } @@ -2624,13 +2624,13 @@ static Int CheckInit ( Pr( "#W HasFiltListTNums [%s] [ ndense + homog ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( HasFiltListTNums[i][FN_IS_TABLE] ) { Pr( "#W HasFiltListTNums [%s] [ ndense + table ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } @@ -2639,19 +2639,19 @@ static Int CheckInit ( Pr( "#W HasFiltListTNums [%s] [ homog + nhomog ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( ! HasFiltListTNums[i][FN_IS_DENSE] ) { Pr( "#W HasFiltListTNums [%s] [ homog -> dense ] missing\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( HasFiltListTNums[i][FN_IS_NDENSE] ) { Pr( "#W HasFiltListTNums [%s] [ homog + ndense ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } @@ -2660,7 +2660,7 @@ static Int CheckInit ( Pr( "#W HasFiltListTNums [%s] [ nhomog + table ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } @@ -2669,13 +2669,13 @@ static Int CheckInit ( Pr( "#W HasFiltListTNums [%s] [ table -> homog ] missing\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } if ( ! HasFiltListTNums[i][FN_IS_DENSE] ) { Pr( "#W HasFiltListTNums [%s] [ table -> dense ] missing\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } @@ -2684,7 +2684,7 @@ static Int CheckInit ( Pr( "#W HasFiltListTNums [%s] [ ssort + nsort ] illegal\n", (Int)TNAM_TNUM(i), 0); - success = 0; + success = FALSE; } } } diff --git a/src/main.c b/src/main.c index 69d5e3dd95..0d1af37314 100644 --- a/src/main.c +++ b/src/main.c @@ -97,7 +97,6 @@ static void SetupGAPLocation(const char * argv0, char * GAPExecLocation) // In the code below, we keep resetting locBuf, as some of the methods we // try do not promise to leave the buffer empty on a failed return. char locBuf[GAP_PATH_MAX] = ""; - Int4 length = 0; #if defined(__APPLE__) && defined(__MACH__) uint32_t len = sizeof(locBuf); @@ -137,7 +136,7 @@ static void SetupGAPLocation(const char * argv0, char * GAPExecLocation) *GAPExecLocation = 0; // reset buffer after error // now strip the executable name off - length = strlen(GAPExecLocation); + size_t length = strlen(GAPExecLocation); while (length > 0 && GAPExecLocation[length] != '/') { GAPExecLocation[length] = 0; length--; diff --git a/src/objcftl.c b/src/objcftl.c index 472fd33772..83adcc9b13 100644 --- a/src/objcftl.c +++ b/src/objcftl.c @@ -44,6 +44,7 @@ struct CFTLModuleState { #ifdef HPCGAP }; +// for debugging from GDB / lldb, we mark this as extern inline extern inline struct CFTLModuleState *CFTLState(void) { return (struct CFTLModuleState *)StateSlotsAtOffset(CFTLStateOffset); diff --git a/src/objset.c b/src/objset.c index d72eaa22c3..1d404a5c8a 100644 --- a/src/objset.c +++ b/src/objset.c @@ -127,7 +127,7 @@ static inline void WRITE_SLOT(Obj container, int slot, Obj elm) static void PrintObjSet(Obj set) { UInt i, size = CONST_ADDR_WORD(set)[OBJSET_SIZE]; - Int comma = 0; + BOOL comma = FALSE; Pr("OBJ_SET([ ", 0, 0); for (i=0; i < size; i++) { Obj obj = READ_SLOT(set, i); @@ -135,7 +135,7 @@ static void PrintObjSet(Obj set) if (comma) { Pr(", ", 0, 0); } else { - comma = 1; + comma = TRUE; } PrintObj(obj); } @@ -146,7 +146,7 @@ static void PrintObjSet(Obj set) static void PrintObjMap(Obj map) { UInt i, size = CONST_ADDR_WORD(map)[OBJSET_SIZE]; - Int comma = 0; + BOOL comma = FALSE; Pr("OBJ_MAP([ ", 0, 0); for (i=0; i < size; i++) { Obj obj = READ_SLOT(map, i * 2); @@ -154,7 +154,7 @@ static void PrintObjMap(Obj map) if (comma) { Pr(", ", 0, 0); } else { - comma = 1; + comma = TRUE; } PrintObj(obj); Pr(", ", 0, 0); diff --git a/src/opers.cc b/src/opers.cc index ce86f7a99d..e2e431f8c9 100644 --- a/src/opers.cc +++ b/src/opers.cc @@ -755,7 +755,8 @@ static Obj FuncWITH_HIDDEN_IMPS_FLAGS(Obj self, Obj flags) #ifdef HPCGAP RegionWriteLock(REGION(WITH_HIDDEN_IMPS_FLAGS_CACHE)); #endif - Int changed, i, lastand, stop; + BOOL changed; + Int i, lastand, stop; Int hidden_imps_length = LEN_PLIST(HIDDEN_IMPS) / 2; Int hash = INT_INTOBJ(FuncHASH_FLAGS(0, flags)) % HIDDEN_IMPS_CACHE_LENGTH; @@ -777,18 +778,18 @@ static Obj FuncWITH_HIDDEN_IMPS_FLAGS(Obj self, Obj flags) #ifdef COUNT_OPERS WITH_HIDDEN_IMPS_MISS++; #endif - changed = 1; + changed = TRUE; lastand = 0; - while(changed) + while (changed) { - changed = 0; + changed = FALSE; for (i = hidden_imps_length, stop = lastand; i > stop; i--) { if( IS_SUBSET_FLAGS(with, ELM_PLIST(HIDDEN_IMPS, i*2)) && !IS_SUBSET_FLAGS(with, ELM_PLIST(HIDDEN_IMPS, i*2-1)) ) { with = FuncAND_FLAGS(0, with, ELM_PLIST(HIDDEN_IMPS, i*2-1)); - changed = 1; + changed = TRUE; stop = 0; lastand = i; } @@ -847,7 +848,8 @@ static Obj FuncWITH_IMPS_FLAGS(Obj self, Obj flags) #ifdef HPCGAP RegionWriteLock(REGION(IMPLICATIONS_SIMPLE)); #endif - Int changed, lastand, i, j, stop, imps_length; + BOOL changed; + Int lastand, i, j, stop, imps_length; Int hash = INT_INTOBJ(FuncHASH_FLAGS(0, flags)) % IMPS_CACHE_LENGTH; Obj cacheval; Obj with = flags; @@ -886,11 +888,11 @@ static Obj FuncWITH_IMPS_FLAGS(Obj self, Obj flags) // the other implications have to be considered in a loop imps_length = LEN_PLIST(IMPLICATIONS_COMPOSED); - changed = 1; + changed = TRUE; lastand = imps_length+1; while(changed) { - changed = 0; + changed = FALSE; for (i = 1, stop = lastand; i < stop; i++) { imp = ELM_PLIST(IMPLICATIONS_COMPOSED, i); @@ -898,7 +900,7 @@ static Obj FuncWITH_IMPS_FLAGS(Obj self, Obj flags) !IS_SUBSET_FLAGS(with, ELM_PLIST(imp, 1)) ) { with = FuncAND_FLAGS(0, with, ELM_PLIST(imp, 1)); - changed = 1; + changed = TRUE; stop = imps_length+1; lastand = i; } @@ -1607,7 +1609,6 @@ static UInt CacheMissStatistics[CACHE_SIZE + 1][7]; template static Obj GetMethodCached(Obj cacheBag, Int prec, Obj ids[]) { - UInt typematch; Obj * cache; Obj method = 0; UInt i; @@ -1625,11 +1626,11 @@ static Obj GetMethodCached(Obj cacheBag, Int prec, Obj ids[]) for (i = target; i < cacheEntrySize * CACHE_SIZE; i += cacheEntrySize) { if (cache[i + 1] == INTOBJ_INT(prec)) { - typematch = 1; + BOOL typematch = TRUE; // This loop runs over the arguments, should be compiled away for (int j = 0; j < n; j++) { if (cache[i + j + 2] != ids[j]) { - typematch = 0; + typematch = FALSE; break; } } diff --git a/src/permutat.cc b/src/permutat.cc index ccd5cfe976..7f7bb034a2 100644 --- a/src/permutat.cc +++ b/src/permutat.cc @@ -113,13 +113,12 @@ DECL_MODULE_STATE Obj TmpPerm; #endif -static UInt1 * UseTmpPerm(UInt size) +static void UseTmpPerm(UInt size) { if (TmpPerm == (Obj)0) TmpPerm = NewBag(T_PERM4, size); else if (SIZE_BAG(TmpPerm) < size) ResizeBag(TmpPerm, size); - return (UInt1 *)(ADDR_OBJ(TmpPerm) + 1); } template diff --git a/src/plist.c b/src/plist.c index c05f9b147a..a9b6d0f7e5 100644 --- a/src/plist.c +++ b/src/plist.c @@ -255,19 +255,19 @@ static Int KTNumPlist(Obj list, Obj * famfirst) // look at the first element elm = ELM_PLIST( list, 1 ); if ( elm == 0 ) { - isDense = 0; + isDense = FALSE; } #ifdef HPCGAP else if ( !CheckReadAccess(elm) ) { - isHom = 0; - areMut = 1; - isTable = 0; + isHom = FALSE; + areMut = TRUE; + isTable = FALSE; } #endif else if (TEST_OBJ_FLAG(elm, OBJ_FLAG_TESTING)) { - isHom = 0; + isHom = FALSE; areMut = IS_PLIST_MUTABLE(elm); - isTable = 0; + isTable = FALSE; } else { #ifdef HPCGAP @@ -285,20 +285,20 @@ static Int KTNumPlist(Obj list, Obj * famfirst) family = FAMILY_TYPE( typeObj ); ktnumFirst = 0; } - isHom = 1; + isHom = TRUE; areMut = IS_MUTABLE_OBJ(elm); // if entry is a homogeneous list this might be a table or list if (ktnumFirst >= T_PLIST_HOM) { - isTable = 1; - isRect = 1; + isTable = TRUE; + isRect = TRUE; len = LEN_PLIST(elm); } else if (ktnumFirst == 0 && IS_HOMOG_LIST(elm)) { - isTable = 1; + isTable = TRUE; // only handle small lists as rectangular if (IS_SMALL_LIST(elm)) { - isRect = 1; + isRect = TRUE; len = LEN_LIST(elm); } } @@ -319,45 +319,45 @@ static Int KTNumPlist(Obj list, Obj * famfirst) for ( ; isDense && (isHom || ! areMut) && i <= lenList; i++ ) { elm = ELM_PLIST( list, i ); if ( elm == 0 ) { - isDense = 0; + isDense = FALSE; } #ifdef HPCGAP else if ( !CheckReadAccess(elm) ) { - isHom = 0; - areMut = 1; - isTable = 0; - isRect = 0; + isHom = FALSE; + areMut = TRUE; + isTable = FALSE; + isRect = FALSE; } #endif else if (TEST_OBJ_FLAG(elm, OBJ_FLAG_TESTING)) { - isHom = 0; + isHom = FALSE; areMut = (areMut || IS_PLIST_MUTABLE(elm)); - isTable = 0; - isRect = 0; + isTable = FALSE; + isRect = FALSE; } else { if (isHom) { loopTypeObj = TYPE_OBJ(elm); if ( loopTypeObj != typeObj && FAMILY_TYPE(loopTypeObj) != family ) { - isHom = 0; - isTable = 0; - isRect = 0; + isHom = FALSE; + isTable = FALSE; + isRect = FALSE; } if ( isTable ) { // check IS_PLIST first, as it is much cheaper if (IS_PLIST(elm)) { if (isRect && LEN_PLIST(elm) != len) { - isRect = 0; + isRect = FALSE; } } else if (IS_SMALL_LIST(elm)) { if (isRect && LEN_LIST(elm) != len) { - isRect = 0; + isRect = FALSE; } } else { - isTable = 0; - isRect = 0; + isTable = FALSE; + isRect = FALSE; } } } @@ -367,13 +367,13 @@ static Int KTNumPlist(Obj list, Obj * famfirst) // if we know it is not dense if (knownNDense) - isDense = 0; + isDense = FALSE; // otherwise if we don't know that it IS dense else if (!knownDense) for ( ; isDense && i <= lenList; i++ ) { elm = ELM_PLIST( list, i ); if ( elm == 0 ) { - isDense = 0; + isDense = FALSE; } } @@ -403,13 +403,13 @@ static Int KTNumPlist(Obj list, Obj * famfirst) else if (IS_FFE(ELM_PLIST(list,1))) { FF fld = FLD_FFE(ELM_PLIST(list,1)); - UInt isFFE = 1; + BOOL isFFE = TRUE; for (i = 2; i <= lenList; i++) { x = ELM_PLIST(list,i); if (!IS_FFE(x) || FLD_FFE(x) != fld) { - isFFE = 0; + isFFE = FALSE; break; } } @@ -446,8 +446,8 @@ static Int KTNumHomPlist(Obj list) Obj elm, x; // one element of Int i; // loop variable Int res; // result - Int isSSort; // list is (known to be) SSorted - Int isNSort; // list is (known to be) non-sorted + BOOL isSSort; // list is (known to be) SSorted + BOOL isNSort; // list is (known to be) non-sorted #ifdef HPCGAP if (!CheckWriteAccess(list)) { @@ -486,13 +486,13 @@ static Int KTNumHomPlist(Obj list) if (IS_FFE(elm)) { FF fld = FLD_FFE(ELM_PLIST(list,1)); - UInt isFFE = 1; + BOOL isFFE = TRUE; for (i = 2; i <= lenList; i++) { x = ELM_PLIST(list,i); if (!IS_FFE(x) || FLD_FFE(x) != fld) { - isFFE = 0; + isFFE = FALSE; break; } } @@ -509,10 +509,10 @@ static Int KTNumHomPlist(Obj list) if (!HAS_FILT_LIST(list, FN_IS_TABLE )) { if ( IS_HOMOG_LIST(elm) ) { - isTable = 1; + isTable = TRUE; if (IS_PLIST(elm)) { - isRect = 1; + isRect = TRUE; len = LEN_PLIST(elm); } } @@ -528,7 +528,7 @@ static Int KTNumHomPlist(Obj list) } else { - isTable = 1; + isTable = TRUE; isRect = HAS_FILT_LIST(list, FN_IS_RECT); } if (isTable && !isRect) @@ -1961,10 +1961,10 @@ static BOOL IsSSortPlist(Obj list) Int lenList; Obj elm1; Obj elm2; - Int areMut; + BOOL areMut; Int i; Obj fam=0; // initialize to help compiler - Int isHom; + BOOL isHom; // get the length lenList = LEN_PLIST( list ); @@ -1987,10 +1987,10 @@ static BOOL IsSSortPlist(Obj list) if (!SyInitializing) { fam = FAMILY_OBJ(elm1); - isHom = 1; + isHom = TRUE; } else - isHom = 0; + isHom = FALSE; // loop over the other elements for ( i = 2; i <= lenList; i++ ) { @@ -2047,10 +2047,10 @@ static BOOL IsSSortPlistDense(Obj list) Int lenList; Obj elm1; Obj elm2; - Int areMut; + BOOL areMut; Int i; Obj fam=0; // initialize to help compiler - Int isHom; + BOOL isHom; // get the length lenList = LEN_PLIST( list ); @@ -2071,10 +2071,10 @@ static BOOL IsSSortPlistDense(Obj list) if (!SyInitializing) { fam = FAMILY_OBJ(elm1); - isHom = 1; + isHom = TRUE; } else - isHom = 0; + isHom = FALSE; // loop over the other elements for ( i = 2; i <= lenList; i++ ) { @@ -2453,7 +2453,7 @@ static Obj FuncIsRectangularTablePlist(Obj self, Obj plist) Obj len; UInt lenlist; UInt i; - UInt hasMut = 0; + BOOL hasMut = FALSE; Obj elm; assert(!HAS_FILT_LIST(plist, FN_IS_RECT)); diff --git a/src/profile.c b/src/profile.c index c6c193adaa..bfd26913cb 100644 --- a/src/profile.c +++ b/src/profile.c @@ -430,7 +430,7 @@ void InformProfilingThatThisIsAForkedGAP(void) char filenamecpy[GAP_PATH_MAX]; // Allow 20 characters to allow space for .%d.gz const int SUPPORTED_PATH_LEN = GAP_PATH_MAX - 20; - if(strlen(profileState.filename) > SUPPORTED_PATH_LEN) { + if (strlen(profileState.filename) > SUPPORTED_PATH_LEN) { Panic("Filename can be at most %d character when forking", SUPPORTED_PATH_LEN); } if (endsWithgz(profileState.filename)) { diff --git a/src/read.c b/src/read.c index 1c12349574..437302919e 100644 --- a/src/read.c +++ b/src/read.c @@ -319,7 +319,7 @@ GAP_STATIC_ASSERT(sizeof(LHSRef) <= 8, "LHSRef is too big"); /**************************************************************************** ** */ -static UInt EvalRef(ReaderState * rs, const LHSRef ref, Int needExpr) +static UInt EvalRef(ReaderState * rs, const LHSRef ref, BOOL needExpr) { TRY_IF_NO_ERROR { @@ -643,7 +643,7 @@ static void ReadReferenceModifiers(ReaderState * rs, TypSymbolSet follow) // read one or more selectors while (IS_IN(rs->s.Symbol, S_LPAREN | S_LBRACK | S_LBRACE | S_DOT)) { LHSRef ref = ReadSelector(rs, follow, level); - level = EvalRef(rs, ref, 1); + level = EvalRef(rs, ref, TRUE); } } @@ -864,13 +864,13 @@ static void ReadCallVarAss(ReaderState * rs, TypSymbolSet follow, Char mode) while (IS_IN(rs->s.Symbol, S_LPAREN | S_LBRACK | S_LBRACE | S_DOT)) { // so the prefix was a reference - UInt level = EvalRef(rs, ref, 1); + UInt level = EvalRef(rs, ref, TRUE); ref = ReadSelector(rs, follow, level); } // if we need a reference if (mode == 'r' || (mode == 'x' && rs->s.Symbol != S_ASSIGN)) { - Int needExpr = mode == 'r' || !IS_IN(rs->s.Symbol, S_SEMICOLON); + BOOL needExpr = mode == 'r' || !IS_IN(rs->s.Symbol, S_SEMICOLON); EvalRef(rs, ref, needExpr); } @@ -2065,7 +2065,7 @@ static void ReadFor(ReaderState * rs, TypSymbolSet follow) // volatile LHSRef ref = ReadVar(rs, follow); if (ref.type != R_INVALID) - EvalRef(rs, ref, 1); + EvalRef(rs, ref, TRUE); CheckUnboundGlobal(rs, ref); // 'in' diff --git a/src/records.c b/src/records.c index e19befec0d..76546db9c1 100644 --- a/src/records.c +++ b/src/records.c @@ -64,7 +64,7 @@ static void NewRNamCallback(SymbolTable * symtab, UInt id, Obj name) */ UInt RNamName(const Char * name) { - UInt len = strlen(name); + size_t len = strlen(name); if (len > 1023) { // Note: We can't pass 'name' here, as it might get moved by garbage collection ErrorQuit("Record names must consist of at most 1023 characters", 0, 0); diff --git a/src/scanner.c b/src/scanner.c index cc607b7582..37e642bb77 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -71,7 +71,7 @@ static void SyntaxErrorOrWarning(ScannerState * s, // error is reported, so the pretty-printed context would leak // a literal 0xFF byte to *errout* with no caret to anchor it. const char * line = GetInputLineBuffer(s->input); - const UInt len = strlen(line); + const size_t len = strlen(line); const int line_is_sentinel = (len == 0 || line[0] == '\377'); if (!line_is_sentinel) { if (line[len-1] != '\n') diff --git a/src/sortbase.h b/src/sortbase.h index 069c97672c..4dfd9afefc 100644 --- a/src/sortbase.h +++ b/src/sortbase.h @@ -164,11 +164,11 @@ static inline void PREFIXNAME(Sort3)(SORT_FUNC_ARGS, Int a, Int b, Int c) { * to be moved, and store the partition_point in the argument * partition_point */ -static inline Int PREFIXNAME(Partition)(SORT_FUNC_ARGS, Int start, Int end, +static inline BOOL PREFIXNAME(Partition)(SORT_FUNC_ARGS, Int start, Int end, Int *partition_point) { Int left = start; Int right = end; - Int first_pass = 1; + BOOL first_pass = TRUE; SORT_CREATE_LOCAL(pivot); PREFIXNAME(Sort3)(SORT_ARGS, start, start / 2 + end / 2, end); @@ -198,7 +198,7 @@ static inline Int PREFIXNAME(Partition)(SORT_FUNC_ARGS, Int start, Int end, *partition_point = left; return first_pass; } - first_pass = 0; + first_pass = FALSE; SWAP_INDICES(SORT_ARGS, left, right); left++; @@ -275,7 +275,8 @@ static void PREFIXNAME(CheckBadPivot)(SORT_FUNC_ARGS, Int start, Int end, Int pi static void PREFIXNAME(QuickSort)(SORT_FUNC_ARGS, Int start, Int end, Int depth) { - Int pivot, first_pass; + Int pivot; + BOOL first_pass; if (end - start < 24) { PREFIXNAME(Insertion)(SORT_ARGS, start, end); diff --git a/src/sysfiles.c b/src/sysfiles.c index c2cf83db00..b65033dbe1 100644 --- a/src/sysfiles.c +++ b/src/sysfiles.c @@ -250,7 +250,7 @@ Int4 SyGAPCRC( const Char * name ) UInt4 new; Int4 ch; Int fid; - Int seen_nl; + BOOL seen_nl; // the CRC of a non existing file is 0 fid = SyFopen(name, "r", TRUE); @@ -260,7 +260,7 @@ Int4 SyGAPCRC( const Char * name ) // read in the file byte by byte and compute the CRC crc = 0x12345678L; - seen_nl = 0; + seen_nl = FALSE; while ( (ch = SyGetch(fid) )!= EOF ) { if ( ch == '\377' || ch == '\n' || ch == '\r' ) @@ -269,10 +269,10 @@ Int4 SyGAPCRC( const Char * name ) if ( seen_nl ) continue; else - seen_nl = 1; + seen_nl = TRUE; } else - seen_nl = 0; + seen_nl = FALSE; old = (crc >> 8) & 0x00FFFFFFL; new = syCcitt32[ ( (UInt4)( crc ^ ch ) ) & 0xff ]; crc = old ^ new; @@ -321,14 +321,14 @@ static Obj FuncCrcString(Obj self, Obj str) UInt4 i, len; const Char *ptr; Int4 ch; - Int seen_nl; + BOOL seen_nl; RequireStringRep(SELF_NAME, str); ptr = CONST_CSTR_STRING(str); len = GET_LEN_STRING(str); crc = 0x12345678L; - seen_nl = 0; + seen_nl = FALSE; for (i = 0; i < len; i++) { ch = (Int4)(ptr[i]); if ( ch == '\377' || ch == '\n' || ch == '\r' ) @@ -337,10 +337,10 @@ static Obj FuncCrcString(Obj self, Obj str) if ( seen_nl ) continue; else - seen_nl = 1; + seen_nl = TRUE; } else - seen_nl = 0; + seen_nl = FALSE; old = (crc >> 8) & 0x00FFFFFFL; new = syCcitt32[ ( (UInt4)( crc ^ ch ) ) & 0xff ]; crc = old ^ new; @@ -981,7 +981,7 @@ static UInt syLastIntr; // time of the last interrupt #ifdef HAVE_LIBREADLINE -static Int doingReadline; +static BOOL doingReadline; #endif static void syAnswerIntr(int signr) @@ -1207,7 +1207,7 @@ void SyFputs ( const Char * line, Int fid ) { - UInt i; + size_t i; // if outputting to the terminal compute the cursor position and length if ( fid == 1 || fid == 3 ) { @@ -2089,9 +2089,9 @@ static Char * readlineFgets(Char * line, UInt length, Int fid, UInt block) rl_event_hook = (OnCharReadHookActiveCheck()) ? charreadhook_rl : 0; #endif // now do the real work - doingReadline = 1; + doingReadline = TRUE; rlres = readline(STATE(Prompt)); - doingReadline = 0; + doingReadline = FALSE; // we get a NULL pointer on EOF, say by pressing Ctr-d if (!rlres) { if (!SyCTRD) { diff --git a/src/sysstr.h b/src/sysstr.h index c9173e5c8e..72ed52e687 100644 --- a/src/sysstr.h +++ b/src/sysstr.h @@ -23,8 +23,8 @@ ** *F IsAlpha( ) . . . . . . . . . . . . . is a character a normal letter ** -** 'IsAlpha' returns 1 if its character argument is a character from the -** range 'a..zA..Z' and 0 otherwise. +** 'IsAlpha' returns TRUE if its character argument is a character from the +** range 'a..zA..Z' and FALSE otherwise. */ #define IsAlpha(ch) (isalpha((unsigned int)ch)) @@ -33,8 +33,8 @@ ** *F IsDigit( ) . . . . . . . . . . . . . . . . . is a character a digit ** -** 'IsDigit' returns 1 if its character argument is a digit from the range -** '0..9' and 0 otherwise. +** 'IsDigit' returns TRUE if its character argument is a digit from the +** range '0..9' and FALSE otherwise. */ #define IsDigit(ch) (isdigit((unsigned int)ch)) @@ -43,8 +43,9 @@ ** *F IsIdent( ) . . . . . . . . is a character valid in a GAP identifier ** -** 'IsIdent' returns 1 if its character argument can be used unquoted inside -** a GAP identifier, i.e., is in the range 'a..zA..Z0-9_@', and 0 otherwise. +** 'IsIdent' returns TRUE if its character argument can be used unquoted +** inside a GAP identifier, i.e., is in the range 'a..zA..Z0-9_@', and +** FALSE otherwise. */ EXPORT_INLINE BOOL IsIdent(char ch) { diff --git a/src/tietze.c b/src/tietze.c index d86049a0ea..fa2ced13fa 100644 --- a/src/tietze.c +++ b/src/tietze.c @@ -289,7 +289,7 @@ static Obj FuncTzReplaceGens(Obj self, Obj tietze) Int total; // total length of relators Int old, new; // generators or inverses Int leng, reduced; // relator lengths - Int altered; // flag + BOOL altered; // flag Int i, j; // loop variables // check the Tietze stack @@ -317,7 +317,7 @@ static Obj FuncTzReplaceGens(Obj self, Obj tietze) rel = ptRels[i]; pt2 = ptRel = ADDR_OBJ( rel ); leng = INT_INTOBJ( ptLens[i] ); - altered = 0; + altered = FALSE; // don't change a square relator defining a valid involution if (ELM_PLIST(flags, i) == INTOBJ_INT(3) && leng == 2 && @@ -336,16 +336,18 @@ static Obj FuncTzReplaceGens(Obj self, Obj tietze) new = INT_INTOBJ( ptInvs[-old] ); if ( ! new ) { - altered = 1; + altered = TRUE; continue; // loop over j } if ( pt2 > ptRel && *pt2 == ptInvs[new] ) { - altered = 1; + altered = TRUE; --pt2; } else { - if ( new != old ) { altered = 1; } + if ( new != old ) { + altered = TRUE; + } *++pt2 = INTOBJ_INT( new ); } } @@ -973,9 +975,8 @@ static Obj FuncTzSearchC(Obj self, Obj args) Int n, m; // subword lengths Int count; // number of altered relators Int i, j, jj, x, y; // loop variables - Int lasty; // flag - Int altered; // flag - Int equal; // flag + Int lasty; // previous value of y + BOOL altered; // flag // get and check arguments if ( ! IS_SMALL_LIST(args) || 4 < LEN_LIST(args) || LEN_LIST(args) < 3 ) { @@ -1036,7 +1037,7 @@ static Obj FuncTzSearchC(Obj self, Obj args) ErrorQuit(" must be false or true", 0, 0); } } - equal = ( equ == True ); + const BOOL equal = ( equ == True ); // Skip relators of inconvenient lengths or with inconvenient flags, // and return if the remaining range is empty @@ -1072,8 +1073,9 @@ static Obj FuncTzSearchC(Obj self, Obj args) inv = 109109 * inv; // initialize the hash table - for ( i = 0; i < 2048; i++ ) - ((UInt4 *)keys1)[i] = ((UInt4 *)keys2)[i] = ((UInt4 *)keys3)[i] = 0; + memset(keys1, 0, sizeof(keys1)); + memset(keys2, 0, sizeof(keys2)); + memset(keys3, 0, sizeof(keys3)); // loop over the Tietze relators, starting at position pos1 for ( y = pos1; y < numrels; ) { @@ -1130,7 +1132,7 @@ static Obj FuncTzSearchC(Obj self, Obj args) ylen = INT_INTOBJ( ptLens[y] ); yflag = INT_INTOBJ( ptFlags[y] ); ylen1 = ylen - 1; - altered = 0; + altered = FALSE; // Loop to the next relator, if the current relator is too short if ( y > lasty @@ -1238,7 +1240,7 @@ static Obj FuncTzSearchC(Obj self, Obj args) } ptFlags[y] = INTOBJ_INT( newflag ); - altered = 1; + altered = TRUE; ++count; break; // loop over i } @@ -1285,7 +1287,7 @@ static Obj FuncTzSearchC(Obj self, Obj args) ptFlags = ADDR_OBJ( flags); ptInvs = ADDR_OBJ( invs ) + (numgens + 1); - altered = 1; + altered = TRUE; ++count; --y; break; // loop over i @@ -1331,7 +1333,7 @@ static Obj FuncTzSearchC(Obj self, Obj args) } ptFlags[y] = INTOBJ_INT( newflag ); - altered = 1; + altered = TRUE; ++count; break; // loop over i } @@ -1378,7 +1380,7 @@ static Obj FuncTzSearchC(Obj self, Obj args) ptFlags = ADDR_OBJ( flags); ptInvs = ADDR_OBJ( invs ) + numgens + 1; - altered = 1; + altered = TRUE; ++count; --y; break; // loop over i diff --git a/src/trans.cc b/src/trans.cc index 891a858598..557e7b02a5 100644 --- a/src/trans.cc +++ b/src/trans.cc @@ -3865,7 +3865,8 @@ Obj OnSetsTrans(Obj set, Obj f) const UInt4 * ptf4; UInt deg; Obj * ptres, tmp, res; - UInt i, isint, k; + UInt i, k; + BOOL isInt; // copy the list into a mutable plist, which we will then modify in place res = PLAIN_LIST_COPY(set); @@ -3876,7 +3877,7 @@ Obj OnSetsTrans(Obj set, Obj f) ptf2 = CONST_ADDR_TRANS2(f); deg = DEG_TRANS2(f); // loop over the entries of the tuple - isint = 1; + isInt = TRUE; for (i = 1; i <= len; i++, ptres++) { tmp = *ptres; if (IS_POS_INTOBJ(tmp)) { @@ -3886,7 +3887,7 @@ Obj OnSetsTrans(Obj set, Obj f) } } else { - isint = 0; + isInt = FALSE; tmp = POW(tmp, f); ptres = ADDR_OBJ(res) + i; ptf2 = CONST_ADDR_TRANS2(f); @@ -3900,7 +3901,7 @@ Obj OnSetsTrans(Obj set, Obj f) deg = DEG_TRANS4(f); // loop over the entries of the tuple - isint = 1; + isInt = TRUE; for (i = 1; i <= len; i++, ptres++) { tmp = *ptres; if (IS_POS_INTOBJ(tmp)) { @@ -3910,7 +3911,7 @@ Obj OnSetsTrans(Obj set, Obj f) } } else { - isint = 0; + isInt = FALSE; tmp = POW(tmp, f); ptres = ADDR_OBJ(res) + i; ptf4 = CONST_ADDR_TRANS4(f); @@ -3921,7 +3922,7 @@ Obj OnSetsTrans(Obj set, Obj f) } // sort the result and remove dups - if (isint) { + if (isInt) { SortPlistByRawObj(res); REMOVE_DUPS_PLIST_INTOBJ(res); RetypeBagSM(res, T_PLIST_CYC_SSORT); diff --git a/src/weakptr.c b/src/weakptr.c index 8d27774971..f99e8bde37 100644 --- a/src/weakptr.c +++ b/src/weakptr.c @@ -279,7 +279,7 @@ static Obj FuncWeakPointerObj(Obj self, Obj list) static Int LengthWPObj(Obj wp) { - Int changed = 0; + BOOL changed = FALSE; Int len = STORED_LEN_WPOBJ(wp); #ifdef HPCGAP if (!CheckExclusiveWriteAccess(wp)) @@ -291,7 +291,7 @@ static Int LengthWPObj(Obj wp) elm = ELM_WPOBJ(wp, len); if (elm) break; - changed = 1; + changed = TRUE; len--; } if (changed) From d09727ac594dcd5136f6aefbea5425a1f7506302 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 6 Jun 2026 13:06:50 +0200 Subject: [PATCH 097/123] kernel: remove `ErrorReturnObj`, `C_NEW_STRING` (#6415) * kernel: remove ErrorReturnObj, C_NEW_STRING We don't use them nor any distributed package. * remove stuff which is now also dead --- lib/error.g | 16 ++-------------- lib/methsel2.g | 1 - src/error.c | 20 +++----------------- src/error.h | 7 ------- src/stringobj.h | 12 ------------ 5 files changed, 5 insertions(+), 51 deletions(-) diff --git a/lib/error.g b/lib/error.g index de03ee813f..dbf522412a 100644 --- a/lib/error.g +++ b/lib/error.g @@ -228,7 +228,7 @@ end); # Unbind(ErrorInner); BIND_GLOBAL("ErrorInner", function(options, earlyMessage) - local context, tracebackContext, mayReturnVoid, mayReturnObj, + local context, tracebackContext, mayReturnVoid, lateMessage, x, prompt, res, errorLVars, errorTracebackLVars, kernelErrorLVars, justQuit, printEarlyMessage, printEarlyTraceback, printAutomaticTraceback, lastErrorStream; @@ -262,17 +262,6 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) mayReturnVoid := false; fi; - if IsBound(options.mayReturnObj) then - mayReturnObj := options.mayReturnObj; - if not mayReturnObj in [false, true] then - PrintTo(ERROR_OUTPUT, "ErrorInner: option mayReturnObj must be true or false\n"); - LEAVE_ALL_NAMESPACES(); - JUMP_TO_CATCH(1); - fi; - else - mayReturnObj := false; - fi; - if IsBound(options.tracebackContext) then tracebackContext := options.tracebackContext; if not IsLVarsBag(tracebackContext) then @@ -410,7 +399,7 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) prompt := "brk> "; fi; if not justQuit then - res := SHELL(context,mayReturnVoid,mayReturnObj,true,prompt,false); + res := SHELL(context,mayReturnVoid,false,true,prompt,false); else res := fail; fi; @@ -455,7 +444,6 @@ BIND_GLOBAL("ErrorNoReturn", function(arg) rec( context := ParentLVars(GetCurrentLVars()), mayReturnVoid := false, - mayReturnObj := false, lateMessage := "type 'quit;' to quit to outer loop", ), arg); diff --git a/lib/methsel2.g b/lib/methsel2.g index 51700574ea..45a5f471b0 100644 --- a/lib/methsel2.g +++ b/lib/methsel2.g @@ -252,7 +252,6 @@ end; context := GetCurrentLVars(), tracebackContext := ParentLVars(GetCurrentLVars()), mayReturnVoid := false, - mayReturnObj := false, lateMessage := "type 'quit;' to quit to outer loop" ), [ no_method_found ]); diff --git a/src/error.c b/src/error.c index 2618e32739..64371589f2 100644 --- a/src/error.c +++ b/src/error.c @@ -422,7 +422,6 @@ static Obj CallErrorInner(const Char * msg, Int arg2, UInt justQuit, UInt mayReturnVoid, - UInt mayReturnObj, Obj lateMessage) { // Must do this before creating any other GAP objects, @@ -447,7 +446,6 @@ static Obj CallErrorInner(const Char * msg, #endif AssPRec(r, RNamName("context"), STATE(CurrLVars)); AssPRec(r, RNamName("justQuit"), justQuit ? True : False); - AssPRec(r, RNamName("mayReturnObj"), mayReturnObj ? True : False); AssPRec(r, RNamName("mayReturnVoid"), mayReturnVoid ? True : False); AssPRec(r, RNamName("lateMessage"), lateMessage); l = NewPlistFromArgs(EarlyMsg); @@ -469,7 +467,7 @@ static Obj CallErrorInner(const Char * msg, void ErrorQuit(const Char * msg, Int arg1, Int arg2) { - CallErrorInner(msg, arg1, arg2, 1, 0, 0, False); + CallErrorInner(msg, arg1, arg2, 1, 0, False); Panic("ErrorQuit must not return"); } @@ -496,18 +494,6 @@ void ErrorMayQuitNrAtLeastArgs(Int narg, Int actual) } -/**************************************************************************** -** -*F ErrorReturnObj( , , , ) . . print and return obj -*/ -Obj ErrorReturnObj(const Char * msg, Int arg1, Int arg2, const Char * msg2) -{ - Obj LateMsg; - LateMsg = MakeString(msg2); - return CallErrorInner(msg, arg1, arg2, 0, 0, 1, LateMsg); -} - - /**************************************************************************** ** *F ErrorReturnVoid( , , , ) . . . print and return @@ -516,7 +502,7 @@ void ErrorReturnVoid(const Char * msg, Int arg1, Int arg2, const Char * msg2) { Obj LateMsg; LateMsg = MakeString(msg2); - CallErrorInner(msg, arg1, arg2, 0, 1, 0, LateMsg); + CallErrorInner(msg, arg1, arg2, 0, 1, LateMsg); // ErrorMode( msg, arg1, arg2, (Obj)0, msg2, 'x' ); } @@ -527,7 +513,7 @@ void ErrorReturnVoid(const Char * msg, Int arg1, Int arg2, const Char * msg2) void ErrorMayQuit(const Char * msg, Int arg1, Int arg2) { Obj LateMsg = MakeString("type 'quit;' to quit to outer loop"); - CallErrorInner(msg, arg1, arg2, 0, 0, 0, LateMsg); + CallErrorInner(msg, arg1, arg2, 0, 0, LateMsg); Panic("ErrorMayQuit must not return"); } diff --git a/src/error.h b/src/error.h index 7915e12756..d0d8749d97 100644 --- a/src/error.h +++ b/src/error.h @@ -69,13 +69,6 @@ void ErrorMayQuitNrArgs(Int narg, Int actual) NORETURN; void ErrorMayQuitNrAtLeastArgs(Int narg, Int actual) NORETURN; -/**************************************************************************** -** -*F ErrorReturnObj( , , , ) . . print and return obj -*/ -Obj ErrorReturnObj(const Char * msg, Int arg1, Int arg2, const Char * msg2); - - /**************************************************************************** ** *F ErrorReturnVoid( , , , ) . . . print and return diff --git a/src/stringobj.h b/src/stringobj.h index 9b28f61107..4071c06365 100644 --- a/src/stringobj.h +++ b/src/stringobj.h @@ -358,18 +358,6 @@ EXPORT_INLINE Obj MakeImmStringWithLen(const char * buf, size_t len) } -/**************************************************************************** -** -*F C_NEW_STRING( , , ) . . . . . . create GAP string -** -** This macro is deprecated and only provided for backwards compatibility -** with some package kernel extensions. Use 'MakeStringWithLen' and -** 'MakeImmStringWithLen' instead. -*/ -#define C_NEW_STRING(string,len,cstr) \ - string = MakeStringWithLen( (cstr), (len) ) - - /**************************************************************************** ** *F AppendCStr( , , ) . . append data in a buffer to a string From dac42b31fd22a8b3b16a21464e0607daea0e02e8 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 6 Jun 2026 13:07:33 +0200 Subject: [PATCH 098/123] Fix ConjugateGroup for matrix groups not defined over a field (#6425) --- lib/grpmat.gi | 7 ++++++- tst/testbugfix/2026-06-05-ConjugateGroup.tst | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2026-06-05-ConjugateGroup.tst diff --git a/lib/grpmat.gi b/lib/grpmat.gi index 5766951a76..fa6128959f 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -1341,7 +1341,12 @@ InstallMethod( ConjugateGroup, ", ", IsCollsElms, if HasIsSubgroupSL( G ) then SetIsSubgroupSL( H, IsSubgroupSL( G ) ); fi; - F:= FieldOfMatrixList( [ g ] ); + + F:= DefaultScalarDomainOfMatrixList( [ g ] ); + if not IsField( F ) then + return H; + fi; + if HasInvariantBilinearForm( G ) then if not IsBound( ginv ) then ginv := g^-1; diff --git a/tst/testbugfix/2026-06-05-ConjugateGroup.tst b/tst/testbugfix/2026-06-05-ConjugateGroup.tst new file mode 100644 index 0000000000..bd8e9c0783 --- /dev/null +++ b/tst/testbugfix/2026-06-05-ConjugateGroup.tst @@ -0,0 +1,13 @@ +# Fix an unexpected error in ConjugateGroup when applied to +# a matrix group not over a field +# See https://github.com/gap-system/gap/issues/6423 +gap> G:=SL(2,Integers mod 4);; +gap> H:=ConjugateGroup(G,G.1);; +gap> G = H; +true + +# original test case +gap> S := SylowSubgroup(SL(2,Integers mod 4),2);; +gap> M := MaximalSubgroups(S);; +gap> Length(M); +3 From 8ec1478d291e544beffacca8051a5e22d3999f85 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 8 Jun 2026 11:15:49 +0200 Subject: [PATCH 099/123] kernel: improve `ErrorReturnVoid` break-loop message (#6416) ... and in general make its phrasing more consistent. Also update some several outdated sections of the documentation about break loops and error handling. Co-authored-by: Codex --- doc/ref/debug.xml | 18 ++++++++----- doc/ref/language.xml | 10 +++---- doc/ref/mloop.xml | 36 +++++++------------------ doc/ref/types.xml | 10 +++---- doc/tut/lists.xml | 9 +++---- lib/list.gd | 16 +++-------- src/cyclotom.c | 2 +- src/error.c | 15 ++++++----- src/funcs.c | 3 +-- src/hpc/thread.c | 2 +- src/stats.c | 20 +++++++------- src/streams.c | 18 +++++-------- src/vec8bit.c | 11 ++++---- src/vecgf2.c | 4 +-- tst/testspecial/mem-overflow.g.out | 3 ++- tst/testspecial/stack-depth-func.g.out | 6 +++-- tst/testspecial/stack-depth-func2.g.out | 6 +++-- tst/testspecial/stack-depth-rec.g.out | 6 +++-- 18 files changed, 86 insertions(+), 109 deletions(-) diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml index 7121efabd7..e947af8d05 100644 --- a/doc/ref/debug.xml +++ b/doc/ref/debug.xml @@ -923,7 +923,8 @@ Error, recursion depth trap (5000) [2] dive( depth - 1 ); @ *stdin*:1 ... at *stdin*:4 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> return; gap> dive(11000); Error, recursion depth trap (5000) @@ -932,7 +933,8 @@ Error, recursion depth trap (5000) [2] dive( depth - 1 ); @ *stdin*:1 ... at *stdin*:5 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> return; Error, recursion depth trap (10000) *[1] dive( depth - 1 ); @@ -940,8 +942,10 @@ Error, recursion depth trap (10000) [2] dive( depth - 1 ); @ *stdin*:1 ... at *stdin*:5 -you may 'return;' -brk> return;gap> +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue +brk> return; +gap> ]]>

@@ -981,7 +985,8 @@ Error, recursion depth trap (1000) [2] dive( depth - 1 ); @ *stdin*:4 ... at *stdin*:12 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> return; Error, recursion depth trap (2000) *[1] dive( depth - 1 ); @@ -989,7 +994,8 @@ Error, recursion depth trap (2000) [2] dive( depth - 1 ); @ *stdin*:4 ... at *stdin*:12 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> GetRecursionDepth(); 0 brk> return; diff --git a/doc/ref/language.xml b/doc/ref/language.xml index cab355969b..cce1a2fbfc 100644 --- a/doc/ref/language.xml +++ b/doc/ref/language.xml @@ -715,11 +715,10 @@ gap> xx := 15; 15 gap> MakeReadOnlyGlobal("xx"); gap> xx := 16; -Variable: 'xx' is read only -not in any function -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can 'return;' after making it writable to continue +Error, Variable: 'xx' is read only +Stack trace: +not in any function at *stdin*:3 +type 'quit;' to quit to outer loop brk> quit; gap> IsReadOnlyGlobal("xx"); true @@ -1563,6 +1562,7 @@ gap> f2:= function( x ) return f1( x ); end;; gap> f2( 4 ); value: 4 Error, Function Calls: must return a value +Stack trace: *[1] f1( x ) @ *stdin*:2 ( ) diff --git a/doc/ref/mloop.xml b/doc/ref/mloop.xml index b39f2f50e8..ee80492a0b 100644 --- a/doc/ref/mloop.xml +++ b/doc/ref/mloop.xml @@ -477,6 +477,7 @@ indicate that you are in a break loop. 1/0; Error, Rational operations: must not be zero +Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop ]]> @@ -487,7 +488,8 @@ If errors occur within a break loop &GAP; enters another break loop at a 1/0; Error, Rational operations: must not be zero -not in any function at *stdin*:2 +Stack trace: +not in any function at *errin*:1 type 'quit;' to quit to outer loop brk_2> ]]> @@ -537,25 +539,11 @@ purpose of this function. return return from break loop The other way to leave a break loop is to return from a break loop. -To do this you type return; or return obj;. If the break loop was entered because you interrupted &GAP;, then you can continue by typing return;. -If the break loop was entered due to an error, -you may have to modify the value of a variable before typing return; -(see the example for ) or you may have to -return an object obj -(by typing: return obj;) to continue the computation; -in any case, the message printed on entering the break loop will -tell you which of these alternatives is possible. -For example, if the break loop was entered because a variable had no -assigned value, the value to be returned is often a value that this -variable should have to continue the computation. -

- return 9; # we had tried to enter the divisor 9 but typed 0 ... -1/9 -gap> -]]> +If the break loop was entered due to an error, this option may or may not +be available, depending on the kind of error. The message printed on entering +the break loop will tell you whether this possible. @@ -581,7 +569,6 @@ function( ) ... end gap> Error("!\n"); Error, ! Hello -Entering break read-eval-print loop ... you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> quit; @@ -606,8 +593,7 @@ emitted at level 1

Note that for break loops entered by a call to , -the lines after Entering break read-eval-print loop ... -and before the brk> prompt can also be customised, +the lines just before the brk> prompt can also be customised, namely by redefining .

ErrorNoTraceBack @@ -649,7 +635,6 @@ Here is a somewhat trivial demonstration of the use of ErrorNoTraceBack("Gidday!", " How's", " it", " going?\n"); Error, Gidday! How's it going? -Entering break read-eval-print loop ... you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> quit; @@ -661,7 +646,6 @@ Now we call with the same arguments to show the difference. gap> Error("Gidday!", " How's", " it", " going?\n"); Error, Gidday! How's it going? Hello -Entering break read-eval-print loop ... you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> quit; @@ -685,9 +669,8 @@ gap> OnBreak := Where;; Break loop message When a break loop is entered by a call to -the message after the -Entering break read-eval-print loop ... line is produced -by the function OnBreakMessage, +the message at the end starting with you can 'quit;' to ... +is produced by the function OnBreakMessage, which just like is a user-configurable global variable that is a function with no arguments. @@ -718,7 +701,6 @@ calling as we did above, now produces: gap> Error("!\n"); Error, ! Hello -Entering break read-eval-print loop ... brk> quit; # to get back to outer loop ]]>

diff --git a/doc/ref/types.xml b/doc/ref/types.xml index 32ffe77b0c..b35730b539 100644 --- a/doc/ref/types.xml +++ b/doc/ref/types.xml @@ -601,12 +601,10 @@ for an object.

Setter( prop )( Rationals, false ); -You cannot set an "and-filter" except to true -not in any function -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can type 'return true;' to set all components true -(but you might really want to reset just one component) to continue +Error, You cannot set an "and-filter" except to true +Stack trace: +not in any function at *stdin*:8 +type 'quit;' to quit to outer loop brk> ]]> diff --git a/doc/tut/lists.xml b/doc/tut/lists.xml index d79908c21e..de893722ef 100644 --- a/doc/tut/lists.xml +++ b/doc/tut/lists.xml @@ -341,11 +341,10 @@ gap> list[3][5] := 'w';; list; copy; [ 1, 2, "threw", [ 4 ] ] [ 1, 2, "three", [ 4 ] ] gap> copy[3][5] := 'w'; -List Assignment: must be a mutable list -not in any function -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can 'return;' and ignore the assignment to continue +Error, List Assignment: must be a mutable list +Stack trace: +not in any function at *stdin*:3 +type 'quit;' to quit to outer loop brk> quit; ]]>

diff --git a/lib/list.gd b/lib/list.gd index 5a44805bae..f595715899 100644 --- a/lib/list.gd +++ b/lib/list.gd @@ -379,7 +379,7 @@ DeclareSynonym( "AsSSortedListList", AS_LIST_SORTED_LIST ); ## Lists with holes are sometimes convenient when the list represents ## a mapping from a finite, but not consecutive, ## subset of the positive integers. -## IsDenseList( [ 1, 2, 3 ] ); ## true ## gap> l := [ , 4, 9,, 25,, 49,,,, 121 ];; IsDenseList( l ); @@ -387,22 +387,12 @@ DeclareSynonym( "AsSSortedListList", AS_LIST_SORTED_LIST ); ## gap> l[3]; ## 9 ## gap> l[4]; -## List Element: [4] must have an assigned value -## not in any function -## Entering break read-eval-print loop ... -## you can 'quit;' to quit to outer loop, or -## you can 'return;' after assigning a value to continue -## brk> l[4] := 16;; # assigning a value -## brk> return; # to escape the break-loop -## 16 -## gap> -## ]]> +## Error, List Element: [4] must have an assigned value +## ]]> ##

## Observe that requesting the value of l[4], which was not ## assigned, caused the entry of a break-loop ## (see Section ). -## After assigning a value and typing return;, &GAP; is finally -## able to comply with our request (by responding with 16). ## ## ## <#/GAPDoc> diff --git a/src/cyclotom.c b/src/cyclotom.c index e626946916..9c56dde8e3 100644 --- a/src/cyclotom.c +++ b/src/cyclotom.c @@ -836,7 +836,7 @@ static UInt FindCommonField(UInt nl, UInt nr, UInt *ml, UInt *mr) "This computation requires a cyclotomic field of degree %d, larger " "than the current limit of %d", n, (Int)CyclotomicsLimit, - "You may return after raising the limit with SetCyclotomicsLimit"); + "you can 'return;' after raising the limit with SetCyclotomicsLimit"); } // Finish up diff --git a/src/error.c b/src/error.c index 64371589f2..b783458689 100644 --- a/src/error.c +++ b/src/error.c @@ -500,10 +500,13 @@ void ErrorMayQuitNrAtLeastArgs(Int narg, Int actual) */ void ErrorReturnVoid(const Char * msg, Int arg1, Int arg2, const Char * msg2) { - Obj LateMsg; - LateMsg = MakeString(msg2); - CallErrorInner(msg, arg1, arg2, 0, 1, LateMsg); - // ErrorMode( msg, arg1, arg2, (Obj)0, msg2, 'x' ); + if (msg2 == 0) { + msg2 = "you can 'return;' to continue"; + } + + Obj lateMsg = MakeString("you can 'quit;' to quit to outer loop, or\n"); + AppendString(lateMsg, MakeString(msg2)); + CallErrorInner(msg, arg1, arg2, 0, 1, lateMsg); } /**************************************************************************** @@ -634,7 +637,7 @@ void ErrorBoundedInt( void AssertionFailure(void) { - ErrorReturnVoid("Assertion failure", 0, 0, "you may 'return;'"); + ErrorReturnVoid("Assertion failure", 0, 0, 0); } void AssertionFailureWithMessage(Obj message) @@ -645,7 +648,7 @@ void AssertionFailureWithMessage(Obj message) AssertionFailure(); } else if (IS_STRING_REP(message)) { - ErrorReturnVoid("Assertion failure: %g", (Int)message, 0, "you may 'return;'"); + ErrorReturnVoid("Assertion failure: %g", (Int)message, 0, 0); } else { PrintObj(message); diff --git a/src/funcs.c b/src/funcs.c index 16acf1fb93..4d585e5bb2 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -387,8 +387,7 @@ void RecursionDepthTrap( void ) if (GetRecursionDepth() > 0) { recursionDepth = GetRecursionDepth(); SetRecursionDepth(0); - ErrorReturnVoid("recursion depth trap (%d)", (Int)recursionDepth, 0, - "you may 'return;'"); + ErrorReturnVoid("recursion depth trap (%d)", (Int)recursionDepth, 0, 0); SetRecursionDepth(recursionDepth); } } diff --git a/src/hpc/thread.c b/src/hpc/thread.c index 420074bf93..67f5219fda 100644 --- a/src/hpc/thread.c +++ b/src/hpc/thread.c @@ -975,7 +975,7 @@ static void InterruptCurrentThread(int locked, Stat stat) if (handler) CALL_WITH_CATCH(handler, NEW_PLIST(T_PLIST, 0)); else - ErrorReturnVoid("system interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("system interrupt", 0, 0, 0); if (!locked) pthread_mutex_unlock(thread->lock); } diff --git a/src/stats.c b/src/stats.c index fb2de23a1b..7ed53a74ce 100644 --- a/src/stats.c +++ b/src/stats.c @@ -392,7 +392,7 @@ static ALWAYS_INLINE ExecStatus ExecForHelper(Stat stat, UInt nr) #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) { - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); } #endif @@ -435,7 +435,7 @@ static ALWAYS_INLINE ExecStatus ExecForHelper(Stat stat, UInt nr) #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) { - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); } #endif @@ -530,7 +530,7 @@ static ALWAYS_INLINE ExecStatus ExecForRangeHelper(Stat stat, UInt nr) #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) { - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); } #endif @@ -666,7 +666,7 @@ static ALWAYS_INLINE ExecStatus ExecWhileHelper(Stat stat, UInt nr) #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) { - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); } #endif @@ -737,7 +737,7 @@ static ALWAYS_INLINE ExecStatus ExecRepeatHelper(Stat stat, UInt nr) #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) { - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); } #endif @@ -952,7 +952,7 @@ static ExecStatus ExecReturnObj(Stat stat) #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) { - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); } #endif @@ -980,7 +980,7 @@ static ExecStatus ExecReturnVoid(Stat stat) #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) { - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); } #endif @@ -1027,7 +1027,7 @@ UInt TakeInterrupt( void ) { if (HaveInterrupt()) { UnInterruptExecStat(); - ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'"); + ErrorReturnVoid("user interrupt", 0, 0, 0); return 1; } return 0; @@ -1067,12 +1067,12 @@ static ExecStatus ExecIntrStat(Stat stat) if (printError) { ErrorReturnVoid("reached the pre-set memory limit\n" "(change it with the -o command line option)", - 0, 0, "you can 'return;'"); + 0, 0, 0); } } else #endif - ErrorReturnVoid( "user interrupt", 0, 0, "you can 'return;'" ); + ErrorReturnVoid("user interrupt", 0, 0, 0); #endif // continue at the interrupted statement diff --git a/src/streams.c b/src/streams.c index d36d67eb46..4750f3dec2 100644 --- a/src/streams.c +++ b/src/streams.c @@ -517,8 +517,7 @@ static Obj FuncLOG_TO(Obj self, Obj filename) { RequireStringRep(SELF_NAME, filename); if ( ! OpenLog( CONST_CSTR_STRING(filename) ) ) { - ErrorReturnVoid("LogTo: cannot log to %g", (Int)filename, 0, - "you can 'return;'"); + ErrorReturnVoid("LogTo: cannot log to %g", (Int)filename, 0, 0); return False; } return True; @@ -533,8 +532,7 @@ static Obj FuncLOG_TO_STREAM(Obj self, Obj stream) { RequireOutputStream(SELF_NAME, stream); if ( ! OpenLogStream(stream) ) { - ErrorReturnVoid("LogTo: cannot log to stream", 0, 0, - "you can 'return;'"); + ErrorReturnVoid("LogTo: cannot log to stream", 0, 0, 0); return False; } return True; @@ -578,8 +576,7 @@ static Obj FuncINPUT_LOG_TO(Obj self, Obj filename) { RequireStringRep(SELF_NAME, filename); if ( ! OpenInputLog( CONST_CSTR_STRING(filename) ) ) { - ErrorReturnVoid("InputLogTo: cannot log to %g", (Int)filename, 0, - "you can 'return;'"); + ErrorReturnVoid("InputLogTo: cannot log to %g", (Int)filename, 0, 0); return False; } return True; @@ -594,8 +591,7 @@ static Obj FuncINPUT_LOG_TO_STREAM(Obj self, Obj stream) { RequireOutputStream(SELF_NAME, stream); if ( ! OpenInputLogStream(stream) ) { - ErrorReturnVoid("InputLogTo: cannot log to stream", 0, 0, - "you can 'return;'"); + ErrorReturnVoid("InputLogTo: cannot log to stream", 0, 0, 0); return False; } return True; @@ -639,8 +635,7 @@ static Obj FuncOUTPUT_LOG_TO(Obj self, Obj filename) { RequireStringRep(SELF_NAME, filename); if ( ! OpenOutputLog( CONST_CSTR_STRING(filename) ) ) { - ErrorReturnVoid("OutputLogTo: cannot log to %g", (Int)filename, 0, - "you can 'return;'"); + ErrorReturnVoid("OutputLogTo: cannot log to %g", (Int)filename, 0, 0); return False; } return True; @@ -655,8 +650,7 @@ static Obj FuncOUTPUT_LOG_TO_STREAM(Obj self, Obj stream) { RequireOutputStream(SELF_NAME, stream); if ( ! OpenOutputLogStream(stream) ) { - ErrorReturnVoid("OutputLogTo: cannot log to stream", 0, 0, - "you can 'return;'"); + ErrorReturnVoid("OutputLogTo: cannot log to stream", 0, 0, 0); return False; } return True; diff --git a/src/vec8bit.c b/src/vec8bit.c index 3b50507c67..1b583895a8 100644 --- a/src/vec8bit.c +++ b/src/vec8bit.c @@ -3002,7 +3002,7 @@ void ASS_VEC8BIT(Obj list, Obj pos, Obj elm) ErrorReturnVoid("List assignment would increase length of " "locked compressed vector", 0, 0, - "You can `return;' to ignore the assignment"); + "you can 'return;' to ignore the assignment"); return; } ResizeWordSizedBag(list, SIZE_VEC8BIT(p, elts)); @@ -3094,7 +3094,7 @@ static Obj FuncUNB_VEC8BIT(Obj self, Obj list, Obj pos) if (True == DoFilter(IsLockedRepresentationVector, list)) { ErrorReturnVoid( "Unbind of entry of locked compressed vector is forbidden", 0, 0, - "You can `return;' to ignore the assignment"); + "you can 'return;' to ignore the assignment"); return 0; } @@ -3220,7 +3220,7 @@ static Obj FuncAPPEND_VEC8BIT(Obj self, Obj vecl, Obj vecr) lenr = LEN_VEC8BIT(vecr); if (True == DoFilter(IsLockedRepresentationVector, vecl) && lenr > 0) { ErrorReturnVoid("Append to locked compressed vector is forbidden", 0, - 0, "You can `return;' to ignore the operation"); + 0, "you can 'return;' to ignore the operation"); return 0; } info = GetFieldInfo8Bit(FIELD_VEC8BIT(vecl)); @@ -4369,7 +4369,7 @@ static void ResizeVec8Bit(Obj vec, UInt newlen, UInt knownclean) if (True == DoFilter(IsLockedRepresentationVector, vec)) { ErrorReturnVoid("Resize of locked compressed vector is forbidden", 0, - 0, "You can `return;' to ignore the operation"); + 0, "you can 'return;' to ignore the operation"); return; } @@ -5002,8 +5002,7 @@ static Obj MakeShiftedVecs(Obj v, UInt len) ResizeVec8Bit(vn, len, 0); len1 = (len == 0) ? 0 : RightMostNonZeroVec8Bit(vn); if (len1 == 0) - ErrorReturnVoid("Zero coefficient vector for reduction", 0, 0, - "you can 'return;'"); + ErrorReturnVoid("Zero coefficient vector for reduction", 0, 0, 0); if (len1 != len) { ResizeVec8Bit(vn, len1, 1); len = len1; diff --git a/src/vecgf2.c b/src/vecgf2.c index b3c7454cb0..c484531c5f 100644 --- a/src/vecgf2.c +++ b/src/vecgf2.c @@ -3826,7 +3826,7 @@ FuncREDUCE_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2) if (len2a == 0) { ErrorReturnVoid("ReduceCoeffs: second argument must not be zero", 0, - 0, "you may 'return;' to skip the reduction"); + 0, "you can 'return;' to skip the reduction"); return 0; } @@ -3872,7 +3872,7 @@ FuncQUOTREM_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2) } if (len2a == 0) { ErrorReturnVoid("QuotremCoeffs: second argument must not be zero", 0, - 0, "you may 'return;' to skip the reduction"); + 0, "you can 'return;' to skip the reduction"); return 0; } diff --git a/tst/testspecial/mem-overflow.g.out b/tst/testspecial/mem-overflow.g.out index 82620ab76a..1f9147a44c 100644 --- a/tst/testspecial/mem-overflow.g.out +++ b/tst/testspecial/mem-overflow.g.out @@ -7,7 +7,8 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:3 -you can 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> # ... then we should be in a break loop. Exit that, perform some other computations. brk> quit; gap> Factorial(42); diff --git a/tst/testspecial/stack-depth-func.g.out b/tst/testspecial/stack-depth-func.g.out index 60ab11d2a3..37a8116566 100644 --- a/tst/testspecial/stack-depth-func.g.out +++ b/tst/testspecial/stack-depth-func.g.out @@ -14,7 +14,8 @@ Stack trace: [5] f( ); @ *stdin*:2 ... at *stdin*:3 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> return; # try once more Error, recursion depth trap (10000) Stack trace: @@ -29,5 +30,6 @@ Stack trace: [5] f( ); @ *stdin*:2 ... at *stdin*:3 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> QUIT; diff --git a/tst/testspecial/stack-depth-func2.g.out b/tst/testspecial/stack-depth-func2.g.out index 7027f3df17..d41cac1c18 100644 --- a/tst/testspecial/stack-depth-func2.g.out +++ b/tst/testspecial/stack-depth-func2.g.out @@ -14,7 +14,8 @@ Stack trace: [5] f( ) @ *stdin*:2 ... at *stdin*:3 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> return; # try once more Error, recursion depth trap (10000) Stack trace: @@ -29,5 +30,6 @@ Stack trace: [5] f( ) @ *stdin*:2 ... at *stdin*:3 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> QUIT; diff --git a/tst/testspecial/stack-depth-rec.g.out b/tst/testspecial/stack-depth-rec.g.out index af205e7582..3a2f0bcb5a 100644 --- a/tst/testspecial/stack-depth-rec.g.out +++ b/tst/testspecial/stack-depth-rec.g.out @@ -82,7 +82,8 @@ Stack trace: [5] String( record.(nam) ) @ GAPROOT/lib/record.gi:LINE ... at *stdin*:4 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> return; # try once more Error, recursion depth trap (5000) Stack trace: @@ -97,5 +98,6 @@ Stack trace: [5] String( record.(nam) ) @ GAPROOT/lib/record.gi:LINE ... at *stdin*:4 -you may 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> QUIT; From 6dedb2f8b4d1c617ea4aa3aa9ee97805876547a8 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 8 Jun 2026 12:10:32 +0200 Subject: [PATCH 100/123] kernel: refactor FuncPRINT_CURRENT_STATEMENT (#6424) Move part of the code from the kernel to the library. This will make future improvements easier. Co-authored-by: Codex --- lib/error.g | 13 ++++++++--- src/error.c | 42 ++++++++++++++-------------------- tst/testinstall/kernel/gap.tst | 2 +- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/lib/error.g b/lib/error.g index dbf522412a..2a942b4fec 100644 --- a/lib/error.g +++ b/lib/error.g @@ -135,7 +135,8 @@ BIND_GLOBAL("PRETTY_PRINT_VARS", function(context) end); BIND_GLOBAL("WHERE", function(depth, context, activecontext, showlocals) - local bottom, lastcontext, f, level, totaldepth, countcontext; + local bottom, lastcontext, f, level, totaldepth, countcontext, + prefixwidth, location; if depth <= 0 then return; fi; @@ -151,14 +152,20 @@ BIND_GLOBAL("WHERE", function(depth, context, activecontext, showlocals) totaldepth := totaldepth + 1; countcontext := ParentLVars(countcontext); od; + prefixwidth := Length(String(totaldepth)); level := 1; while depth > 0 and context <> bottom do - PRINT_CURRENT_STATEMENT( + location := PRINT_CURRENT_STATEMENT( ERROR_OUTPUT, context, activecontext, level, - totaldepth); + prefixwidth); + if location <> fail then + PrintTo(ERROR_OUTPUT, "\n", + ListWithIdenticalEntries(prefixwidth+2, ' '), + "@ ", location[1], ":", location[2]); + fi; if showlocals then PRETTY_PRINT_VARS(context); else diff --git a/src/error.c b/src/error.c index b783458689..b392cd4302 100644 --- a/src/error.c +++ b/src/error.c @@ -184,12 +184,17 @@ static Obj FuncCURRENT_STATEMENT_LOCATION(Obj self, Obj context) return retlist; } -static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, - Obj activeContext, Obj level, - Obj totalDepth) +static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, + Obj stream, + Obj context, + Obj activeContext, + Obj level, + Obj prefixWidth) { + volatile Obj location = Fail; + if (IsBottomLVars(context)) - return 0; + return Fail; // HACK: we want to redirect output // Try to print the output to stream. Use *errout* as a fallback. @@ -208,35 +213,26 @@ static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, BOOL rethrow = FALSE; GAP_TRY { - UInt levelInt = INT_INTOBJ(level); - UInt totalDepthInt = INT_INTOBJ(totalDepth); - UInt prefixWidth = 0; - UInt levelWidth = 0; - UInt i; - - char prefix[32]; Obj func = FUNC_LVARS(context); Obj funcname = NAME_FUNC(func); Int line = -1; - GAP_ASSERT(func); + Stat call = STAT_LVARS(context); Obj body = BODY_FUNC(func); Obj filename = GET_FILENAME_BODY(body); - while (totalDepthInt > 0) { - prefixWidth++; - totalDepthInt /= 10; - } - if (activeContext != Fail) { - i = levelInt; + char prefix[32]; + UInt levelInt = INT_INTOBJ(level); + UInt levelWidth = 0; + UInt i = levelInt; while (i > 0) { levelWidth++; i /= 10; } snprintf(prefix, sizeof(prefix), "%c%*s[%lu] ", context == activeContext ? '*' : ' ', - (int)(prefixWidth - levelWidth), "", + (int)(INT_INTOBJ(prefixWidth) - levelWidth), "", (unsigned long)levelInt); Pr("%s", (Int)prefix, 0); } @@ -274,11 +270,7 @@ static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, SWITCH_TO_OLD_LVARS(currLVars); } if (line > 0) { - Pr("\n", 0, 0); - for (i = 0; i < prefixWidth + 2; i++) { - Pr(" ", 0, 0); - } - Pr("@ %g:%d", (Int)filename, line); + location = NewPlistFromArgs(filename, INTOBJ_INT(line)); } } GAP_CATCH @@ -292,7 +284,7 @@ static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, if (rethrow) GAP_THROW(); - return 0; + return location; } /**************************************************************************** diff --git a/tst/testinstall/kernel/gap.tst b/tst/testinstall/kernel/gap.tst index 493afea431..ba82a4c3ca 100644 --- a/tst/testinstall/kernel/gap.tst +++ b/tst/testinstall/kernel/gap.tst @@ -112,9 +112,9 @@ fail gap> CURRENT_STATEMENT_LOCATION(GetCurrentLVars()); fail gap> PRINT_CURRENT_STATEMENT("*errout*", GetCurrentLVars(), fail, 1, 1); +fail gap> f:=function() local l; l:=GetCurrentLVars(); PRINT_CURRENT_STATEMENT("*errout*", l, fail, 1, 1); Print("\n"); end;; f(); PRINT_CURRENT_STATEMENT( "*errout*", l, fail, 1, 1 ); - @ stream:1 # gap> CALL_WITH_CATCH(fail,fail); From 78ce558612708f0a5511015f9612468034f57984 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 9 Jun 2026 01:07:41 +0200 Subject: [PATCH 101/123] Adjust when 'Stack trace:' message is printed (#6432) * Adjust when 'Stack trace:' message is printed * Update one more error message * Add two missing 'Stack trace:' --- doc/ref/debug.xml | 6 +++- doc/ref/language.xml | 1 - doc/ref/mloop.xml | 35 ++++++++++--------- doc/ref/types.xml | 1 - doc/tut/group.xml | 1 + doc/tut/lists.xml | 1 - doc/tut/migrat.xml | 31 ++++++++-------- lib/error.g | 4 +-- lib/integer.gd | 1 + lib/oper1.g | 1 + .../64bit/low-mem-list-types.g.out | 3 -- tst/testspecial/64bit/low-mem-plist-1.g.out | 2 -- tst/testspecial/64bit/low-mem-plist-2.g.out | 2 -- tst/testspecial/backtrace.g.out | 30 ++++++++++++++++ tst/testspecial/backtrace2.g.out | 21 +++++++++++ tst/testspecial/debug-var.g.out | 1 - .../error-in-InputTextString.g.out | 1 - tst/testspecial/last-access.g.out | 1 - tst/testspecial/line-continuation.g.out | 2 -- tst/testspecial/method-not-found-where.g.out | 1 + tst/testspecial/print-formatting.g.out | 1 - tst/testspecial/repl-syntax-err.g.out | 1 - tst/testspecial/stack-trace-depth.g.out | 2 ++ tst/testspecial/top-level-error.g.out | 1 - tst/testspecial/trace.g.out | 6 ---- tst/testspecial/up-down-env.g.out | 2 -- 26 files changed, 98 insertions(+), 61 deletions(-) diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml index e947af8d05..92f55cff95 100644 --- a/doc/ref/debug.xml +++ b/doc/ref/debug.xml @@ -42,7 +42,6 @@ error as in the following example occurs and a break loop is entered: gap> IsNormal(2,2); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `IsNormal' on 2 arguments -Stack trace: called from read-eval loop at *stdin*:1 type 'quit;' to quit to outer loop brk> @@ -918,6 +917,7 @@ gap> dive(100); gap> OnBreak:= function() Where(2); end;; # shorter traceback gap> dive(6000); Error, recursion depth trap (5000) +Stack trace: *[1] dive( depth - 1 ); @ *stdin*:1 [2] dive( depth - 1 ); @@ -928,6 +928,7 @@ you can 'return;' to continue brk> return; gap> dive(11000); Error, recursion depth trap (5000) +Stack trace: *[1] dive( depth - 1 ); @ *stdin*:1 [2] dive( depth - 1 ); @@ -937,6 +938,7 @@ you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> return; Error, recursion depth trap (10000) +Stack trace: *[1] dive( depth - 1 ); @ *stdin*:1 [2] dive( depth - 1 ); @@ -980,6 +982,7 @@ gap> dive(100); Depth 100 gap> dive(2500); Error, recursion depth trap (1000) +Stack trace: *[1] dive( depth - 1 ); @ *stdin*:4 [2] dive( depth - 1 ); @@ -989,6 +992,7 @@ you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> return; Error, recursion depth trap (2000) +Stack trace: *[1] dive( depth - 1 ); @ *stdin*:4 [2] dive( depth - 1 ); diff --git a/doc/ref/language.xml b/doc/ref/language.xml index cce1a2fbfc..b4fbfefcaa 100644 --- a/doc/ref/language.xml +++ b/doc/ref/language.xml @@ -716,7 +716,6 @@ gap> xx := 15; gap> MakeReadOnlyGlobal("xx"); gap> xx := 16; Error, Variable: 'xx' is read only -Stack trace: not in any function at *stdin*:3 type 'quit;' to quit to outer loop brk> quit; diff --git a/doc/ref/mloop.xml b/doc/ref/mloop.xml index ee80492a0b..a13c30e6c8 100644 --- a/doc/ref/mloop.xml +++ b/doc/ref/mloop.xml @@ -477,7 +477,6 @@ indicate that you are in a break loop. 1/0; Error, Rational operations: must not be zero -Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop ]]> @@ -488,7 +487,6 @@ If errors occur within a break loop &GAP; enters another break loop at a 1/0; Error, Rational operations: must not be zero -Stack trace: not in any function at *errin*:1 type 'quit;' to quit to outer loop brk_2> @@ -634,7 +632,8 @@ Here is a somewhat trivial demonstration of the use of

ErrorNoTraceBack("Gidday!", " How's", " it", " going?\n"); -Error, Gidday! How's it going? +Error, +Gidday! How's it going? you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> quit; @@ -752,7 +751,8 @@ Error, user interrupt @ GAPROOT/lib/stbc.gi:18 ( ) called from read-eval loop at *stdin*:2 -you can 'return;' +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue brk> Where(2); *[1] genlabels := Filtered( genlabels, function ( x ) return pnt ^ sgs[x] = pnt; @@ -828,14 +828,15 @@ Error, ! you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); +Stack trace: *[1] Error( "!\n" ); - @ *stdin*:4 + @ *stdin*:3 [2] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [3] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [4] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 ( ) called from read-eval loop at *errin*:1 brk> n; @@ -844,28 +845,30 @@ brk> DownEnv(); brk> n; 3 brk> Where(); +Stack trace: [1] Error( "!\n" ); - @ *stdin*:4 + @ *stdin*:3 *[2] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [3] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [4] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 ( ) called from read-eval loop at *errin*:5 brk> DownEnv( 2 ); brk> n; 1 brk> Where(); +Stack trace: [1] Error( "!\n" ); - @ *stdin*:4 + @ *stdin*:3 [2] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [3] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 *[4] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 ( ) called from read-eval loop at *errin*:8 brk> DownEnv( -2 ); diff --git a/doc/ref/types.xml b/doc/ref/types.xml index b35730b539..cc80d788a6 100644 --- a/doc/ref/types.xml +++ b/doc/ref/types.xml @@ -602,7 +602,6 @@ for an object. Setter( prop )( Rationals, false ); Error, You cannot set an "and-filter" except to true -Stack trace: not in any function at *stdin*:8 type 'quit;' to quit to outer loop brk> diff --git a/doc/tut/group.xml b/doc/tut/group.xml index 3d19ea2713..f8b1020368 100644 --- a/doc/tut/group.xml +++ b/doc/tut/group.xml @@ -928,6 +928,7 @@ gap> Size( Image( hom, DerivedSubgroup(s4) ) ); PreImage( hom, (1,2,3) ); Error, must be an injective and surjective mapping +Stack trace: *[1] ErrorNoReturn( " must be an injective and surjective ", "mapping" ); @ GAPROOT/lib/mapping.gi:262 ( ) diff --git a/doc/tut/lists.xml b/doc/tut/lists.xml index de893722ef..0361f480bb 100644 --- a/doc/tut/lists.xml +++ b/doc/tut/lists.xml @@ -342,7 +342,6 @@ gap> list[3][5] := 'w';; list; copy; [ 1, 2, "three", [ 4 ] ] gap> copy[3][5] := 'w'; Error, List Assignment: must be a mutable list -Stack trace: not in any function at *stdin*:3 type 'quit;' to quit to outer loop brk> quit; diff --git a/doc/tut/migrat.xml b/doc/tut/migrat.xml index bf73228ae0..13cdad7898 100644 --- a/doc/tut/migrat.xml +++ b/doc/tut/migrat.xml @@ -851,24 +851,23 @@ When interrupting, the first line printed by Where actually may be one level higher, as shown below.

OnBreak := function() Where(0); end;; # eliminate back-tracing on -gap> # entry to break loop +gap> OnBreak := function() end;; # eliminate back-tracing on entry to break loop gap> test:= function( n ) > if n > 3 then Error( "!\n" ); fi; test( n+1 ); end;; gap> test( 1 ); Error, ! -at *stdin*:6 you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); +Stack trace: *[1] Error( "!\n" ); - @ *stdin*:4 + @ *stdin*:3 [2] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [3] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [4] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 ( ) called from read-eval loop at *errin*:1 brk> n; @@ -877,28 +876,30 @@ brk> DownEnv(); brk> n; 3 brk> Where(); +Stack trace: [1] Error( "!\n" ); - @ *stdin*:4 + @ *stdin*:3 *[2] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [3] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [4] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 ( ) called from read-eval loop at *errin*:5 brk> DownEnv( 2 ); brk> n; 1 brk> Where(); +Stack trace: [1] Error( "!\n" ); - @ *stdin*:4 + @ *stdin*:3 [2] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 [3] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 *[4] test( n + 1 ); - @ *stdin*:4 + @ *stdin*:3 ( ) called from read-eval loop at *errin*:8 brk> DownEnv( -2 ); diff --git a/lib/error.g b/lib/error.g index 2a942b4fec..0daa77277a 100644 --- a/lib/error.g +++ b/lib/error.g @@ -145,6 +145,7 @@ BIND_GLOBAL("WHERE", function(depth, context, activecontext, showlocals) PrintTo(ERROR_OUTPUT, "called from read-eval loop "); return; fi; + PrintTo(ERROR_OUTPUT, "Stack trace:\n"); lastcontext := context; totaldepth := 0; countcontext := context; @@ -308,9 +309,6 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) printAutomaticTraceback := function() if IsBound(OnBreak) and IsFunction(OnBreak) then - if OnBreak = Where or OnBreak = WhereWithVars then - PrintTo(ERROR_OUTPUT, "Stack trace:\n"); - fi; OnBreak(); fi; end; diff --git a/lib/integer.gd b/lib/integer.gd index 20ca4e07ed..c2ae9c8ac8 100644 --- a/lib/integer.gd +++ b/lib/integer.gd @@ -249,6 +249,7 @@ DeclareGlobalFunction( "BestQuoInt" ); ## ChineseRem( [ 6, 10, 14 ], [ 1, 2, 3 ] ); ## Error, the residues must be equal modulo 2 +## Stack trace: ## *[1] Error( "the residues must be equal modulo ", g.gcd ); ## @ GAPROOT/lib/integer.gi:391 ## ( ) diff --git a/lib/oper1.g b/lib/oper1.g index 2c25bf1cff..1abc10d131 100644 --- a/lib/oper1.g +++ b/lib/oper1.g @@ -929,6 +929,7 @@ end); ## SylowSubgroup( s4, 6 ); ## Error, SylowSubgroup:

must be a prime +## Stack trace: ## *[1] <> ## @ GAPROOT/lib/oper1.g:964 ## [2] <> diff --git a/tst/testspecial/64bit/low-mem-list-types.g.out b/tst/testspecial/64bit/low-mem-list-types.g.out index 086225b90a..b8c7f74302 100644 --- a/tst/testspecial/64bit/low-mem-list-types.g.out +++ b/tst/testspecial/64bit/low-mem-list-types.g.out @@ -1,18 +1,15 @@ gap> ListWithIdenticalEntries(2^50, 'a'); Error, Cannot allocate 1125899906842633 bytes: cannot extend the workspace any more!! -Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> ListWithIdenticalEntries(2^50, true); Error, Cannot allocate 140737488355336 bytes: cannot extend the workspace any more!! -Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> ListWithIdenticalEntries(2^50, 2); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! -Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; diff --git a/tst/testspecial/64bit/low-mem-plist-1.g.out b/tst/testspecial/64bit/low-mem-plist-1.g.out index 9264df9d43..f3bdaee9b0 100644 --- a/tst/testspecial/64bit/low-mem-plist-1.g.out +++ b/tst/testspecial/64bit/low-mem-plist-1.g.out @@ -2,13 +2,11 @@ gap> l := []; [ ] gap> l[2^50] := 1; Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!!!! -Stack trace: not in any function at *stdin*:3 type 'quit;' to quit to outer loop brk> quit; gap> l[2^50] := 2; Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!!!! -Stack trace: not in any function at *stdin*:3 type 'quit;' to quit to outer loop brk> quit; diff --git a/tst/testspecial/64bit/low-mem-plist-2.g.out b/tst/testspecial/64bit/low-mem-plist-2.g.out index d50a3a7ab5..3d430e5bb8 100644 --- a/tst/testspecial/64bit/low-mem-plist-2.g.out +++ b/tst/testspecial/64bit/low-mem-plist-2.g.out @@ -1,12 +1,10 @@ gap> EmptyPlist(2^50); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! -Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> EmptyPlist(2^50); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! -Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; diff --git a/tst/testspecial/backtrace.g.out b/tst/testspecial/backtrace.g.out index f2130d7a95..c29cadf6fc 100644 --- a/tst/testspecial/backtrace.g.out +++ b/tst/testspecial/backtrace.g.out @@ -20,11 +20,13 @@ Stack trace: called from read-eval loop at *stdin*:13 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] l[[ 1 .. 3 ]] := 1; @ *stdin*:11 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] l[[ 1 .. 3 ]] := 1; @ *stdin*:11 arguments: @@ -45,11 +47,13 @@ Stack trace: called from read-eval loop at *stdin*:16 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] 1 / 0 @ *stdin*:15 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] 1 / 0 @ *stdin*:15 arguments: @@ -71,6 +75,7 @@ fi; called from read-eval loop at *stdin*:19 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] if x then return 1; fi; @@ -78,6 +83,7 @@ fi; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] if x then return 1; fi; @@ -102,6 +108,7 @@ fi; called from read-eval loop at *stdin*:22 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] if 1 then return 1; fi; @@ -109,6 +116,7 @@ fi; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] if 1 then return 1; fi; @@ -134,6 +142,7 @@ fi; called from read-eval loop at *stdin*:25 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] if 1 < 0 then return 1; elif 1 then @@ -143,6 +152,7 @@ fi; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] if 1 < 0 then return 1; elif 1 then @@ -168,6 +178,7 @@ od; called from read-eval loop at *stdin*:28 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] while 1 do return 1; od; @@ -175,6 +186,7 @@ od; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] while 1 do return 1; od; @@ -201,6 +213,7 @@ od; you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); +Stack trace: *[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); @ GAPROOT/lib/integer.gi:LINE [2] for i in 1 do @@ -210,6 +223,7 @@ od; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); @ GAPROOT/lib/integer.gi:LINE arguments: @@ -240,6 +254,7 @@ od; called from read-eval loop at *stdin*:34 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] for i in true do return 1; od; @@ -247,6 +262,7 @@ od; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] for i in true do return 1; od; @@ -271,6 +287,7 @@ od; called from read-eval loop at *stdin*:36 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] for i in true do return 1; od; @@ -278,6 +295,7 @@ od; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] for i in true do return 1; od; @@ -304,6 +322,7 @@ od; called from read-eval loop at *stdin*:38 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] for i in true do return 1; od; @@ -311,6 +330,7 @@ od; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] for i in true do return 1; od; @@ -337,6 +357,7 @@ od; called from read-eval loop at *stdin*:40 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] for i in true do return 1; od; @@ -344,6 +365,7 @@ od; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] for i in true do return 1; od; @@ -369,6 +391,7 @@ until 1; called from read-eval loop at *stdin*:42 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] repeat x := 1; until 1; @@ -376,6 +399,7 @@ until 1; ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] repeat x := 1; until 1; @@ -398,11 +422,13 @@ Stack trace: called from read-eval loop at *stdin*:45 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] Assert( 0, 1 ); @ *stdin*:44 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] Assert( 0, 1 ); @ *stdin*:44 arguments: @@ -423,11 +449,13 @@ Stack trace: called from read-eval loop at *stdin*:48 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] Assert( 0, 1, "hello" ); @ *stdin*:47 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] Assert( 0, 1, "hello" ); @ *stdin*:47 arguments: @@ -457,6 +485,7 @@ Stack trace: called from read-eval loop at *stdin*:56 type 'quit;' to quit to outer loop brk> Where(); +Stack trace: *[1] return m[i][j]; @ GAPROOT/lib/matrix.gi:LINE [2] ELM_LIST( m, row, col ) @@ -466,6 +495,7 @@ brk> Where(); ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +Stack trace: *[1] return m[i][j]; @ GAPROOT/lib/matrix.gi:LINE arguments: diff --git a/tst/testspecial/backtrace2.g.out b/tst/testspecial/backtrace2.g.out index 3583cc7588..51ade71f0c 100644 --- a/tst/testspecial/backtrace2.g.out +++ b/tst/testspecial/backtrace2.g.out @@ -39,6 +39,7 @@ you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> n; Where(); 3 +Stack trace: *[1] Error( "!\n" ); @ *stdin*:24 [2] test( n + 1 ); @@ -49,6 +50,7 @@ brk> n; Where(); called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 2 +Stack trace: [1] Error( "!\n" ); @ *stdin*:24 *[2] test( n + 1 ); @@ -59,6 +61,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 1 +Stack trace: [1] Error( "!\n" ); @ *stdin*:24 [2] test( n + 1 ); @@ -69,6 +72,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 +Stack trace: [1] Error( "!\n" ); @ *stdin*:24 [2] test( n + 1 ); @@ -79,6 +83,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 +Stack trace: [1] Error( "!\n" ); @ *stdin*:24 *[2] test( n + 1 ); @@ -89,6 +94,7 @@ brk> UpEnv(); n; Where(); called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 +Stack trace: *[1] Error( "!\n" ); @ *stdin*:24 [2] test( n + 1 ); @@ -99,6 +105,7 @@ brk> UpEnv(); n; Where(); called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 +Stack trace: *[1] Error( "!\n" ); @ *stdin*:24 [2] test( n + 1 ); @@ -133,6 +140,7 @@ Stack trace: type 'quit;' to quit to outer loop brk> n; Where(); 3 +Stack trace: *[1] 1 / 0 @ *stdin*:35 [2] test( n + 1 ); @@ -143,6 +151,7 @@ brk> n; Where(); called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 2 +Stack trace: [1] 1 / 0 @ *stdin*:35 *[2] test( n + 1 ); @@ -153,6 +162,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 1 +Stack trace: [1] 1 / 0 @ *stdin*:35 [2] test( n + 1 ); @@ -163,6 +173,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 +Stack trace: [1] 1 / 0 @ *stdin*:35 [2] test( n + 1 ); @@ -173,6 +184,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 +Stack trace: [1] 1 / 0 @ *stdin*:35 *[2] test( n + 1 ); @@ -183,6 +195,7 @@ brk> UpEnv(); n; Where(); called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 +Stack trace: *[1] 1 / 0 @ *stdin*:35 [2] test( n + 1 ); @@ -193,6 +206,7 @@ brk> UpEnv(); n; Where(); called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 +Stack trace: *[1] 1 / 0 @ *stdin*:35 [2] test( n + 1 ); @@ -229,6 +243,7 @@ Stack trace: type 'quit;' to quit to outer loop brk> n; Where(); 3 +Stack trace: *[1] IsAbelian( 1 ) @ *stdin*:47 [2] test( n + 1 ); @@ -239,6 +254,7 @@ brk> n; Where(); called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 3 +Stack trace: *[1] IsAbelian( 1 ) @ *stdin*:47 [2] test( n + 1 ); @@ -249,6 +265,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 2 +Stack trace: [1] IsAbelian( 1 ) @ *stdin*:47 *[2] test( n + 1 ); @@ -259,6 +276,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 +Stack trace: [1] IsAbelian( 1 ) @ *stdin*:47 [2] test( n + 1 ); @@ -269,6 +287,7 @@ brk> DownEnv(); n; Where(); called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 +Stack trace: [1] IsAbelian( 1 ) @ *stdin*:47 *[2] test( n + 1 ); @@ -279,6 +298,7 @@ brk> UpEnv(); n; Where(); called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 +Stack trace: *[1] IsAbelian( 1 ) @ *stdin*:47 [2] test( n + 1 ); @@ -289,6 +309,7 @@ brk> UpEnv(); n; Where(); called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 +Stack trace: *[1] IsAbelian( 1 ) @ *stdin*:47 [2] test( n + 1 ); diff --git a/tst/testspecial/debug-var.g.out b/tst/testspecial/debug-var.g.out index c39af18014..ab72b2459f 100644 --- a/tst/testspecial/debug-var.g.out +++ b/tst/testspecial/debug-var.g.out @@ -89,7 +89,6 @@ gap> x; 42 gap> y; Error, Variable: 'y' must have a value -Stack trace: not in any function at *stdin*:16 gap> gap> h:=function(p) diff --git a/tst/testspecial/error-in-InputTextString.g.out b/tst/testspecial/error-in-InputTextString.g.out index 18aca9b5f0..36b19d8b23 100644 --- a/tst/testspecial/error-in-InputTextString.g.out +++ b/tst/testspecial/error-in-InputTextString.g.out @@ -1,7 +1,6 @@ gap> Read(InputTextString("Print(1 + [()]);")); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `+' on 2 arguments -Stack trace: called from read-eval loop at stream:1 type 'quit;' to quit to outer loop brk> quit; diff --git a/tst/testspecial/last-access.g.out b/tst/testspecial/last-access.g.out index d958151341..78d756615f 100644 --- a/tst/testspecial/last-access.g.out +++ b/tst/testspecial/last-access.g.out @@ -5,7 +5,6 @@ gap> 1;2;3;[last,last2,last3]; [ 3, 2, 1 ] gap> Error("err"); Error, err -Stack trace: not in any function at *stdin*:3 you can 'quit;' to quit to outer loop, or you can 'return;' to continue diff --git a/tst/testspecial/line-continuation.g.out b/tst/testspecial/line-continuation.g.out index 88f253686c..2f06f33fdc 100644 --- a/tst/testspecial/line-continuation.g.out +++ b/tst/testspecial/line-continuation.g.out @@ -4,7 +4,6 @@ gap> # counter only once, so that both examples below report the error in line 2 gap> # gap> EvalString("123\\\n45x;"); Error, Variable: '12345x' must have a value -Stack trace: not in any function at stream:2 Error, Could not evaluate string. Stack trace: @@ -17,7 +16,6 @@ you can 'return;' to continue brk> quit; gap> EvalString("123\\\r\n45x;"); Error, Variable: '12345x' must have a value -Stack trace: not in any function at stream:2 Error, Could not evaluate string. Stack trace: diff --git a/tst/testspecial/method-not-found-where.g.out b/tst/testspecial/method-not-found-where.g.out index 30601cd166..eaaeaee161 100644 --- a/tst/testspecial/method-not-found-where.g.out +++ b/tst/testspecial/method-not-found-where.g.out @@ -13,6 +13,7 @@ brk> ShowMethods(1); #I Searching Method for IsDiagonalMatrix with 1 argument: #I Total: 3 entries brk> Where(5); +Stack trace: *[1] IsDiagonalMat( a ) @ *stdin*:3 ( ) diff --git a/tst/testspecial/print-formatting.g.out b/tst/testspecial/print-formatting.g.out index 984e623ac8..91e7af8741 100644 --- a/tst/testspecial/print-formatting.g.out +++ b/tst/testspecial/print-formatting.g.out @@ -22,7 +22,6 @@ gap> gap> # test formatting status for errout gap> 1/0; # trigger a break loop Error, Rational operations: must not be zero -Stack trace: not in any function at *stdin*:14 type 'quit;' to quit to outer loop brk> old := PrintFormattingStatus("*errout*"); diff --git a/tst/testspecial/repl-syntax-err.g.out b/tst/testspecial/repl-syntax-err.g.out index 9b4f6bc090..7f31dd0233 100644 --- a/tst/testspecial/repl-syntax-err.g.out +++ b/tst/testspecial/repl-syntax-err.g.out @@ -7,7 +7,6 @@ gap> # error, which wasn't reported correctly before the above issues was gap> # fixed. gap> Error(""): Error, -Stack trace: not in any function at *stdin*:9 you can 'quit;' to quit to outer loop, or you can 'return;' to continue diff --git a/tst/testspecial/stack-trace-depth.g.out b/tst/testspecial/stack-trace-depth.g.out index 7a30baca80..9c12a52a9a 100644 --- a/tst/testspecial/stack-trace-depth.g.out +++ b/tst/testspecial/stack-trace-depth.g.out @@ -49,6 +49,7 @@ you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> SetUserPreference("WhereDepth", 12); brk> Where(); +Stack trace: * [1] Error( "foo" ); @ *stdin*:3 [2] f11( ) @@ -75,6 +76,7 @@ brk> Where(); called from read-eval loop at *errin*:2 brk> SetUserPreference("WhereDepth", 5); brk> Where(); +Stack trace: *[1] Error( "foo" ); @ *stdin*:3 [2] f11( ) diff --git a/tst/testspecial/top-level-error.g.out b/tst/testspecial/top-level-error.g.out index 9ed8d6c077..f27f9df6d9 100644 --- a/tst/testspecial/top-level-error.g.out +++ b/tst/testspecial/top-level-error.g.out @@ -1,6 +1,5 @@ gap> Error("foo"); Error, foo -Stack trace: not in any function at *stdin*:2 you can 'quit;' to quit to outer loop, or you can 'return;' to continue diff --git a/tst/testspecial/trace.g.out b/tst/testspecial/trace.g.out index 3467715778..844962b4d0 100644 --- a/tst/testspecial/trace.g.out +++ b/tst/testspecial/trace.g.out @@ -31,7 +31,6 @@ gap> o(1,2,3,4,5,6); [ 1, 2, 3, 4, 5, 6 ] gap> o(1,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument operations -Stack trace: not in any function at *stdin*:25 gap> gap> # with tracing @@ -59,7 +58,6 @@ gap> o(1,2,3,4,5,6); [ 1, 2, 3, 4, 5, 6 ] gap> o(1,2,3,4,5,6,7); Error, sorry: cannot yet have X argument operations -Stack trace: not in any function at *stdin*:36 gap> UntraceMethods( o ); # not (yet?) supported gap> @@ -80,7 +78,6 @@ gap> o(1,2,3,4,5,6); [ 1, 2, 3, 4, 5, 6 ] gap> o(1,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument operations -Stack trace: not in any function at *stdin*:47 gap> gap> # @@ -113,7 +110,6 @@ gap> o(IsInt,2,3,4,5,6); [ , 2, 3, 4, 5, 6 ] gap> o(IsInt,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument constructors -Stack trace: not in any function at *stdin*:70 gap> gap> # with tracing @@ -138,7 +134,6 @@ gap> o(IsInt,2,3,4,5,6); [ , 2, 3, 4, 5, 6 ] gap> o(IsInt,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument constructors -Stack trace: not in any function at *stdin*:80 gap> UntraceMethods( o ); gap> @@ -157,6 +152,5 @@ gap> o(IsInt,2,3,4,5,6); [ , 2, 3, 4, 5, 6 ] gap> o(IsInt,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument constructors -Stack trace: not in any function at *stdin*:90 gap> QUIT; diff --git a/tst/testspecial/up-down-env.g.out b/tst/testspecial/up-down-env.g.out index f27012aa67..93062e655b 100644 --- a/tst/testspecial/up-down-env.g.out +++ b/tst/testspecial/up-down-env.g.out @@ -55,7 +55,6 @@ brk> ## start a fresh execution context brk> ## brk> Read("top-level-error.g"); Error, foo -Stack trace: not in any function at top-level-error.g:1 you can 'quit;' to quit to outer loop, or you can 'return;' to continue @@ -63,7 +62,6 @@ brk_2> Where(20); not in any function at *errin*:1 brk_2> lvl; # since `Read` started a fresh execution context, we can't access lvl here Error, Variable: 'lvl' must have a value -Stack trace: not in any function at *errin*:2 brk_2> quit; brk> lvl; From 8e141664187a0e75e3a93df4519404d6bdd19b75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:14:45 +0200 Subject: [PATCH 102/123] build(deps): bump codecov/codecov-action from 6 to 7 (#6430) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6 to 7. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v6...v7) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 0159bdcfb8..e9937fed7f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -276,7 +276,7 @@ jobs: - name: "Gather coverage data" run: ${{ matrix.extra }} dev/ci-gather-coverage.sh - name: "Upload coverage data to Codecov" - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -288,7 +288,7 @@ jobs: steps: - name: "Send Codecov notifications" - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} run_command: send-notifications From 85effa8d066acb1b8ae5a0d3a67ba646e7d0acca Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 9 Jun 2026 02:38:24 +0200 Subject: [PATCH 103/123] Adjust conway polynomial error message (#6433) The 'return to continue' is redundant and potentially confusing. --- hpcgap/lib/ffeconway.gi | 2 +- lib/ffe.gd | 6 +++--- lib/ffeconway.gi | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hpcgap/lib/ffeconway.gi b/hpcgap/lib/ffeconway.gi index ff9d82145e..d148ad64f5 100644 --- a/hpcgap/lib/ffeconway.gi +++ b/hpcgap/lib/ffeconway.gi @@ -80,7 +80,7 @@ FFECONWAY.SetUpConwayStuff := function(p,d) if not IsCheapConwayPolynomial(p,d) then Error("Conway Polynomial ",p,"^",d, - " will need to computed and might be slow\n", "return to continue"); + " will need to be computed and might be slow"); fi; cp := CoefficientsOfUnivariatePolynomial(ConwayPolynomial(p,d)); diff --git a/lib/ffe.gd b/lib/ffe.gd index 3eeddef057..1bd089717a 100644 --- a/lib/ffe.gd +++ b/lib/ffe.gd @@ -118,9 +118,9 @@ ## ]]> ## Z(11,40); -## Error, Conway Polynomial 11^40 will need to computed and might be slow -## return to continue -## *[1] Error( "Conway Polynomial ", p, "^", d, " will need to computed and might be slow\n", "return to continue" ); +## Error, Conway Polynomial 11^40 will need to be computed and might be slow +## Stack trace: +## *[1] Error( "Conway Polynomial ", p, "^", d, " will need to be computed and might be slow" ); ## @ GAPROOT/lib/ffeconway.gi:81 ## [2] FFECONWAY.SetUpConwayStuff( p, d ); ## @ GAPROOT/lib/ffeconway.gi:140 diff --git a/lib/ffeconway.gi b/lib/ffeconway.gi index fd6f5b721d..04555686d4 100644 --- a/lib/ffeconway.gi +++ b/lib/ffeconway.gi @@ -78,7 +78,7 @@ FFECONWAY.SetUpConwayStuff := function(p,d) if not IsCheapConwayPolynomial(p,d) then Error("Conway Polynomial ",p,"^",d, - " will need to computed and might be slow\n", "return to continue"); + " will need to be computed and might be slow"); fi; cp := CoefficientsOfUnivariatePolynomial(ConwayPolynomial(p,d)); From 447f0931a09d008b7229bbc5ec9a57db7003d016 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 9 Jun 2026 02:43:58 +0200 Subject: [PATCH 104/123] Widen declaration for many matrix related functions (#6095) Also remove some now redundant methods. Before: gap> m:=RandomMat(256, 256, GF(1000000007));; gap> mat:=Matrix(IsZmodnZMatrixRep, GF(1000000007), m);; gap> RankMat(mat)=256; time; true 170 gap> DeterminantMat(mat); time; ZmodpZObj( 873487643, 1000000007 ) 23982 After: gap> m:=RandomMat(256, 256, GF(1000000007));; gap> mat:=Matrix(IsZmodnZMatrixRep, GF(1000000007), m);; gap> RankMat(mat)=256; time; true 161 gap> DeterminantMat(mat); time; ZmodpZObj( 873487643, 1000000007 ) 1949 --- lib/matobjnz.gi | 16 ------------ lib/matrix.gd | 68 ++++++++++++++++++++++++------------------------- lib/matrix.gi | 30 +++++++++++----------- 3 files changed, 49 insertions(+), 65 deletions(-) diff --git a/lib/matobjnz.gi b/lib/matobjnz.gi index c2edf17d3a..e2ac12cd69 100644 --- a/lib/matobjnz.gi +++ b/lib/matobjnz.gi @@ -1315,14 +1315,6 @@ InstallMethod( InverseSameMutability, "for a zmodnz matrix", return n; end ); -InstallMethod( RankMat, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], -function( m ) - m:=MutableCopyMatrix(m); - m:=SemiEchelonMatDestructive(m); - if m<>fail then m:=Length(m.vectors);fi; - return m; -end); - #InstallMethodWithRandomSource( Randomize, # "for a random source and a mutable zmodnz matrix", @@ -1451,14 +1443,6 @@ InstallMethod( CompatibleVector, "for a zmodnz matrix", return NewZeroVector(IsZmodnZVectorRep,BaseDomain(v),NumberRows(v)); end ); -InstallMethod( DeterminantMat, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], -function( a ) -local m; - m:=Size(BaseDomain(a)); - a:=List(a![ROWSPOS],x->x![ELSPOS]); - return ZmodnZObj(DeterminantMat(a),m); -end ); - # Minimal/Characteristic Polynomial stuff ############################################################################# diff --git a/lib/matrix.gd b/lib/matrix.gd index 4fe2262981..31ddbf47fb 100644 --- a/lib/matrix.gd +++ b/lib/matrix.gd @@ -296,7 +296,7 @@ DeclareSynonym( "DiagonalOfMat", DiagonalOfMatrix ); ## ## <#/GAPDoc> ## -DeclareAttribute( "BaseMat", IsMatrix ); +DeclareAttribute( "BaseMat", IsMatrixOrMatrixObj ); ############################################################################# ## @@ -323,7 +323,7 @@ DeclareAttribute( "BaseMat", IsMatrix ); ## ## <#/GAPDoc> ## -DeclareOperation( "BaseMatDestructive", [ IsMatrix ] ); +DeclareOperation( "BaseMatDestructive", [ IsMatrixOrMatrixObj ] ); ############################################################################# ## @@ -345,7 +345,7 @@ DeclareOperation( "BaseMatDestructive", [ IsMatrix ] ); ## ## <#/GAPDoc> ## -DeclareAttribute( "BaseOrthogonalSpaceMat", IsMatrix ); +DeclareAttribute( "BaseOrthogonalSpaceMat", IsMatrixOrMatrixObj ); ############################################################################# @@ -372,7 +372,7 @@ DeclareAttribute( "BaseOrthogonalSpaceMat", IsMatrix ); ## ## <#/GAPDoc> ## -DeclareAttribute( "DefaultFieldOfMatrix", IsMatrix ); +DeclareAttribute( "DefaultFieldOfMatrix", IsMatrixOrMatrixObj ); ############################################################################# @@ -396,7 +396,7 @@ DeclareAttribute( "DefaultFieldOfMatrix", IsMatrix ); ## ## <#/GAPDoc> ## -DeclareAttribute( "DepthOfUpperTriangularMatrix", IsMatrix ); +DeclareAttribute( "DepthOfUpperTriangularMatrix", IsMatrixOrMatrixObj ); ############################################################################# @@ -503,7 +503,7 @@ DeclareSynonym( "DeterminantMatDivFree", DeterminantMatrixDivFree ); ## ## <#/GAPDoc> ## -DeclareAttribute( "DimensionsMat", IsMatrix ); +DeclareAttribute( "DimensionsMat", IsMatrixOrMatrixObj ); ############################################################################# @@ -550,7 +550,7 @@ DeclareAttribute( "DimensionsMat", IsMatrix ); ## ## <#/GAPDoc> ## -DeclareOperation( "ElementaryDivisorsMat", [IsRing,IsMatrix] ); +DeclareOperation( "ElementaryDivisorsMat", [IsRing, IsMatrixOrMatrixObj] ); DeclareGlobalFunction( "ElementaryDivisorsMatDestructive" ); ############################################################################# @@ -623,7 +623,7 @@ DeclareGlobalFunction( "ElementaryDivisorsMatDestructive" ); ## ## <#/GAPDoc> ## -DeclareOperation( "ElementaryDivisorsTransformationsMat", [IsRing,IsMatrix] ); +DeclareOperation( "ElementaryDivisorsTransformationsMat", [IsRing, IsMatrixOrMatrixObj] ); DeclareGlobalFunction( "ElementaryDivisorsTransformationsMatDestructive" ); ############################################################################# @@ -640,7 +640,7 @@ DeclareGlobalFunction( "ElementaryDivisorsTransformationsMatDestructive" ); ## ## ## -DeclareOperation( "TriangulizedNullspaceMatNT", [ IsMatrix ] ); +DeclareOperation( "TriangulizedNullspaceMatNT", [ IsMatrixOrMatrixObj ] ); ############################################################################# @@ -666,8 +666,8 @@ DeclareOperation( "TriangulizedNullspaceMatNT", [ IsMatrix ] ); ## ## <#/GAPDoc> ## -DeclareAttribute( "NullspaceMat", IsMatrix ); -DeclareAttribute( "TriangulizedNullspaceMat", IsMatrix ); +DeclareAttribute( "NullspaceMat", IsMatrixOrMatrixObj ); +DeclareAttribute( "TriangulizedNullspaceMat", IsMatrixOrMatrixObj ); ############################################################################# @@ -706,8 +706,8 @@ DeclareAttribute( "TriangulizedNullspaceMat", IsMatrix ); ## ## <#/GAPDoc> ## -DeclareOperation( "NullspaceMatDestructive", [ IsMatrix and IsMutable] ); -DeclareOperation( "TriangulizedNullspaceMatDestructive", [ IsMatrix and IsMutable] ); +DeclareOperation( "NullspaceMatDestructive", [ IsMatrixOrMatrixObj and IsMutable] ); +DeclareOperation( "TriangulizedNullspaceMatDestructive", [ IsMatrixOrMatrixObj and IsMutable] ); ############################################################################# @@ -779,7 +779,7 @@ DeclareOperation( "Eigenvalues", [ IsRing, IsMatrixOrMatrixObj ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "Eigenspaces", [ IsRing, IsMatrix ] ); +DeclareOperation( "Eigenspaces", [ IsRing, IsMatrixOrMatrixObj ] ); ############################################################################# ## @@ -795,7 +795,7 @@ DeclareOperation( "Eigenspaces", [ IsRing, IsMatrix ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "Eigenvectors", [ IsRing, IsMatrix ] ); +DeclareOperation( "Eigenvectors", [ IsRing, IsMatrixOrMatrixObj ] ); ############################################################################# @@ -926,7 +926,7 @@ DeclareSynonymAttr( "RankMatDestructive", RankMatrixDestructive ); ## ## <#/GAPDoc> ## -DeclareAttribute( "SemiEchelonMat", IsMatrix ); +DeclareAttribute( "SemiEchelonMat", IsMatrixOrMatrixObj ); ############################################################################# ## @@ -950,7 +950,7 @@ DeclareAttribute( "SemiEchelonMat", IsMatrix ); ## ## <#/GAPDoc> ## -DeclareOperation( "SemiEchelonMatDestructive", [ IsMatrix and IsMutable] ); +DeclareOperation( "SemiEchelonMatDestructive", [ IsMatrixOrMatrixObj and IsMutable] ); ############################################################################# @@ -987,7 +987,7 @@ DeclareOperation( "SemiEchelonMatDestructive", [ IsMatrix and IsMutable] ); ## ## <#/GAPDoc> ## -DeclareAttribute( "SemiEchelonMatTransformation", IsMatrix ); +DeclareAttribute( "SemiEchelonMatTransformation", IsMatrixOrMatrixObj ); ############################################################################# ## @@ -1003,7 +1003,7 @@ DeclareAttribute( "SemiEchelonMatTransformation", IsMatrix ); ## ## DeclareOperation( "SemiEchelonMatTransformationDestructive", [ - IsMatrix and IsMutable ] ); + IsMatrixOrMatrixObj and IsMutable ] ); ############################################################################# @@ -1135,7 +1135,7 @@ DeclareSynonym( "MutableTransposedMat", TransposedMatMutable ); # needed? ## ## ## -DeclareOperation( "MutableTransposedMatDestructive", [IsMatrix and IsMutable] ); +DeclareOperation( "MutableTransposedMatDestructive", [IsMatrixOrMatrixObj and IsMutable] ); ############################################################################# @@ -1163,7 +1163,7 @@ DeclareOperation( "MutableTransposedMatDestructive", [IsMatrix and IsMutable] ); ## ## <#/GAPDoc> ## -DeclareOperation( "TransposedMatDestructive", [ IsMatrix ] ); +DeclareOperation( "TransposedMatDestructive", [ IsMatrixOrMatrixObj ] ); @@ -1186,7 +1186,7 @@ DeclareOperation( "TransposedMatDestructive", [ IsMatrix ] ); ## ## <#/GAPDoc> ## -DeclareProperty( "IsMonomialMatrix", IsMatrix ); +DeclareProperty( "IsMonomialMatrix", IsMatrixOrMatrixObj ); ############################################################################# @@ -1211,7 +1211,7 @@ DeclareProperty( "IsMonomialMatrix", IsMatrix ); ## ## <#/GAPDoc> ## -DeclareOperation( "InverseMatMod", [ IsMatrix, IsObject ] ); +DeclareOperation( "InverseMatMod", [ IsMatrixOrMatrixObj, IsObject ] ); ############################################################################# @@ -1246,11 +1246,11 @@ DeclareOperation( "KroneckerProduct", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ## ## ## -## Does thework for SolutionMat and SolutionMatDestructive. +## Does the work for SolutionMat and SolutionMatDestructive. ## ## ## -DeclareOperation( "SolutionMatNoCo", [ IsMatrix, IsRowVector ] ); +DeclareOperation( "SolutionMatNoCo", [ IsMatrixOrMatrixObj, IsRowVectorOrVectorObj ] ); ############################################################################# @@ -1268,7 +1268,7 @@ DeclareOperation( "SolutionMatNoCo", [ IsMatrix, IsRowVector ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "SolutionMat", [ IsMatrix, IsRowVector ] ); +DeclareOperation( "SolutionMat", [ IsMatrixOrMatrixObj, IsRowVectorOrVectorObj ] ); ############################################################################# ## @@ -1300,7 +1300,7 @@ DeclareOperation( "SolutionMat", [ IsMatrix, IsRowVector ] ); ## <#/GAPDoc> ## DeclareOperation( "SolutionMatDestructive", - [ IsMatrix and IsMutable, IsRowVector ] ); + [ IsMatrixOrMatrixObj and IsMutable, IsRowVectorOrVectorObj ] ); ############################################################################ @@ -1326,7 +1326,7 @@ DeclareOperation( "SolutionMatDestructive", ## ## <#/GAPDoc> ## -DeclareOperation( "SumIntersectionMat", [ IsMatrix, IsMatrix ] ); +DeclareOperation( "SumIntersectionMat", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ] ); @@ -1349,7 +1349,7 @@ DeclareOperation( "SumIntersectionMat", [ IsMatrix, IsMatrix ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "TriangulizedMat", [ IsMatrix ] ); +DeclareOperation( "TriangulizedMat", [ IsMatrixOrMatrixObj ] ); DeclareSynonym( "RREF", TriangulizedMat); ############################################################################# @@ -1380,7 +1380,7 @@ DeclareSynonym( "RREF", TriangulizedMat); ## ## <#/GAPDoc> ## -DeclareOperation( "TriangulizeMat", [ IsMatrix and IsMutable ] ); +DeclareOperation( "TriangulizeMat", [ IsMatrixOrMatrixObj and IsMutable ] ); ############################################################################# @@ -1574,7 +1574,7 @@ DeclareGlobalFunction( "BlownUpVector" ); ## ## <#/GAPDoc> ## -DeclareOperation( "DiagonalizeMat", [IsRing,IsMatrix and IsMutable] ); +DeclareOperation( "DiagonalizeMat", [IsRing, IsMatrixOrMatrixObj and IsMutable] ); ############################################################################# @@ -2199,7 +2199,7 @@ DeclareSynonymAttr( "TraceMat", TraceMatrix ); ## ## <#/GAPDoc> ## -DeclareAttribute( "JordanDecomposition", IsMatrix ); +DeclareAttribute( "JordanDecomposition", IsMatrixOrMatrixObj ); ############################################################################# @@ -2382,7 +2382,7 @@ DeclareOperation( "CharacteristicPolynomial", ## DeclareOperation("CharacteristicPolynomialMatrixNC", #IsField is not yet known - [IsRing,IsOrdinaryMatrix,IsPosInt]); + [IsRing,IsMatrixOrMatrixObj,IsPosInt]); ############################################################################# @@ -2400,7 +2400,7 @@ DeclareOperation("CharacteristicPolynomialMatrixNC", ## DeclareOperation("MinimalPolynomialMatrixNC", #IsField is not yet known - [IsRing,IsOrdinaryMatrix,IsPosInt]); + [IsRing,IsMatrixOrMatrixObj,IsPosInt]); ############################################################################# ## diff --git a/lib/matrix.gi b/lib/matrix.gi index 569d65c5b9..11b16fb563 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -805,7 +805,7 @@ InstallMethod( CharacteristicPolynomial, "spinning over field", fi; return false; end, - [ IsField, IsField, IsOrdinaryMatrix, IsPosInt ], + [ IsField, IsField, IsMatrixOrMatrixObj, IsPosInt ], function( F, E, mat, inum ) local B; @@ -824,7 +824,7 @@ InstallMethod( CharacteristicPolynomial, "spinning over field", InstallMethod( CharacteristicPolynomialMatrixNC, "spinning over field", IsElmsCollsX, - [ IsField, IsOrdinaryMatrix, IsPosInt ], + [ IsField, IsMatrixOrMatrixObj, IsPosInt ], Matrix_CharacteristicPolynomialSameField); InstallOtherMethod( CharacteristicPolynomial, @@ -868,7 +868,7 @@ InstallOtherMethod( CharacteristicPolynomialMatrixNC, InstallMethod( MinimalPolynomial, "spinning over field", IsElmsCollsX, - [ IsField, IsOrdinaryMatrix, IsPosInt ], + [ IsField, IsMatrixOrMatrixObj, IsPosInt ], function( F, mat,inum ) local fld, B; @@ -905,7 +905,7 @@ end); InstallMethod( MinimalPolynomialMatrixNC, "spinning over field", IsElmsCollsX, - [ IsField, IsOrdinaryMatrix, IsPosInt ], + [ IsField, IsMatrixOrMatrixObj, IsPosInt ], Matrix_MinimalPolynomialSameField); InstallOtherMethod( MinimalPolynomial, @@ -1597,7 +1597,7 @@ end); ## InstallMethod( DeterminantMatDestructive, "fraction-free method", - [ IsOrdinaryMatrix and IsMutable], + [ IsMatrixOrMatrixObj and IsMutable], function ( mat ) local det, sgn, row, zero, m, i, j, k, mult, row2, piv; @@ -1668,7 +1668,7 @@ end); ## through here also. ## InstallMethod( DeterminantMatDestructive,"non fraction free", - [ IsOrdinaryMatrix and IsFFECollColl and IsMutable], + [ IsMatrixOrMatrixObj and IsFFECollColl and IsMutable], function( mat ) local m, zero, det, sgn, k, j, row, l, row2, x; @@ -1743,7 +1743,7 @@ InstallMethod( DeterminantMat, end ); InstallMethod( DeterminantMatDestructive,"nonprime residue rings", - [ IsOrdinaryMatrix and + [ IsMatrixOrMatrixObj and CategoryCollections(CategoryCollections(IsZmodnZObjNonprime)) and IsMutable], DeterminantMatDivFree); @@ -1779,7 +1779,7 @@ InstallMethod( DeterminantMatDestructive,"nonprime residue rings", ## InstallMethod( DeterminantMatDivFree, "Division-free method", - [ IsMatrix ], + [ IsMatrixOrMatrixObj ], function ( M ) local u,v,w,i, ## indices a,b,c,x,y, ## temp indices @@ -2335,7 +2335,7 @@ end ); ## InstallMethod( NullspaceMat, "generic method for ordinary matrices", - [ IsOrdinaryMatrix ], + [ IsMatrixOrMatrixObj ], mat -> SemiEchelonMatTransformation(mat).relations ); InstallOtherMethod(NullspaceMat,"matrix objects",[IsMatrixObj], @@ -2356,7 +2356,7 @@ end); InstallMethod( NullspaceMatDestructive, "generic method for ordinary matrices", - [ IsOrdinaryMatrix and IsMutable], + [ IsMatrixOrMatrixObj and IsMutable], mat -> SemiEchelonMatTransformationDestructive(mat).relations ); InstallOtherMethod( TriangulizedNullspaceMat, @@ -2381,7 +2381,7 @@ end ); InstallMethod( TriangulizedNullspaceMatNT, "generic method", - [ IsOrdinaryMatrix ], + [ IsMatrixOrMatrixObj ], function( mat ) local nullspace, n, empty, i, k, row, zero, one;# @@ -2425,7 +2425,7 @@ InstallMethod( TriangulizedNullspaceMatNT, end ); #InstallMethod(TriangulizedNullspaceMat,"generic method", -# [IsOrdinaryMatrix], +# [IsMatrixOrMatrixObj], # function ( mat ) # # triangulize the transposed of the matrix # return TriangulizedNullspaceMatNT( @@ -2433,7 +2433,7 @@ end ); #end ); #InstallMethod(TriangulizedNullspaceMatDestructive,"generic method", -# [IsOrdinaryMatrix], +# [IsMatrixOrMatrixObj], # function ( mat ) # # triangulize the transposed of the matrix # return TriangulizedNullspaceMatNT( @@ -2545,7 +2545,7 @@ InstallOtherMethod( ProjectiveOrder, ## InstallOtherMethod( RankMatDestructive, "generic method for mutable matrices", - [ IsMatrix and IsMutable ], + [ IsMatrixOrMatrixObj and IsMutable ], function( mat ) mat:= SemiEchelonMatDestructive( mat ); if mat <> fail then @@ -2556,7 +2556,7 @@ InstallOtherMethod( RankMatDestructive, InstallOtherMethod( RankMat, "generic method for matrices", - [ IsMatrix ], + [ IsMatrixOrMatrixObj ], mat -> RankMatDestructive( MutableCopyMatrix( mat ) ) ); From 5b8275fdc05f4de1b69e270ad451b7da4af34605 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 10 Jun 2026 16:56:55 +0200 Subject: [PATCH 105/123] Further unify messages before break loop (#6434) * Align and clarify break loop instructions further * Adjust blocks to new late error msg * Regenerate tst/testspecial --- doc/ref/debug.xml | 22 ++++++------ doc/ref/language.xml | 4 +-- doc/ref/methsel.xml | 4 +-- doc/ref/mloop.xml | 34 +++++++++---------- doc/ref/types.xml | 2 +- doc/tut/group.xml | 2 +- doc/tut/lists.xml | 2 +- doc/tut/migrat.xml | 4 +-- doc/tut/opers.xml | 2 +- lib/error.g | 2 +- lib/ffe.gd | 4 +-- lib/grpfp.gd | 6 ++-- lib/grpfp.gi | 6 ++-- lib/init.g | 4 +-- lib/integer.gd | 4 +-- lib/integer.gi | 2 +- lib/methsel2.g | 2 +- lib/oper1.g | 4 +-- src/cyclotom.c | 2 +- src/error.c | 6 ++-- src/gaptime.c | 4 +-- src/vec8bit.c | 8 ++--- src/vecgf2.c | 4 +-- .../64bit/low-mem-list-types.g.out | 6 ++-- tst/testspecial/64bit/low-mem-plist-1.g.out | 4 +-- tst/testspecial/64bit/low-mem-plist-2.g.out | 4 +-- tst/testspecial/backtrace.g.out | 34 +++++++++---------- tst/testspecial/backtrace2.g.out | 8 ++--- tst/testspecial/bad-add.g.out | 2 +- tst/testspecial/bad-array-double-1.g.out | 2 +- tst/testspecial/bad-array-int-0.g.out | 2 +- tst/testspecial/bad-array-int-1.g.out | 2 +- tst/testspecial/bad-array-string.g.out | 2 +- tst/testspecial/bad-array-undef-0.g.out | 2 +- tst/testspecial/bad-array-undef-1.g.out | 2 +- tst/testspecial/bad-minus.g.out | 2 +- tst/testspecial/break-loop-loop.g.out | 4 +-- tst/testspecial/broken-test.g.out | 18 +++++----- .../bugfix-2019-09-27-LastPV.g.out | 2 +- tst/testspecial/current-env.g.out | 4 +-- tst/testspecial/debug-var.g.out | 16 ++++----- .../error-in-InputTextString.g.out | 2 +- .../func-and-proc-call-trace.g.out | 32 ++++++++--------- tst/testspecial/last-access.g.out | 4 +-- tst/testspecial/line-continuation.g.out | 8 ++--- tst/testspecial/mem-overflow.g.out | 4 +-- tst/testspecial/method-not-found-where.g.out | 2 +- tst/testspecial/method-not-found.g.out | 2 +- tst/testspecial/print-formatting.g.out | 2 +- tst/testspecial/repl-syntax-err.g.out | 4 +-- tst/testspecial/stack-depth-func.g.out | 8 ++--- tst/testspecial/stack-depth-func2.g.out | 8 ++--- tst/testspecial/stack-depth-rec.g.out | 8 ++--- tst/testspecial/stack-trace-depth.g.out | 4 +-- tst/testspecial/stack-trace-label.g.out | 4 +-- tst/testspecial/syntax-tree-error.g.out | 4 +-- tst/testspecial/top-level-error.g.out | 4 +-- tst/testspecial/up-down-env.g.out | 6 ++-- 58 files changed, 178 insertions(+), 178 deletions(-) diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml index 92f55cff95..5f5b77f9d7 100644 --- a/doc/ref/debug.xml +++ b/doc/ref/debug.xml @@ -43,7 +43,7 @@ gap> IsNormal(2,2); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `IsNormal' on 2 arguments called from read-eval loop at *stdin*:1 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> ]]>

@@ -923,8 +923,8 @@ Stack trace: [2] dive( depth - 1 ); @ *stdin*:1 ... at *stdin*:4 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> return; gap> dive(11000); Error, recursion depth trap (5000) @@ -934,8 +934,8 @@ Stack trace: [2] dive( depth - 1 ); @ *stdin*:1 ... at *stdin*:5 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> return; Error, recursion depth trap (10000) Stack trace: @@ -944,8 +944,8 @@ Stack trace: [2] dive( depth - 1 ); @ *stdin*:1 ... at *stdin*:5 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> return; gap> ]]> @@ -988,8 +988,8 @@ Stack trace: [2] dive( depth - 1 ); @ *stdin*:4 ... at *stdin*:12 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> return; Error, recursion depth trap (2000) Stack trace: @@ -998,8 +998,8 @@ Stack trace: [2] dive( depth - 1 ); @ *stdin*:4 ... at *stdin*:12 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> GetRecursionDepth(); 0 brk> return; diff --git a/doc/ref/language.xml b/doc/ref/language.xml index b4fbfefcaa..b0e03199ff 100644 --- a/doc/ref/language.xml +++ b/doc/ref/language.xml @@ -717,7 +717,7 @@ gap> MakeReadOnlyGlobal("xx"); gap> xx := 16; Error, Variable: 'xx' is read only not in any function at *stdin*:3 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> IsReadOnlyGlobal("xx"); true @@ -1566,7 +1566,7 @@ Stack trace: @ *stdin*:2 ( ) called from read-eval loop at *stdin*:3 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> ]]>

diff --git a/doc/ref/methsel.xml b/doc/ref/methsel.xml index 1ce2674710..5e88dabef2 100644 --- a/doc/ref/methsel.xml +++ b/doc/ref/methsel.xml @@ -127,13 +127,13 @@ gap> XCons(IsFullTransformationMonoid,4); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `XCons' on 2 arguments called from read-eval loop at *stdin*:8 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> XCons(IsNilpotentGroup,4); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `XCons' on 2 arguments called from read-eval loop at *stdin*:8 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> ]]> diff --git a/doc/ref/mloop.xml b/doc/ref/mloop.xml index a13c30e6c8..8b9aef83fa 100644 --- a/doc/ref/mloop.xml +++ b/doc/ref/mloop.xml @@ -478,7 +478,7 @@ indicate that you are in a break loop. gap> 1/0; Error, Rational operations: must not be zero not in any function at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop ]]>

If errors occur within a break loop &GAP; enters another break loop at a @@ -488,7 +488,7 @@ If errors occur within a break loop &GAP; enters another break loop at a brk> 1/0; Error, Rational operations: must not be zero not in any function at *errin*:1 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk_2> ]]>

@@ -567,8 +567,8 @@ function( ) ... end gap> Error("!\n"); Error, ! Hello -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> quit; ]]>

@@ -634,8 +634,8 @@ Here is a somewhat trivial demonstration of the use of gap> ErrorNoTraceBack("Gidday!", " How's", " it", " going?\n"); Error, Gidday! How's it going? -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> quit; ]]>

@@ -645,8 +645,8 @@ Now we call with the same arguments to show the difference. gap> Error("Gidday!", " How's", " it", " going?\n"); Error, Gidday! How's it going? Hello -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> quit; ]]>

@@ -668,7 +668,7 @@ gap> OnBreak := Where;; Break loop message When a break loop is entered by a call to -the message at the end starting with you can 'quit;' to ... +the message at the end starting with you can enter 'quit;' to ... is produced by the function OnBreakMessage, which just like is a user-configurable global variable @@ -676,8 +676,8 @@ that is a function with no arguments.

OnBreakMessage(); # By default, OnBreakMessage prints the following -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue ]]>

Perhaps you are familiar with what's possible in a break loop, and so @@ -751,8 +751,8 @@ Error, user interrupt @ GAPROOT/lib/stbc.gi:18 ( ) called from read-eval loop at *stdin*:2 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> Where(2); *[1] genlabels := Filtered( genlabels, function ( x ) return pnt ^ sgs[x] = pnt; @@ -825,8 +825,8 @@ gap> test:= function( n ) > if n > 3 then Error( "!\n" ); fi; test( n+1 ); end;; gap> test( 1 ); Error, ! -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> Where(); Stack trace: *[1] Error( "!\n" ); @@ -908,8 +908,8 @@ Stack trace: @ *stdin*:7 ( ) called from read-eval loop at *stdin*:8 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> x; 1 brk> DownEnv(1); diff --git a/doc/ref/types.xml b/doc/ref/types.xml index cc80d788a6..b49fe1ad2f 100644 --- a/doc/ref/types.xml +++ b/doc/ref/types.xml @@ -603,7 +603,7 @@ for an object. gap> Setter( prop )( Rationals, false ); Error, You cannot set an "and-filter" except to true not in any function at *stdin*:8 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> ]]> diff --git a/doc/tut/group.xml b/doc/tut/group.xml index f8b1020368..a47c55dec9 100644 --- a/doc/tut/group.xml +++ b/doc/tut/group.xml @@ -933,7 +933,7 @@ Stack trace: @ GAPROOT/lib/mapping.gi:262 ( ) called from read-eval loop at *stdin*:7 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; ]]>

diff --git a/doc/tut/lists.xml b/doc/tut/lists.xml index 0361f480bb..e2f8393cc6 100644 --- a/doc/tut/lists.xml +++ b/doc/tut/lists.xml @@ -343,7 +343,7 @@ gap> list[3][5] := 'w';; list; copy; gap> copy[3][5] := 'w'; Error, List Assignment: must be a mutable list not in any function at *stdin*:3 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; ]]>

diff --git a/doc/tut/migrat.xml b/doc/tut/migrat.xml index 13cdad7898..cf182c4fc2 100644 --- a/doc/tut/migrat.xml +++ b/doc/tut/migrat.xml @@ -856,8 +856,8 @@ gap> test:= function( n ) > if n > 3 then Error( "!\n" ); fi; test( n+1 ); end;; gap> test( 1 ); Error, ! -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> Where(); Stack trace: *[1] Error( "!\n" ); diff --git a/doc/tut/opers.xml b/doc/tut/opers.xml index 6413348e73..313bdc7faf 100644 --- a/doc/tut/opers.xml +++ b/doc/tut/opers.xml @@ -218,7 +218,7 @@ stops with an error message of the form Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `Size' on 1 arguments called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop ]]>

You would get an error message as above if you asked for Size( 1 ). diff --git a/lib/error.g b/lib/error.g index 0daa77277a..3a81bebffd 100644 --- a/lib/error.g +++ b/lib/error.g @@ -449,7 +449,7 @@ BIND_GLOBAL("ErrorNoReturn", function(arg) rec( context := ParentLVars(GetCurrentLVars()), mayReturnVoid := false, - lateMessage := "type 'quit;' to quit to outer loop", + lateMessage := "you can enter 'quit;' to quit to outer loop", ), arg); end); diff --git a/lib/ffe.gd b/lib/ffe.gd index 1bd089717a..aa93c7a24f 100644 --- a/lib/ffe.gd +++ b/lib/ffe.gd @@ -128,8 +128,8 @@ ## @ GAPROOT/lib/ffeconway.gi:167 ## ( ) ## called from read-eval loop at *stdin*:2 -## you can 'quit;' to quit to outer loop, or -## you can 'return;' to continue +## you can enter 'quit;' to quit to outer loop, or +## you can enter 'return;' to continue ## brk> ## ]]> ## diff --git a/lib/grpfp.gd b/lib/grpfp.gd index eaa41d6421..8e373a6ec3 100644 --- a/lib/grpfp.gd +++ b/lib/grpfp.gd @@ -90,9 +90,9 @@ fi; ## [5] CosetTableInWholeGroup( H ) ## @ GAPROOT/lib/grpfp.gi:1733 ## ... at *stdin*:3 -## type 'return;' if you want to continue with a new limit of 8192000 cosets, -## type 'quit;' if you want to quit the coset enumeration, -## type 'maxlimit := 0; return;' in order to continue without a limit +## you can enter 'return;' to continue with a new limit of 8192000 cosets, +## you can enter 'quit;' to abort the coset enumeration, +## you can enter 'maxlimit := 0; return;' in order to continue without a limit ## brk> quit; ## ]]> ##

diff --git a/lib/grpfp.gi b/lib/grpfp.gi index b9fd266b29..ceac830d16 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -1113,10 +1113,10 @@ BindGlobal("GTC_CosetTableFromGensAndRels",function(arg) # to give tidy instructions if one enters a break-loop SavedOnBreakMessage := OnBreakMessage; TCEOnBreakMessage := function(n) - Print( "type 'return;' if you want to continue with a new limit of ", + Print( "you can enter 'return;' to continue with a new limit of ", n, " cosets,\n", - "type 'quit;' if you want to quit the coset enumeration,\n", - "type 'maxlimit := 0; return;' in order to continue without a ", + "you can enter 'quit;' to abort the coset enumeration,\n", + "you can enter 'maxlimit := 0; return;' in order to continue without a ", "limit\n" ); OnBreakMessage := SavedOnBreakMessage; end; diff --git a/lib/init.g b/lib/init.g index 82c828d242..f6061f1e58 100644 --- a/lib/init.g +++ b/lib/init.g @@ -34,8 +34,8 @@ OnBreak := function() Print("An error has occurred before the traceback ", ## break loop. ## OnBreakMessage := function() - Print("you can 'quit;' to quit to outer loop, or\n", - "you can 'return;' to continue\n"); + Print("you can enter 'quit;' to quit to outer loop, or\n", + "you can enter 'return;' to continue\n"); end; ############################################################################# diff --git a/lib/integer.gd b/lib/integer.gd index c2ae9c8ac8..29be88cae8 100644 --- a/lib/integer.gd +++ b/lib/integer.gd @@ -254,8 +254,8 @@ DeclareGlobalFunction( "BestQuoInt" ); ## @ GAPROOT/lib/integer.gi:391 ## ( ) ## called from read-eval loop at *stdin*:2 -## you can 'quit;' to quit to outer loop, or -## you can 'return;' to continue +## you can enter 'quit;' to quit to outer loop, or +## you can enter 'return;' to continue ## brk> ## ]]> ## diff --git a/lib/integer.gi b/lib/integer.gi index b5da9421d7..9928ff6cb3 100644 --- a/lib/integer.gi +++ b/lib/integer.gi @@ -727,7 +727,7 @@ InstallGlobalFunction(FactorsInt,function ( n ) return Factors(n_orig); else Error( "sorry, cannot factor ", tmp[2], - "\ntype 'return;' to try again with a larger number of trials in\n", + "\nyou can enter 'return;' to try again with a larger number of trials in\n", "FactorsRho (or use option 'RhoTrials')\n"); if ValueOption("RhoTrials") <> fail then rt := 5 * ValueOption("RhoTrials"); diff --git a/lib/methsel2.g b/lib/methsel2.g index 45a5f471b0..a56b928f5a 100644 --- a/lib/methsel2.g +++ b/lib/methsel2.g @@ -252,7 +252,7 @@ end; context := GetCurrentLVars(), tracebackContext := ParentLVars(GetCurrentLVars()), mayReturnVoid := false, - lateMessage := "type 'quit;' to quit to outer loop" + lateMessage := "you can enter 'quit;' to quit to outer loop" ), [ no_method_found ]); end; diff --git a/lib/oper1.g b/lib/oper1.g index 1abc10d131..23550e1d7c 100644 --- a/lib/oper1.g +++ b/lib/oper1.g @@ -936,8 +936,8 @@ end); ## @ GAPROOT/lib/oper1.g:1007 ## ( ) ## called from read-eval loop at *stdin*:3 -## you can 'quit;' to quit to outer loop, or -## you can 'return;' to continue +## you can enter 'quit;' to quit to outer loop, or +## you can enter 'return;' to continue ## brk> quit; ## ]]> ##

diff --git a/src/cyclotom.c b/src/cyclotom.c index 9c56dde8e3..17b61a3c03 100644 --- a/src/cyclotom.c +++ b/src/cyclotom.c @@ -836,7 +836,7 @@ static UInt FindCommonField(UInt nl, UInt nr, UInt *ml, UInt *mr) "This computation requires a cyclotomic field of degree %d, larger " "than the current limit of %d", n, (Int)CyclotomicsLimit, - "you can 'return;' after raising the limit with SetCyclotomicsLimit"); + "you can enter 'return;' after raising the limit with SetCyclotomicsLimit"); } // Finish up diff --git a/src/error.c b/src/error.c index b392cd4302..325a661234 100644 --- a/src/error.c +++ b/src/error.c @@ -493,10 +493,10 @@ void ErrorMayQuitNrAtLeastArgs(Int narg, Int actual) void ErrorReturnVoid(const Char * msg, Int arg1, Int arg2, const Char * msg2) { if (msg2 == 0) { - msg2 = "you can 'return;' to continue"; + msg2 = "you can enter 'return;' to continue"; } - Obj lateMsg = MakeString("you can 'quit;' to quit to outer loop, or\n"); + Obj lateMsg = MakeString("you can enter 'quit;' to quit to outer loop, or\n"); AppendString(lateMsg, MakeString(msg2)); CallErrorInner(msg, arg1, arg2, 0, 1, lateMsg); } @@ -507,7 +507,7 @@ void ErrorReturnVoid(const Char * msg, Int arg1, Int arg2, const Char * msg2) */ void ErrorMayQuit(const Char * msg, Int arg1, Int arg2) { - Obj LateMsg = MakeString("type 'quit;' to quit to outer loop"); + Obj LateMsg = MakeString("you can enter 'quit;' to quit to outer loop"); CallErrorInner(msg, arg1, arg2, 0, 0, LateMsg); Panic("ErrorMayQuit must not return"); } diff --git a/src/gaptime.c b/src/gaptime.c index affa0895ac..4bc40fe55f 100644 --- a/src/gaptime.c +++ b/src/gaptime.c @@ -315,7 +315,7 @@ static Obj FuncSleep(Obj self, Obj secs) if (HaveInterrupt()) { ClearError(); // The interrupt may still be pending ErrorReturnVoid("user interrupt in sleep", 0, 0, - "you can 'return;' as if the sleep was finished"); + "you can enter 'return;' as if the sleep was finished"); } return 0; @@ -339,7 +339,7 @@ static Obj FuncMicroSleep(Obj self, Obj msecs) ClearError(); // The interrupt may still be pending ErrorReturnVoid( "user interrupt in microsleep", 0, 0, - "you can 'return;' as if the microsleep was finished"); + "you can enter 'return;' as if the microsleep was finished"); } return 0; diff --git a/src/vec8bit.c b/src/vec8bit.c index 1b583895a8..83f34e0657 100644 --- a/src/vec8bit.c +++ b/src/vec8bit.c @@ -3002,7 +3002,7 @@ void ASS_VEC8BIT(Obj list, Obj pos, Obj elm) ErrorReturnVoid("List assignment would increase length of " "locked compressed vector", 0, 0, - "you can 'return;' to ignore the assignment"); + "you can enter 'return;' to ignore the assignment"); return; } ResizeWordSizedBag(list, SIZE_VEC8BIT(p, elts)); @@ -3094,7 +3094,7 @@ static Obj FuncUNB_VEC8BIT(Obj self, Obj list, Obj pos) if (True == DoFilter(IsLockedRepresentationVector, list)) { ErrorReturnVoid( "Unbind of entry of locked compressed vector is forbidden", 0, 0, - "you can 'return;' to ignore the assignment"); + "you can enter 'return;' to ignore the assignment"); return 0; } @@ -3220,7 +3220,7 @@ static Obj FuncAPPEND_VEC8BIT(Obj self, Obj vecl, Obj vecr) lenr = LEN_VEC8BIT(vecr); if (True == DoFilter(IsLockedRepresentationVector, vecl) && lenr > 0) { ErrorReturnVoid("Append to locked compressed vector is forbidden", 0, - 0, "you can 'return;' to ignore the operation"); + 0, "you can enter 'return;' to ignore the operation"); return 0; } info = GetFieldInfo8Bit(FIELD_VEC8BIT(vecl)); @@ -4369,7 +4369,7 @@ static void ResizeVec8Bit(Obj vec, UInt newlen, UInt knownclean) if (True == DoFilter(IsLockedRepresentationVector, vec)) { ErrorReturnVoid("Resize of locked compressed vector is forbidden", 0, - 0, "you can 'return;' to ignore the operation"); + 0, "you can enter 'return;' to ignore the operation"); return; } diff --git a/src/vecgf2.c b/src/vecgf2.c index c484531c5f..d61c046c3a 100644 --- a/src/vecgf2.c +++ b/src/vecgf2.c @@ -3826,7 +3826,7 @@ FuncREDUCE_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2) if (len2a == 0) { ErrorReturnVoid("ReduceCoeffs: second argument must not be zero", 0, - 0, "you can 'return;' to skip the reduction"); + 0, "you can enter 'return;' to skip the reduction"); return 0; } @@ -3872,7 +3872,7 @@ FuncQUOTREM_COEFFS_GF2VEC(Obj self, Obj vec1, Obj len1, Obj vec2, Obj len2) } if (len2a == 0) { ErrorReturnVoid("QuotremCoeffs: second argument must not be zero", 0, - 0, "you can 'return;' to skip the reduction"); + 0, "you can enter 'return;' to skip the reduction"); return 0; } diff --git a/tst/testspecial/64bit/low-mem-list-types.g.out b/tst/testspecial/64bit/low-mem-list-types.g.out index b8c7f74302..87dff93393 100644 --- a/tst/testspecial/64bit/low-mem-list-types.g.out +++ b/tst/testspecial/64bit/low-mem-list-types.g.out @@ -1,16 +1,16 @@ gap> ListWithIdenticalEntries(2^50, 'a'); Error, Cannot allocate 1125899906842633 bytes: cannot extend the workspace any more!! not in any function at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> ListWithIdenticalEntries(2^50, true); Error, Cannot allocate 140737488355336 bytes: cannot extend the workspace any more!! not in any function at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> ListWithIdenticalEntries(2^50, 2); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! not in any function at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> quit; diff --git a/tst/testspecial/64bit/low-mem-plist-1.g.out b/tst/testspecial/64bit/low-mem-plist-1.g.out index f3bdaee9b0..921fd7e60e 100644 --- a/tst/testspecial/64bit/low-mem-plist-1.g.out +++ b/tst/testspecial/64bit/low-mem-plist-1.g.out @@ -3,12 +3,12 @@ gap> l := []; gap> l[2^50] := 1; Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!!!! not in any function at *stdin*:3 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> l[2^50] := 2; Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!!!! not in any function at *stdin*:3 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> l[3] := 3; 3 diff --git a/tst/testspecial/64bit/low-mem-plist-2.g.out b/tst/testspecial/64bit/low-mem-plist-2.g.out index 3d430e5bb8..757b353f3d 100644 --- a/tst/testspecial/64bit/low-mem-plist-2.g.out +++ b/tst/testspecial/64bit/low-mem-plist-2.g.out @@ -1,11 +1,11 @@ gap> EmptyPlist(2^50); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! not in any function at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> EmptyPlist(2^50); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! not in any function at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> quit; diff --git a/tst/testspecial/backtrace.g.out b/tst/testspecial/backtrace.g.out index c29cadf6fc..053849a831 100644 --- a/tst/testspecial/backtrace.g.out +++ b/tst/testspecial/backtrace.g.out @@ -18,7 +18,7 @@ Stack trace: @ *stdin*:11 ( ) called from read-eval loop at *stdin*:13 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] l[[ 1 .. 3 ]] := 1; @@ -45,7 +45,7 @@ Stack trace: @ *stdin*:15 ( ) called from read-eval loop at *stdin*:16 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] 1 / 0 @@ -73,7 +73,7 @@ fi; @ *stdin*:18 ( ) called from read-eval loop at *stdin*:19 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] if x then @@ -106,7 +106,7 @@ fi; @ *stdin*:21 ( ) called from read-eval loop at *stdin*:22 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] if 1 then @@ -140,7 +140,7 @@ fi; @ *stdin*:24 ( ) called from read-eval loop at *stdin*:25 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] if 1 < 0 then @@ -176,7 +176,7 @@ od; @ *stdin*:27 ( ) called from read-eval loop at *stdin*:28 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] while 1 do @@ -210,8 +210,8 @@ od; @ *stdin*:30 ( ) called from read-eval loop at *stdin*:31 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> Where(); Stack trace: *[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); @@ -252,7 +252,7 @@ od; @ *stdin*:33 ( ) called from read-eval loop at *stdin*:34 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] for i in true do @@ -285,7 +285,7 @@ od; @ *stdin*:35 ( ) called from read-eval loop at *stdin*:36 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] for i in true do @@ -320,7 +320,7 @@ od; @ *stdin*:37 ( ) called from read-eval loop at *stdin*:38 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] for i in true do @@ -355,7 +355,7 @@ od; @ *stdin*:39 ( ) called from read-eval loop at *stdin*:40 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] for i in true do @@ -389,7 +389,7 @@ until 1; @ *stdin*:41 ( ) called from read-eval loop at *stdin*:42 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] repeat @@ -420,7 +420,7 @@ Stack trace: @ *stdin*:44 ( ) called from read-eval loop at *stdin*:45 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] Assert( 0, 1 ); @@ -447,7 +447,7 @@ Stack trace: @ *stdin*:47 ( ) called from read-eval loop at *stdin*:48 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] Assert( 0, 1, "hello" ); @@ -483,7 +483,7 @@ Stack trace: @ *stdin*:55 ( ) called from read-eval loop at *stdin*:56 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> Where(); Stack trace: *[1] return m[i][j]; @@ -531,5 +531,5 @@ Stack trace: @ GAPROOT/lib/oper1.g:LINE ( ) called from read-eval loop at *stdin*:61 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/backtrace2.g.out b/tst/testspecial/backtrace2.g.out index 51ade71f0c..2633405b76 100644 --- a/tst/testspecial/backtrace2.g.out +++ b/tst/testspecial/backtrace2.g.out @@ -35,8 +35,8 @@ Stack trace: @ *stdin*:26 ( ) called from read-eval loop at *stdin*:28 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> n; Where(); 3 Stack trace: @@ -137,7 +137,7 @@ Stack trace: @ *stdin*:37 ( ) called from read-eval loop at *stdin*:39 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> n; Where(); 3 Stack trace: @@ -240,7 +240,7 @@ Stack trace: @ *stdin*:49 ( ) called from read-eval loop at *stdin*:51 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> n; Where(); 3 Stack trace: diff --git a/tst/testspecial/bad-add.g.out b/tst/testspecial/bad-add.g.out index 9259da66d3..0dcbbfff42 100644 --- a/tst/testspecial/bad-add.g.out +++ b/tst/testspecial/bad-add.g.out @@ -10,5 +10,5 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/bad-array-double-1.g.out b/tst/testspecial/bad-array-double-1.g.out index a68076d65a..05de996ca7 100644 --- a/tst/testspecial/bad-array-double-1.g.out +++ b/tst/testspecial/bad-array-double-1.g.out @@ -10,5 +10,5 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/bad-array-int-0.g.out b/tst/testspecial/bad-array-int-0.g.out index 17e703a17a..2a307b9437 100644 --- a/tst/testspecial/bad-array-int-0.g.out +++ b/tst/testspecial/bad-array-int-0.g.out @@ -12,5 +12,5 @@ Stack trace: @ *stdin*:5 ( ) called from read-eval loop at *stdin*:7 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/bad-array-int-1.g.out b/tst/testspecial/bad-array-int-1.g.out index cd7a87a095..ae359c3547 100644 --- a/tst/testspecial/bad-array-int-1.g.out +++ b/tst/testspecial/bad-array-int-1.g.out @@ -9,5 +9,5 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/bad-array-string.g.out b/tst/testspecial/bad-array-string.g.out index d0bd81ee20..34dd31bbd0 100644 --- a/tst/testspecial/bad-array-string.g.out +++ b/tst/testspecial/bad-array-string.g.out @@ -10,5 +10,5 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/bad-array-undef-0.g.out b/tst/testspecial/bad-array-undef-0.g.out index 5ea205de9a..8ce908cbd9 100644 --- a/tst/testspecial/bad-array-undef-0.g.out +++ b/tst/testspecial/bad-array-undef-0.g.out @@ -10,5 +10,5 @@ Stack trace: @ *stdin*:4 ( ) called from read-eval loop at *stdin*:6 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/bad-array-undef-1.g.out b/tst/testspecial/bad-array-undef-1.g.out index 7efcc85219..d172c4f20f 100644 --- a/tst/testspecial/bad-array-undef-1.g.out +++ b/tst/testspecial/bad-array-undef-1.g.out @@ -11,5 +11,5 @@ Stack trace: @ *stdin*:5 ( ) called from read-eval loop at *stdin*:7 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/bad-minus.g.out b/tst/testspecial/bad-minus.g.out index ec55c46e87..42a34245bd 100644 --- a/tst/testspecial/bad-minus.g.out +++ b/tst/testspecial/bad-minus.g.out @@ -14,5 +14,5 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> QUIT; diff --git a/tst/testspecial/break-loop-loop.g.out b/tst/testspecial/break-loop-loop.g.out index 4da0087abd..c1f24f4ce9 100644 --- a/tst/testspecial/break-loop-loop.g.out +++ b/tst/testspecial/break-loop-loop.g.out @@ -9,8 +9,8 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> x; 1 brk> y; diff --git a/tst/testspecial/broken-test.g.out b/tst/testspecial/broken-test.g.out index bbe429da39..f51326c8ce 100644 --- a/tst/testspecial/broken-test.g.out +++ b/tst/testspecial/broken-test.g.out @@ -9,7 +9,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-3.tst", rec(width := 800)); Error, Invalid test file at broken-test-3.tst:5 @@ -22,7 +22,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-4.tst", rec(width := 800)); Error, Invalid test file: Nested #@if at broken-test-4.tst:2 @@ -35,7 +35,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-5.tst", rec(width := 800)); Error, Invalid test file: two #@else at broken-test-5.tst:7 @@ -48,7 +48,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-6.tst", rec(width := 800)); Error, Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space at broken-test-6.tst:3 @@ -61,7 +61,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-7.tst", rec(width := 800)); Error, Invalid test file: #@elif after #@else at broken-test-7.tst:7 @@ -74,7 +74,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-8.tst", rec(width := 800)); Error, Invalid test file: #@elif without #@if at broken-test-8.tst:1 @@ -87,7 +87,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-9.tst", rec(width := 800)); Error, Invalid test file: Unterminated #@if at broken-test-9.tst:7 @@ -100,7 +100,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("invalidtestfile.tst", rec(width := 800)); Error, Invalid test file at invalidtestfile.tst:7 @@ -113,7 +113,7 @@ Stack trace: @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Test("empty.tst", rec(width := 800)); #I Test: File does not contain any tests! diff --git a/tst/testspecial/bugfix-2019-09-27-LastPV.g.out b/tst/testspecial/bugfix-2019-09-27-LastPV.g.out index bfb7f37450..c10ae80f68 100644 --- a/tst/testspecial/bugfix-2019-09-27-LastPV.g.out +++ b/tst/testspecial/bugfix-2019-09-27-LastPV.g.out @@ -7,7 +7,7 @@ gap> old_OnBreak:=OnBreak;; gap> OnBreak:=fail;; # prevent backtrace with line numbers that keep chaning gap> View([[badgroup]]); # <- trigger break loop Error, Rational operations: must not be zero -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; [ [ gap> OnBreak:=old_OnBreak;; diff --git a/tst/testspecial/current-env.g.out b/tst/testspecial/current-env.g.out index e90991e7e2..68ec461013 100644 --- a/tst/testspecial/current-env.g.out +++ b/tst/testspecial/current-env.g.out @@ -16,8 +16,8 @@ od; @ *stdin*:6 ( ) called from read-eval loop at *stdin*:9 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> ContentsLVars(CurrentEnv()); rec( func := function( n ) ... end, names := [ "n" ], values := [ 1 ] ) brk> DownEnv(); ContentsLVars(CurrentEnv()); diff --git a/tst/testspecial/debug-var.g.out b/tst/testspecial/debug-var.g.out index ab72b2459f..bbff49cdd5 100644 --- a/tst/testspecial/debug-var.g.out +++ b/tst/testspecial/debug-var.g.out @@ -19,8 +19,8 @@ Stack trace: @ *stdin*:12 ( ) called from read-eval loop at *stdin*:14 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> brk> x; # access global 1 @@ -61,7 +61,7 @@ Stack trace: @ *stdin*:12 ( ) called from read-eval loop at *errin*:12 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk_2> quit; brk> brk> z; # access local @@ -80,7 +80,7 @@ Stack trace: @ *stdin*:12 ( ) called from read-eval loop at *errin*:17 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk_2> quit; brk> brk> return; @@ -106,8 +106,8 @@ Stack trace: @ *stdin*:12 ( ) called from read-eval loop at *stdin*:23 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> h(2); Error, foobar Stack trace: @@ -119,8 +119,8 @@ Stack trace: @ *stdin*:12 ( ) called from read-eval loop at *errin*:1 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk_2> brk_2> y; # access higher local as debug var 2 diff --git a/tst/testspecial/error-in-InputTextString.g.out b/tst/testspecial/error-in-InputTextString.g.out index 36b19d8b23..f27a402920 100644 --- a/tst/testspecial/error-in-InputTextString.g.out +++ b/tst/testspecial/error-in-InputTextString.g.out @@ -2,6 +2,6 @@ gap> Read(InputTextString("Print(1 + [()]);")); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `+' on 2 arguments called from read-eval loop at stream:1 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> QUIT; diff --git a/tst/testspecial/func-and-proc-call-trace.g.out b/tst/testspecial/func-and-proc-call-trace.g.out index 046b27f874..e58f4ef668 100644 --- a/tst/testspecial/func-and-proc-call-trace.g.out +++ b/tst/testspecial/func-and-proc-call-trace.g.out @@ -10,7 +10,7 @@ Stack trace: @ *stdin*:4 ( ) called from read-eval loop at *stdin*:6 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -27,7 +27,7 @@ Stack trace: @ *stdin*:9 ( ) called from read-eval loop at *stdin*:11 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -44,7 +44,7 @@ Stack trace: @ *stdin*:14 ( ) called from read-eval loop at *stdin*:16 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -61,7 +61,7 @@ Stack trace: @ *stdin*:19 ( ) called from read-eval loop at *stdin*:21 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -78,7 +78,7 @@ Stack trace: @ *stdin*:24 ( ) called from read-eval loop at *stdin*:26 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -95,7 +95,7 @@ Stack trace: @ *stdin*:29 ( ) called from read-eval loop at *stdin*:31 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -112,7 +112,7 @@ Stack trace: @ *stdin*:34 ( ) called from read-eval loop at *stdin*:36 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -129,7 +129,7 @@ Stack trace: @ *stdin*:39 ( ) called from read-eval loop at *stdin*:41 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -146,7 +146,7 @@ Stack trace: @ *stdin*:44 ( ) called from read-eval loop at *stdin*:46 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -163,7 +163,7 @@ Stack trace: @ *stdin*:49 ( ) called from read-eval loop at *stdin*:51 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -180,7 +180,7 @@ Stack trace: @ *stdin*:54 ( ) called from read-eval loop at *stdin*:56 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -197,7 +197,7 @@ Stack trace: @ *stdin*:59 ( ) called from read-eval loop at *stdin*:61 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -214,7 +214,7 @@ Stack trace: @ *stdin*:64 ( ) called from read-eval loop at *stdin*:66 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -231,7 +231,7 @@ Stack trace: @ *stdin*:69 ( ) called from read-eval loop at *stdin*:71 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -248,7 +248,7 @@ Stack trace: @ *stdin*:74 ( ) called from read-eval loop at *stdin*:76 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); @@ -265,7 +265,7 @@ Stack trace: @ *stdin*:79 ( ) called from read-eval loop at *stdin*:81 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> quit; gap> Print("\n\n"); diff --git a/tst/testspecial/last-access.g.out b/tst/testspecial/last-access.g.out index 78d756615f..2bc0c8131e 100644 --- a/tst/testspecial/last-access.g.out +++ b/tst/testspecial/last-access.g.out @@ -6,8 +6,8 @@ gap> 1;2;3;[last,last2,last3]; gap> Error("err"); Error, err not in any function at *stdin*:3 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> 1;2;3;[last,last2,last3]; 1 2 diff --git a/tst/testspecial/line-continuation.g.out b/tst/testspecial/line-continuation.g.out index 2f06f33fdc..a6ed2a8a24 100644 --- a/tst/testspecial/line-continuation.g.out +++ b/tst/testspecial/line-continuation.g.out @@ -11,8 +11,8 @@ Stack trace: @ GAPROOT/lib/string.gi:LINE ( ) called from read-eval loop at *stdin*:6 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> quit; gap> EvalString("123\\\r\n45x;"); Error, Variable: '12345x' must have a value @@ -23,7 +23,7 @@ Stack trace: @ GAPROOT/lib/string.gi:LINE ( ) called from read-eval loop at *stdin*:6 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> quit; gap> QUIT; diff --git a/tst/testspecial/mem-overflow.g.out b/tst/testspecial/mem-overflow.g.out index 1f9147a44c..9de037b50f 100644 --- a/tst/testspecial/mem-overflow.g.out +++ b/tst/testspecial/mem-overflow.g.out @@ -7,8 +7,8 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:3 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> # ... then we should be in a break loop. Exit that, perform some other computations. brk> quit; gap> Factorial(42); diff --git a/tst/testspecial/method-not-found-where.g.out b/tst/testspecial/method-not-found-where.g.out index eaaeaee161..5f80b728c7 100644 --- a/tst/testspecial/method-not-found-where.g.out +++ b/tst/testspecial/method-not-found-where.g.out @@ -8,7 +8,7 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:4 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> ShowMethods(1); #I Searching Method for IsDiagonalMatrix with 1 argument: #I Total: 3 entries diff --git a/tst/testspecial/method-not-found.g.out b/tst/testspecial/method-not-found.g.out index fa8a04ad87..2001ae951b 100644 --- a/tst/testspecial/method-not-found.g.out +++ b/tst/testspecial/method-not-found.g.out @@ -7,7 +7,7 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:3 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> return; 'return' cannot be used in this read-eval-print loop brk> QUIT; diff --git a/tst/testspecial/print-formatting.g.out b/tst/testspecial/print-formatting.g.out index 91e7af8741..11a0eb6932 100644 --- a/tst/testspecial/print-formatting.g.out +++ b/tst/testspecial/print-formatting.g.out @@ -23,7 +23,7 @@ gap> # test formatting status for errout gap> 1/0; # trigger a break loop Error, Rational operations: must not be zero not in any function at *stdin*:14 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> old := PrintFormattingStatus("*errout*"); true brk> SetPrintFormattingStatus("*errout*", false); diff --git a/tst/testspecial/repl-syntax-err.g.out b/tst/testspecial/repl-syntax-err.g.out index 7f31dd0233..783de07a05 100644 --- a/tst/testspecial/repl-syntax-err.g.out +++ b/tst/testspecial/repl-syntax-err.g.out @@ -8,8 +8,8 @@ gap> # fixed. gap> Error(""): Error, not in any function at *stdin*:9 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> quit; Syntax error: ; expected Error(""): diff --git a/tst/testspecial/stack-depth-func.g.out b/tst/testspecial/stack-depth-func.g.out index 37a8116566..26446d3435 100644 --- a/tst/testspecial/stack-depth-func.g.out +++ b/tst/testspecial/stack-depth-func.g.out @@ -14,8 +14,8 @@ Stack trace: [5] f( ); @ *stdin*:2 ... at *stdin*:3 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> return; # try once more Error, recursion depth trap (10000) Stack trace: @@ -30,6 +30,6 @@ Stack trace: [5] f( ); @ *stdin*:2 ... at *stdin*:3 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> QUIT; diff --git a/tst/testspecial/stack-depth-func2.g.out b/tst/testspecial/stack-depth-func2.g.out index d41cac1c18..f82d7ece2f 100644 --- a/tst/testspecial/stack-depth-func2.g.out +++ b/tst/testspecial/stack-depth-func2.g.out @@ -14,8 +14,8 @@ Stack trace: [5] f( ) @ *stdin*:2 ... at *stdin*:3 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> return; # try once more Error, recursion depth trap (10000) Stack trace: @@ -30,6 +30,6 @@ Stack trace: [5] f( ) @ *stdin*:2 ... at *stdin*:3 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> QUIT; diff --git a/tst/testspecial/stack-depth-rec.g.out b/tst/testspecial/stack-depth-rec.g.out index 3a2f0bcb5a..88d55ca50e 100644 --- a/tst/testspecial/stack-depth-rec.g.out +++ b/tst/testspecial/stack-depth-rec.g.out @@ -82,8 +82,8 @@ Stack trace: [5] String( record.(nam) ) @ GAPROOT/lib/record.gi:LINE ... at *stdin*:4 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> return; # try once more Error, recursion depth trap (5000) Stack trace: @@ -98,6 +98,6 @@ Stack trace: [5] String( record.(nam) ) @ GAPROOT/lib/record.gi:LINE ... at *stdin*:4 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> QUIT; diff --git a/tst/testspecial/stack-trace-depth.g.out b/tst/testspecial/stack-trace-depth.g.out index 9c12a52a9a..bb06fe9547 100644 --- a/tst/testspecial/stack-trace-depth.g.out +++ b/tst/testspecial/stack-trace-depth.g.out @@ -45,8 +45,8 @@ Stack trace: [5] f8( ) @ *stdin*:15 ... at *stdin*:35 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> SetUserPreference("WhereDepth", 12); brk> Where(); Stack trace: diff --git a/tst/testspecial/stack-trace-label.g.out b/tst/testspecial/stack-trace-label.g.out index a7a71b90c8..2397215b7c 100644 --- a/tst/testspecial/stack-trace-label.g.out +++ b/tst/testspecial/stack-trace-label.g.out @@ -8,7 +8,7 @@ Stack trace: @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> quit; gap> QUIT; diff --git a/tst/testspecial/syntax-tree-error.g.out b/tst/testspecial/syntax-tree-error.g.out index 96794103f1..bff4a4d368 100644 --- a/tst/testspecial/syntax-tree-error.g.out +++ b/tst/testspecial/syntax-tree-error.g.out @@ -12,6 +12,6 @@ Stack trace: *[1] ( ) called from read-eval loop at *stdin*:8 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> QUIT; diff --git a/tst/testspecial/top-level-error.g.out b/tst/testspecial/top-level-error.g.out index f27f9df6d9..b4a6915bca 100644 --- a/tst/testspecial/top-level-error.g.out +++ b/tst/testspecial/top-level-error.g.out @@ -1,6 +1,6 @@ gap> Error("foo"); Error, foo not in any function at *stdin*:2 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk> QUIT; diff --git a/tst/testspecial/up-down-env.g.out b/tst/testspecial/up-down-env.g.out index 93062e655b..a3c9ea82b0 100644 --- a/tst/testspecial/up-down-env.g.out +++ b/tst/testspecial/up-down-env.g.out @@ -19,7 +19,7 @@ Stack trace: [5] f( lvl - 1 ) @ *stdin*:7 ... at *stdin*:8 -type 'quit;' to quit to outer loop +you can enter 'quit;' to quit to outer loop brk> UpEnv(1); lvl; 0 brk> DownEnv(1); lvl; @@ -56,8 +56,8 @@ brk> ## brk> Read("top-level-error.g"); Error, foo not in any function at top-level-error.g:1 -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +you can enter 'quit;' to quit to outer loop, or +you can enter 'return;' to continue brk_2> Where(20); not in any function at *errin*:1 brk_2> lvl; # since `Read` started a fresh execution context, we can't access lvl here From 9b0b658aa5d23600ecb879de6b57316b90b2a8c8 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 10 Jun 2026 23:11:13 +0200 Subject: [PATCH 106/123] Remove dev/migratedoc.tex and doc/tut/migrat.xml (#6431) They are not referenced anywhere and nowadays at most of historical interest. --- dev/migratedoc.tex | 1141 ---------------------------------------- doc/tut/migrat.xml | 1227 -------------------------------------------- 2 files changed, 2368 deletions(-) delete mode 100644 dev/migratedoc.tex delete mode 100644 doc/tut/migrat.xml diff --git a/dev/migratedoc.tex b/dev/migratedoc.tex deleted file mode 100644 index 8e3f02270e..0000000000 --- a/dev/migratedoc.tex +++ /dev/null @@ -1,1141 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%W migratedoc.tex GAP documentation Thomas Breuer -%W & Frank Celler -%W & Martin Schoenert -%W & Heiko Theissen -%% -%% -%Y Copyright 1997, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany -%% -%% self-contained document with the former chapter -%% ``Migrating to GAP 4'' of the GAP Tutorial -%% -\input gapmacro -\BeginningOfBook{mig} -\TitlePage{ - \centerline{\titlefont GAP}\bigskip - \centerline{\secfont Release 4.5}\medskip - \centerline{\secfont May 2012}\bigskip\bigskip - \centerline{\titlefont Migrating to GAP 4}\vfill - \centerline{\secfont The GAP Group}\bigskip - \centerline{\secfont https://www.gap-system.org} -} -\TableOfContents -\FrontMatter -Copyright {\copyright} (1987-2012) for the core -part of the {\GAP} system by the {\GAP} Group. - -Most parts of the {\GAP} distribution, including -the core part of the {\GAP} system, are distributed -under the terms of the GNU General Public License -(see {\tt{https://www.gnu.org/licenses/gpl.html}} -or the file {\tt GPL} in the {\tt etc} directory -of the {\GAP} installation). - -More detailed information about copyright and -licenses of parts of this distribution can be -found in the {\GAP}~4 Reference manual -(see {\bf Reference: Copyright and License}). - -{\GAP} is developed over a long time and has -many authors and contributors. More detailed -information can be found in the {\GAP}~4 -Reference manual (see {\bf Reference: Authors and Maintainers}). - -\Chapters - -\Chapter{Migrating to GAP 4} - -This chapter is intended to give users who have experience with {\GAP}~3 -some information about what has changed in {\GAP}~4. -In particular, it informs about changed command line options -(see~"Changed Command Line Options"), -the new global variable `fail' (see~"Fail"), -some functions that have changed their behaviour -(see~"Changed Functionality") or their names -(see~"Changed Variable Names"), -and some conventions used for variable names (see~"Naming Conventions"). - -Then the new concepts of {\GAP}~4 are sketched, -first that of mutability or immutability (see~"Immutable Objects"), -with the explanation of related changes in functions that copy objects -(see~"Copy"), -then the concepts of operations and method selection, which are compared -with the use of operations records in {\GAP}~3 -(see~"Attributes vs. Record Components", "Operations Records", -and~"Operations vs. Dispatcher Functions"). - -More local changes affect the concepts of notions of generation -(see~"Different Notions of Generation"), -of parents (see~"Parents and Subgroups"), -of homomorphisms (see~"Homomorphisms vs. General Mappings", -"Homomorphisms vs. Factor Structures", -and~"Isomorphisms vs. Isomorphic Structures"), -how elements in finitely presented groups are treated -(see~"Elements of Finitely Presented Groups"), -how information about progress of computations can be obtained -(see~"The Info Mechanism"), -and how one gets information in a `break' loop -(see~"Debugging"). - -%Commented out: no longer provided with GAP 4.5 -%While a ``{\GAP}~3 compatibility mode'' is provided -%(see "Compatibility Mode"), -%its use will disable some of the new features of {\GAP}~4. -%Also it certainly can only try to provide partial compatibility. - -%For a detailed explanation of the new features and concepts of {\GAP}~4, -%see the manual ``Programming in GAP''. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Changed Command Line Options} - -In {\GAP}~4, the `-l' option is used to specify the *root directory* -(see ``GAP Root Directory'' in the {\GAP}~4 Reference Manual) -of the {\GAP} distribution, -which is the directory containing the `lib' and `doc' subdirectories. -Note that in {\GAP}~3 this option was used to specify the path to the -`lib' directory. - -The `-h' option of {\GAP}~3 has been removed, -the path(s) for the documentation are deduced automatically in {\GAP}~4. - -The option `-g' is now used to print information only about full garbage -collections. -The new option `-g -g' generates information about partial -garbage collections too. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Fail} - -There is a new global variable - -\>`fail'{fail instead of false} - -in {\GAP}~4. -It is intended as a return value of a function for the case that it -could not perform its task. -For example, `Inverse' returns `fail' if it is called with a singular -matrix, and `Position' returns `fail' if the second argument is not -contained in the list given as first argument. - -{\GAP}~3 handled such situations by either signalling an error, -for example if it was asked for the inverse of a singular matrix, -or by (mis)using `false' as return value, as in the example `Position'. -Note that in the first example, in {\GAP}~3 it was necessary to check -the invertibility of a matrix before one could safely ask for its -inverse, which meant that roughly the same work was done twice. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Changed Functionality} - -Some functions that were already available in {\GAP}~3 behave -differently in {\GAP}~4. This section lists them. - -\>Orbit( ,) - -The {\GAP}~3 manual promised that would be the first entry of the -resulting orbit. This was wrong already there in a few cases, therefore -{\GAP}~4 does not promise anything about the ordering of points in an orbit. - -\>Order( ) - -only takes the element and computes its multiplicative order. -%Calling `Order' with two arguments is permitted only in the -%{\GAP}~3 compatibility mode, see~"Compatibility Mode". -(Note that it does not make sense anymore to specify a group as -first argument w.r.t. which the order of the second argument shall -be computed, see~"Elements of Finitely Presented Groups".) - -\>Position( , ) - -If is not contained in the list then `fail' is returned -in {\GAP}~4 (see~"Fail"), whereas `false' was returned in {\GAP}~3. - - -\>PermGroupOps.ElementProperty( , [, ] ) - -In {\GAP}~3, this function took either two or three arguments, -the optional argument being a subgroup of that stabilizes -in the sense that for any element in , -either all elements or no element in the coset ` \* ' have the -property . - -The {\GAP}~4 function `ElementProperty', however, -takes between two and four arguments, -and the subgroup known from {\GAP}~3 has to be entered as the *fourth* -argument *not* the third. -(The third argument in the {\GAP}~4 function denotes a subgroup -stabilizing in the sense that either all elements or no element -in right cosets ` \* ' have the property .) - -(This discrepancy was discovered only in March~2002, -short before the release of {\GAP}~4.3.) - - -\>Print( , ... ) - -Objects may appear on the screen in a different way, -depending on whether they are printed by the read eval print loop -or by an explicit call of `Print'. -The reason is that the read eval print loop calls the operation `ViewObj' -and not `PrintObj', whereas `Print' calls `PrintObj' for each of its -arguments. -This permits the installation of methods for printing objects in a short form -in the read eval print loop while retaining `Print' to display -the object completely. -See also Section ``View and Print'' in the {\GAP}~4 Reference Manual. - -(`PrintObj' is installed as standard method `ViewObj', so it is -not really necessary to have a `ViewObj' method for an object.) - -\>PrintTo( , , ... ) - -In {\GAP}~3, `PrintTo' could be (mis)used to ``redirect'' the text -*printed* by a function (that is, *not* only the output of a function) -to a file by entering the function call as second argument. -This was used mainly in order to avoid many calls of `AppendTo'. -In {\GAP}~4, this feature has disappeared. -One can use streams (see Chapter ``Streams'' in the {\GAP}~4 Reference Manual) -instead in order to write files efficiently. - -\break - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Changed Variable Names} - -\indextt{AgGroup} -\indextt{ApplyFunc} -\indextt{Backtrace} -\indextt{CharTable} -\indextt{Denominator} -\indextt{DepthVector} -\indextt{Elements} -\indextt{IsBijection} -\indextt{IsFunc} -\indextt{IsMat} -\indextt{IsRec} -\indextt{IsSet} -\indextt{LengthWord} -\indextt{NOfCyc} -\indextt{Numerator} -\indextt{RandomInvertableMat} -\indextt{RecFields} -\indextt{X} - -Some functions have changed their name without changing the -functionality. -A -- probably incomplete -- list follows -\begintt - GAP 3 GAP 4 - - AgGroup PcGroup # (also composita) - ApplyFunc CallFuncList - Backtrace Where - CharTable CharacterTable # (also composita) - Denominator DenominatorRat - DepthVector PositionNonZero - Elements AsSSortedList - IsBijection IsBijective - IsFunc IsFunction - IsMat IsMatrix - IsRec IsRecord - IsSet IsSSortedList - LengthWord Length - NOfCyc Conductor - Numerator NumeratorRat - NormedVector NormedRowVector - Operation Action # (also composita) - Order(G,g) Order(g) - OrderMat Order - OrderPerm Order - RandomInvertableMat RandomInvertibleMat - RecFields RecNames - X Indeterminate -\endtt - -%See Section~"Compatibility Mode" for a way to make the old names -%available again. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Naming Conventions} - -The way functions are named has been unified in {\GAP}~4. -This might help to memorize or even guess names of library functions. - -If a variable name consists of several words then the first -letter of each word is capitalized. - -If the first part of the name of a function is a verb then the function -may modify its argument(s) but does not return anything, -for example `Append' appends the list given as second argument to the -list given as first argument. -Otherwise the function returns an object without changing the arguments, -for example `Concatenation' returns the concatenation of the lists -given as arguments. - -If the name of a function contains the word `By' then the return value is -thought of as built in a certain way from the parts given as arguments. -For example, `GroupByGenerators' returns a group built from its group -generators, and creating a group as a factor group of a given group -by a normal subgroup can be done by taking the image of -`NaturalHomomorphismByNormalSubgroup' -(see also~"Homomorphisms vs. Factor Structures"). -Other examples of ```By''' functions are `GroupHomomorphismByImages' and -`UnivariateLaurentPolynomialByCoefficients'. - -If the name of a function contains the word `Of' then the return value is -thought of as information deduced from the arguments. -Usually such functions are attributes -(see ``Attributes'' in the {\GAP}~4 Reference Manual). -Examples are `GeneratorsOfGroup', which returns a list of generators for -the group entered as argument, or `DiagonalOfMat'. - -For the setter and tester functions of an attribute -(see~"Attributes vs. Record Components" in this document -and ``Attributes'' in the {\GAP}~4 Reference Manual) -the names `Set' resp.~`Has' are available. - -If the name of a function ends with `NC' then there is another -function with the same name except that the `NC' is missing. -`NC' stands for ``no check''. -When is called then it checks whether its arguments are valid, -and if so then it calls . -The functions `SubgroupNC' and `Subgroup' are a typical example. - -The idea is that the possibly time consuming check of the arguments -can be omitted if one is sure that they are unnecessary. -For example, if an algorithm produces generators of the derived subgroup -of a group then it is guaranteed that they lie in the original group; -`Subgroup' would check this, and `SubgroupNC' omits the check. - -Needless to say, all these rules are not followed slavishly, -for example there is one operation `Zero' instead of two operations -`ZeroOfElement' and `ZeroOfAdditiveGroup'. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Immutable Objects} - -{\GAP}~4 supports ``immutable'' objects. Such objects cannot be -changed, attempting to do so issues an error. Typically attribute -values are immutable, and also the results of those binary arithmetic -operations where both arguments are immutable. -For example, `[1..100]+[1..100]' is a -mutable list and `2 \* Immutable([1..100])' is an immutable -list, both are equal to the (mutable) list `[2,4..200]'. - -There is no way to *make* an immutable object mutable, one can only -get a mutable copy by `ShallowCopy'. The other way round, -`MakeImmutable' makes a (mutable or immutable) object and all its -subobjects immutable; one must be very careful to use `MakeImmutable' -only for those objects that are really newly created, for such objects -the advantage over `Immutable' is that no copy is made. - -More about immutability can be found in Sections ``Immutability'' in -the {\GAP}~4 Tutorial and ``Mutability and Copyability'' in the {\GAP}~4 -Reference Manual. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Copy} - -\indextt{StructuralCopy} -\indextt{ShallowCopy} -The function `Copy' of {\GAP}~3 is not supported in {\GAP}~4. This -function was used to create a copy of its argument with -the properties that and had no subobjects in common and -that if two subobjects of were identical then also the -corresponding subobjects of were identical. - -The possibility of having immutable objects (see~"Immutable Objects") can and -should be used to avoid unnecessary copying. -Namely, given an immutable object one needs to copy it only if one wants -to get a modified object, and in such a situation usually it is -sufficient to use `ShallowCopy', or at least one knows how deep one must -copy in order to do the changes one has in mind. - -For example, suppose you have a matrix group, and you want to -construct a list of matrices by modifying the group generators. This -list of generators is immutable, so you call `ShallowCopy' to get a -mutable list that contains the same matrices. If you only want to -exchange some of them, or to append some other matrices, this shallow -copy is already what you need. So suppose that you are interested in -a list of matrices where some rows are also changed. For that, you -call `ShallowCopy' for the matrices in question, and you get matrices -whose rows can be changed. If you want to change single entries in -some rows, `ShallowCopy' must be called to get mutable copies of these -rows. Note that in all these situations there is no danger to change, -i.e., to destroy the original generators of the matrix group. - -If one needs the facility of the `Copy' function of {\GAP}~3 to get a -copy with the same structure then one can use the new {\GAP}~4 -function `StructuralCopy'. It returns a structural copy that has no -*mutable* subobject in common with its argument. So if -`StructuralCopy' is called with an immutable object then this object -itself is returned, and if `StructuralCopy' is called with a mutable -list of immutable objects then a shallow copy of this list is -returned. - -Note that `ShallowCopy' now is an operation. So if you create your -own type of (copyable) objects then you must define what a shallow -copy of these objects is, and install an appropriate method. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Attributes vs. Record Components} - -In {\GAP}~3, many complex objects were represented via records, for -example all domains. Information about these objects was stored in -components of these records. For the user, this was usually not -relevant, since there were functions for computing information about -the objects in question. For example, if one was interested in the -size of a group then one could call `Size'. - -But since it was guaranteed that the size of a domain was stored -as value of the component `size', it was allowed to access `.size' -if this component was bound, and a check for this was possible via -`IsBound( .size )'. - -In {\GAP}~4, only the access via functions is admissible. One reason -is the following basic rule. - -*From the information that a given {\GAP}~4 object is for example a -domain, one cannot conclude that this object has a certain -representation.* - -For attributes like `Size', {\GAP}~4 provides two related functions, -the *setter* and the *tester* of the attribute, which can be used to -set an attribute value and to check whether the value of an attribute -is already stored for an object (see also ``Attributes'' in the {\GAP}~4 -Reference Manual). For example, if is a domain in {\GAP}~4 then -`HasSize( )' is `true' if the size of is already stored, and -`false' otherwise. In the latter case, if you know that the size of - is then you may store it by `SetSize( , )'. - -Besides the flexibility in the internal representation of objects, -storing information only via function calls has also the advantage -that {\GAP}~4 is able to draw conclusions automatically. For example, -as soon as it is stored that a group is nilpotent, it is also stored -that it is solvable, see Chapters ``Types of Objects'' and -``Method Selection'' in the {\GAP}~4 Reference Manual for the details. - -As a consequence, you cannot put your favourite information into a -domain by assigning it to a new component like -`.myPrivateInfo'. Instead you can introduce a new attribute and -then use its setter, -see Section ``Attributes'' in the {\GAP}~4 Reference Manual. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Different Notions of Generation} - -As in {\GAP}~3, a *domain* in {\GAP}~4 is a structured set. - -The same set can have different structures, for example a field can be -regarded as a ring or as an algebra or vector space over a subfield. - -In {\GAP}~3, however, an object representing a ring did not represent -a field, and an object representing a field did not represent a ring. -One reason for this was that the record component `generators' was -used to denote the appropriate generators of the domain. For a ring -, the component `.generators' was a list of ring generators, and -for a field , `.generators' was a list of field generators. - -{\GAP}~4 cleans this up, -see ``Notions of Generation'' in the {\GAP}~4 Tutorial. It supports -many different notions of generation, for example one can ask for -magma generators of a group or for generators of a field as an additive -group. A subtle but important distinction is that between generators -of an algebra and of an algebra-with-one. - -So the attributes `GeneratorsOfGroup', `GeneratorsOfMagma', -`GeneratorsOfRing', `GeneratorsOfField', `GeneratorsOfVectorSpace', -and so on, replace the access to the `generators' component. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Operations Records} - -Already in {\GAP}~3 there were several functions that were applicable -to many different kinds of objects, for example `Size' could be -applied to any domain, and the binary infix multiplication `*' could -be used to multiply two matrices, an integer with a row vector, or a -permutation with a permutation group. This was implemented as -follows. Functions like `Size' and `*' tried to find out what -situation was described by its arguments, and then it called a more -specific function to compute the desired information. These more -specific functions, let us call them *methods* as they are also called -in {\GAP}~4, were stored in so-called *operations records* of the -arguments. - -For example, every domain in {\GAP}~3 was represented as a record, and -the operations record was stored in the record component `operations'. -If `Size' was called for the domain then the method to compute the -size of the domain was found as value of the `Size' component of the -operations record. - -This was fine for functions taking only one argument, and in principle -it is possible that for those functions an object stored an optimal -method in its operations record. But in the case of more arguments -this is not possible. In a multiplication of two objects in {\GAP}~3, -one had to choose between the methods stored in the operations records -of the arguments, and if for example the method stored for the left -operand was called, this method had to handle all possible right -operands. - -So operations records turned out to be not flexible enough. In -{\GAP}~4, operations records are not supported -%(see~"Compatibility Mode" for a possibility to use your {\GAP}~3 -%code that utilizes operations records, at least to some extent). -A detailed description -of the new mechanism to select methods can be found in -Chapter ``Method Selection'' in the {\GAP}~4 Reference Manual. - -An important point is that the new mechanism allows {\GAP} to take the -relation between arguments into account. So it is possible (and -recommended) to install different methods for different relations -between the arguments. Note that such methods need not do the -extensive argument checking that was necessary in {\GAP}~3, because -most of the checks are done already by the method selection mechanism. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Operations vs. Dispatcher Functions} - -{\GAP}~3 functions like `Size', `CommutatorSubgroup', or -`SylowSubgroup' did mainly call an appropriate method (see~"Operations -Records") after they had checked their arguments. Such functions were -called *dispatchers* in {\GAP}~3. In {\GAP}~4, many dispatchers have -been replaced by *operations*, due to the fact that methods are no -longer stored in operations records (see ``Method Selection'' in -in the {\GAP}~4 Reference Manual for the details). - -Most dispatchers taking only one argument were treated in a special -way in {\GAP}~3, they had the additional task of storing computed -values and using these values in subsequent calls. For example, the -dispatcher `Size' first checked whether the size of the argument was -already stored, and if so then this value was returned; otherwise a -method was called, the value returned by this method was stored in the -argument, and then returned by `Size'. - -In {\GAP}~4, computed values of operations that take one argument -(these operations are called *attributes*) are also stored, only the -mechanism to achieve this has changed, see the sections ``Attributes'' -and ``Properties'' in the {\GAP}~4 Reference Manual. - -So the behaviour of `Size' is the same in {\GAP}~3 and {\GAP}~4. But -note that in {\GAP}~4, it is not possible to access `.size', -see~"Attributes vs. Record Components". As described in~"Operations -Records", {\GAP}~4 does not admit ``bypassing the dispatcher'' by -calling for example `.operations.Size'. This was done in {\GAP}~3 -often for efficiency reasons, but the method selection mechanism of -{\GAP}~4 is fast enough to make this unnecessary. - -If you had written your own dispatchers and put your own methods into -existing operations records then this code will not work in {\GAP}~4. -See ``Creating New Objects'' and ``Method Selection'' in the {\GAP}~4 -Reference Manual for a description of how to define operations and -to install methods. - -Finally, some functions in {\GAP}~3 were hidden in -operations records, e.g., `PermGroupOps.MovedPoints'. -These functions became proper operations in {\GAP}~4. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Parents and Subgroups} - -In {\GAP}~3 there was a strict distinction between parent groups and -subgroups. -The use of the name ``parent'' (instead of ``supergroup'') -was chosen to indicate that the parent of an object was more than just -useful information. -In fact the main reason for the introduction of parents was to provide -a common roof for example for all groups of polycyclic words that -belonged to the same PC-presentation, or for all subgroups of a finitely -presented group (see~"Elements of Finitely Presented Groups"). -A subgroup was never a parent group, and it was possible to create -subgroups only of parent groups. - -In {\GAP}~4 this common roof is provided already by the concept of -*families*, see Section ``Families'' in the {\GAP}~4 Reference Manual. -Thus it is no longer compulsory to use parent groups at all. -On the other hand, parents *may* be used in {\GAP}~4 to provide -information about an object, for example the normalizer of a group in its -parent group may be stored as an attribute value. -Note that there is no restriction on the supergroup that is set to be -the parent, -it is possible to create a subgroup of -any group, this group then being the parent of the new subgroup. -This permits for example chains of subgroups with respective parents, -of arbitrary length. - -As a consequence, the `Parent' command cannot be used in {\GAP}~4 to -test whether the two arguments of `CommutatorSubgroup' fit together, -this is now a question that concerns the relation between the families -of the groups. So the 2-argument version of `Parent' and the now -meaningless function `IsParent' have been abolished. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Homomorphisms vs. General Mappings} - -In {\GAP}~3 there had been a confusion between group homomorphisms and -general mappings, as `GroupHomomorphismByImages' created only a -general mapping that did *not* store whether it was a mapping. This -caused expensive, unwanted, and unnecessary tests whether the mapping -was in fact a group homomorphism. Moreover, the ``official'' -workaround to set some components of the mapping record was quite -unwieldy. - -In {\GAP}~4, `GroupHomomorphismByImages' checks whether the desired -mapping is indeed a group homomorphism; if so then this property is -stored in the returned mapping, otherwise `fail' is returned. If you -want to avoid the checks then you can use -`GroupHomomorphismByImagesNC'. If you want to check whether a general -mapping that respects the group operations is really a group -homomorphism, you can construct it via `GroupGeneralMappingByImages' -and then call `IsGroupHomomorphism' for it. (Note that -`IsGroupHomomorphism' returns `true' if and only if both -`IsGroupGeneralMapping' and `IsMapping' do, so one does in fact check -`IsMapping' in this case.) - -There is *no* function `IsHomomorphism' in {\GAP}~4, -since there are several different operations with respect to which a -mapping can be a homomorphism. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Homomorphisms vs. Factor Structures} - -If $F$ is a factor structure of $G$, with kernel $N$, complete -information about the connection between $F$ and $G$ is provided by -the *natural homomorphism*. - -In {\GAP}~3, the ``official way'' to construct this natural homomorphism -was to create first the factor structure $F$, and then to call -`NaturalHomomorphism' with the arguments $G$ and $F$. -For that, the data necessary to compute the homomorphism was stored in -$F$ when $F$ was constructed. - -In {\GAP}~4, factor structures are not treated in a special way, -in particular they do not store information about a homomorphism. -Instead, the more natural way is taken to construct the natural -homomorphism from $G$ and $N$ by `NaturalHomomorphismByNormalSubgroup' -if $N$ is a normal subgroup of the group $G$, -or by `NaturalHomomorphismByIdeal' if $N$ is an ideal in the ring $G$. -The factor $F$ can then be accessed as the image of this homomorphism, -and of course $G$ is the preimage and $N$ is the kernel. - -Note that {\GAP}~4 does not guarantee anything about the representation -of the factor $F$, it may be a permutation group or a polycyclically -presented group or another kind of group. -Also note that a natural homomorphism need not be surjective. - -A consequence of this change is that {\GAP}~4 does *not* allow you to -construct a natural homomorphism from the groups $G$ and $F$. - -The other common type of homomorphism in {\GAP} 3, ``operation -homomorphisms'', have been replaced (just a name change) by *action -homomorphisms*, which are handled in a similar fashion. That is, an -action homomorphism is constructed from an acting group, an action -domain, and a function describing the operation. The permutation -group arising by the induced action is then the image of this -operation homomorphism. - -The {\GAP}~3 function `Operation' is still supported, under the name `Action', -but from the original group and the result of `Action' it is not -possible to construct the action homomorphism. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Isomorphisms vs. Isomorphic Structures} - -In {\GAP}~3, a different representation of a group could be obtained by -calling `AgGroup' to get an isomorphic polycyclically presented group, -`PermGroup' to get an isomorphic permutation group, and so on. -The returned objects stored an isomorphism in the record component -`bijection'. - -For the same reason as in~"Homomorphisms vs. Factor Structures", -{\GAP}~4 puts emphasis on the isomorphism, -and the isomorphic object in the desired representation can be accessed -as its image. -So you can call `IsomorphismPcGroup' or `IsomorphismPermGroup' in order -to get an isomorphism to a polycyclically presented group or a -permutation group, respectively, and then call `Image' to get the -isomorphic group. - -Note that the image of an action homomorphism with trivial kernel is -also an isomorphic permutation group, but an action homomorphism need -not be surjective, since it may be easier to define it into the full -symmetric group. - -Further note that in {\GAP}~3, a usual application of isomorphisms to -polycyclically presented groups was to utilize the usually more -effective algorithms for solvable groups. However, the new concept of -polycyclic generating systems in {\GAP}~4 makes it possible to apply -these algorithms to arbitrary solvable groups, independent of the -representation. For example, {\GAP}~4 can handle polycyclic -generating systems of solvable permutation groups. So in many cases, -a change of the representation for efficiency reasons may be not -necessary any longer. - -In general `IsomorphismFpGroup' will define a presentation on generators -chosen by the algorithm. The corresponding elements of the original -group can be obtained by the command -\begintt -gens:=List(GeneratorsOfGroup(Image(isofp)),i->PreImagesRepresentative(isofp,i)); -\endtt -If a presentation in the given generators is needed, the command -`IsomorphismFpGroupByGenerators(, )' will produce one. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Elements of Finitely Presented Groups} - -Strictly speaking, {\GAP}~3 did not support elements of finitely -presented groups. Instead, the ``words in abstract generators'' of -the underlying free groups were (mis)used. This caused problems -whenever calculations with elements were involved, the most obvious -ones being wrong results of element comparisons. Also functions -that should in principle work for any group were not applicable to -finitely presented groups. In effect, a finitely presented group had -to be treated in a special way in {\GAP}~3. - -{\GAP}~4 distinguishes free groups and their elements from finitely -presented groups and their elements. Comparing two elements of a -finitely presented group will yield either the correct result or no -result at all. - -Note that in {\GAP}~4, the arithmetic and comparison operations for -group elements do not depend on a context provided by a group that -contains the elements. In particular, in {\GAP}~4 it is not -meaningful to call `Order( , )' for a group and an element -. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Polynomials} - -In {\GAP}~3, polynomials were defined over a field. So a polynomial over -`GF(3)' was different from a polynomial over `GF(9)', even if the -coefficients were exactly the same. - -{\GAP}~4 defines polynomials only over a characteristic. This makes it -possible for example to multiply a polynomial over `GF(3)' with a polynomial -over `GF(9)' without the need to convert the former to the larger field. - -However it has an effect on the result of `DefaultRing' for polynomials: -In {\GAP}~3 the default ring for a polynomial was the polynomial ring of the -field over which the polynomial was defined. In {\GAP}~4 no field is -associated, so (to avoid having to define the algebraic closure as the only -other sensible alternative) the default ring of a polynomial is the -`DefaultRing' of its coefficients. - -This has an effect on `Factors': If no ring is given, a polynomial is -factorized over its `DefaultRing' and so `Factors()' -might return different results. - -To be safe from this problem, if you are not working over prime fields, -rather call `Factors(,)' with the appropriate polynomial ring -and change your code accordingly. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{The Info Mechanism} - -Sometimes it is useful to get information about the progress of a -calculation. -Many {\GAP} functions contain statements to display such information -under certain conditions. - -In {\GAP}~3, these statements were calls to functions such as -`InfoGroup1' or `InfoGroup2', and if the user assigned `Print' to -these variables then this had the effect to switch on the printing of -information. -`InfoGroup2' was used for more detailed information than `InfoGroup1'. -One could switch off the printing again by assigning `Ignore' to the -variables, and `Ignore' was also the default value. - -{\GAP}~4 uses one function `Info' for the same purpose, -which is a function that takes as first argument an *info class* such as -`InfoGroup', as second argument an *info level*, and the print statements -as remaining arguments. -The level of an info class is set to by calling -`SetInfoLevel( , )'. -An `Info' statement is printed only if its second argument is smaller than -or equal to the current info level. -For example, -\beginexample -gap> test:= function( obj ) -> Info( InfoGroup, 2, "This is useful, isn't it?" ); -> return obj; -> end;; -gap> test( 1 ); -1 -gap> SetInfoLevel( InfoGroup, 2 ); -gap> test( 1 ); -#I This is useful, isn't it? -1 -\endexample - -As in {\GAP}~3, if an info statement is ignored then its arguments are -not evaluated. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\Section{Debugging} - -\indextt{Backtrace} -\indextt{DownEnv} -\indextt{Where} -If {\GAP}~4 runs into an error or is interrupted, -it enters a break loop. -The command `Where( )', which replaces `Backtrace' of {\GAP}~3, -can be used to display lines of information about the current -function call stack. - -As in {\GAP}~3, access is only possible to the variables of the current -level in the function stack, -but in {\GAP}~4 the function `DownEnv', with a positive or negative -integer as argument, permits one to step down or up in the -stack. - -When interrupting, the first line printed by `Where' actually may be -one level higher, as the following example shows -\begintt -gap> OnBreak := function() Where(0); end;; # eliminate back-tracing on -gap> # entry to break loop -gap> test:= function( n ) -> if n > 3 then Error( "!\n" ); fi; test( n+1 ); end;; -gap> test( 1 ); -Error, ! -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue -brk> Where(); - called from -test( n + 1 ); called from -test( n + 1 ); called from -test( n + 1 ); called from -( ) called from read-eval-loop -brk> n; -4 -brk> DownEnv(); -brk> n; -3 -brk> Where(); - called from -test( n + 1 ); called from -test( n + 1 ); called from -( ) called from read-eval-loop -brk> DownEnv( 2 ); -brk> n; -1 -brk> Where(); - called from -( ) called from read-eval-loop -brk> DownEnv( -2 ); -brk> n; -3 -brk> quit; -gap> OnBreak := Where;; # restore OnBreak to its default value -\endtt - -For purposes of debugging, it can be helpful sometimes, to see what -information is stored within an object. In {\GAP}~3 this was possible using -`RecFields' because the objects in question were represented via records. -For component objects, {\GAP}~4 permits the same by -`NamesOfComponents( )', which will list all components present. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% \Section{Compatibility Mode} -% -% For users who want to use {\GAP}~3 code with as little changes as -% possible, a compatibility mode is provided by {\GAP}~4. -% This mode must be turned on explicitly by the user. -% -% It should be noted that this compatibility mode has not been tested -% thoroughly. -% -% The compatibility mode can be turned on by loading some of the following -% files with `ReadLib'. -% The different files address different aspects of compatibility. -% -% \beginitems -% `compat3a.g' & -% makes some {\GAP}~3 function names available that were changed -% in {\GAP}~4, -% and provides code for some {\GAP}~3 features that were -% deliberately left out from the {\GAP}~4 library. -% For example, -% almost all variable names concerning character theory that are -% mentioned in the {\GAP}~3 manual, -% such as `CharTable' and `SubgroupFusions', -% are available after `compat3a.g' has been read; -% the only exceptions are names of operations records. -% -% `compat3b.g' & -% implements the availability of ``components'' of domains; -% besides components that have no meaning for the rest of the {\GAP}~4 -% library, such as `.myInfo', there are components associated to -% attributes; for example `.size' is redirected to the call of the -% attribute `Size', `IsBound( .size )' to the call of its tester, -% and `.size:= ' to the call of its setter. -% (An important special case is the component `operations', see below.) -% -% `compat3c.g' & -% permits you to implement your own elements represented as records, -% and using operations records to provide a `Print' method and -% the basic arithmetic operations. -% When using operations records, it is probably a good idea to -% use *immutable* operations records; for example, if the results -% of arithmetic operations are records with operations records then -% this avoids to create shallow copies of the operations records -% in the call to `Immutable' for the results. -% \enditems -% -% The following features are accessible only via starting {\GAP} with -% the command line option `-O' and may damage some features of {\GAP}~4 -% permanently for the current session. -% -% With this option, also the files listed above are read automatically. -% -% \beginitems -% `compat3d.g' & -% provides some {\GAP}~3 functions like `Domain', simulates the -% {\GAP}~3 behaviour of `IsString' (to convert a list to string -% representation if possible), and replaces `fail' by `false'; -% these changes destroy parts of the functionality of {\GAP}~4. -% \enditems -% -% Some words concerning the simulation of operations records may be -% necessary. -% -% The operations records of the {\GAP}~3 library, such as `DomainOps' -% and `GroupOps', are available *only* for access to their components, -% whose values are {\GAP}~4 operations; for example, the value of both -% `DomainOps.Size' and `GroupOps.Size' is the operation `Size'. So it -% is *not* safely possible to delegate from a `Size' method in another -% operations record to `DomainOps.Size'. Also it is not possible to -% change these predefined operations records. -% -% If one wants to install individual methods for a given object -% via the mechanism of operations records then one can construct a new -% operations record with `OperationsRecord', assign the desired methods -% to components of this record, and then assign the operations record to -% `.operations'. Whenever an operation that is associated with a -% component of the operations record is called with as first -% argument, the value of is chosen as the method. -% -% In the case of the binary operations `=', `\<', `+', `-', `*', `/', -% `Comm', and `LeftQuotient', -% this also happens if is the right-hand argument. -% As in {\GAP}~3, if both arguments of one of the above binary operations -% have operations records containing a function for this operation, -% then the function in the operations record of the right-hand argument -% is chosen. -% -% We give a small example how the compatibility mode works. -% -% Suppose we want to deal with new objects that are derived from known -% field elements by distorting their multiplication. Namely, let $a'$ -% and $b'$ be the new objects corresponding to the field elements $a$, -% $b$, and define $a' \* b' = a b - a - b + 2$. -% -% In {\GAP}~3, this problem was solved by representing each new object -% by a record that stored the corresponding ``old'' object and an -% operations record, where the latter was a record containing the -% functions applicable to the new object. After the library file -% `compat3c.g' has been read, we can use this construction of the -% operations record and of the new objects. Note that operations -% records must be created with the function `OperationsRecord' (this was -% also the norm in {\GAP}~3), starting with an empty record would not work. -% For our intended application, we thus start with the following two -% lines of code. -% -% \begintt -% gap> ReadLib( "compat3c.g" ); -% gap> MyOps:= OperationsRecord( "MyOps" );; -% HasMyOps := NewFilter( "HasMyOps" ); -% \endtt -% -% In order to make the translation from {\GAP}~3 code to {\GAP}~4 -% easier, {\GAP} prints the definition of filters associated with -% operations records and the method installations for operations -% corresponding to components of the operations records. The output -% line printed by {\GAP} after the call of `OperationsRecord' is one -% such case. -% -% Now we add our multiplication function to the operations record, -% and again {\GAP}~4 prints a translation to {\GAP}~4 code. -% -% \begintt -% gap> MyOps.\* := function( a, b ) -% > return rec( x:= a.x * b.x - a.x - b.x + 2, -% > operations := MyOps ); -% > end;; -% # If the following method installation matches the requirements -% # of the operation `PROD' then `InstallMethod' should be used. -% # It might be useful to replace the rank `SUM_FLAGS' by `0'. -% InstallOtherMethod( PROD, -% "for object with `MyOps' as first argument", -% true, -% [ HasMyOps, IsObject ], SUM_FLAGS, -% MyOps.\* ); -% -% # For binary infix operators, a second method is installed -% # for the case that the object with `MyOps' is the right operand; -% # since this case has higher priority in GAP 3, the method is -% # installed with higher rank `SUM_FLAGS + 1'. -% InstallOtherMethod( PROD, -% "for object with `MyOps' as second argument", -% true, -% [ IsObject, HasMyOps ], SUM_FLAGS + 1, -% MyOps.\* ); -% \endtt -% -% Let us look how this installation works. -% -% \begintt -% gap> a:= rec( x:= 3, operations:= MyOps ); -% rec( x := 3, operations := MyOps ) -% gap> b:= rec( x:= 5, operations:= MyOps ); -% rec( x := 5, operations := MyOps ) -% gap> a * b; -% rec( x := 9, operations := MyOps ) -% \endtt -% -% (In more complicated cases, we might run into problems, but this was -% already the case in {\GAP}~3. For example, suppose we want to support -% the multiplication of two operands having different operations -% records; then it is not clear which of the two multiplication -% functions is to be chosen, and in {\GAP}~3, the only way out was to -% change the multiplication functions, in order to make them aware of -% such situations.) -% -% If we are now interested to translate the code to {\GAP}~4 in the -% sense that no compatibility mode is needed, we can use what {\GAP}~4 -% has printed above. (The same example is dealt with in Section ``An -% Example -- Designing Arithmetic Operations'' in the {\GAP}~4 Reference -% Manual.) -% -% The objects will no longer be records with `operations' component. -% Instead of records we may use so-called component objects -% with record-like access to components, -% and instead of the `operations' component, we give the objects a -% type that has the filter `HasMyOps' set. -% \begintt -% HasMyOps := NewFilter( "HasMyOps" ); -% MyType := NewType( NewFamily( "MyFamily" ), -% HasMyOps and IsComponentObjectRep ); -% \endtt -% (More about families and representations in this context can be found -% in the same chapter of the {\GAP}~4 Reference Manual mentioned above.) -% -% The next step is to write a function that creates a new object. -% It may look as follows. -% \begintt -% MyObject := function( val ) -% return Objectify( MyType, rec( x:= val ) ); -% end; -% \endtt -% -% The multiplication function shall return an object with the -% filter `HasMyOp', so we change it as follows. -% \begintt -% gap> MyMult := function( a, b ) -% > return MyObject( x:= a!.x * b!.x - a!.x - b!.x + 2 ); -% > end;; -% \endtt -% Note that the component access for these objects -% works via `!.' instead of `.'; -% further note that no operations record needs to appear here, -% the filter takes its role. -% -% Finally, we install the multiplication for at least one argument -% with the new filter, as had been printed by {\GAP}~4 in the -% session shown above. -% \begintt -% InstallOtherMethod( PROD, -% "for object with `MyOps' as first argument", -% true, -% [ HasMyOps, IsObject ], 0, -% MyMult ); -% -% InstallOtherMethod( PROD, -% "for object with `MyOps' as second argument", -% true, -% [ IsObject, HasMyOps ], 1, -% MyMult ); -% \endtt -% And now the example works (again). -% \begintt -% gap> a:= MyObject( 3 ); -% -% gap> b:= MyObject( 5 ); -% -% gap> a * b; -% -% gap> last!.x -% 9 -% \endtt -% -% We may install a method to print our objects in a nice way; -% we could have done this for the operations record `MyOps' -% in the compatibility mode, -% the printed output would look similar to the following. -% \begintt -% InstallOtherMethod( PRINT_OBJ, -% "for object with `MyOps' as first argument", -% true, -% [ HasMyOps ], 0, -% function( obj ) Print( "MyObject( ", obj!.x, " )" ); end ); -% \endtt -% -% Now the example behaves as follows. -% \begintt -% gap> a; b; a * b; -% MyObject( 3 ) -% MyObject( 5 ) -% MyObject( 9 ) -% \endtt -% -% Maybe now we want to improve the installation. -% The multiplication function we want to use is apparently -% thought only for the case that *both* operands have -% the filter `HasMyOps' (and a component `x'). -% So it is reasonable to replace the two methods for -% the multiplication by one method for which both arguments -% are required to have the filter. -% \begintt -% InstallOtherMethod( PROD, -% "for two objects with `MyOps'", -% true, -% [ HasMyOps, HasMyOps ], 0, -% MyMult ); -% \endtt -% -% At first sight, the {\GAP}~4 approach seems to be much more -% complicated. -% But the last example shows that in {\GAP}~4, -% each method can be installed more specifically for the appropriate -% situation. -% Moreover, it is for example possible to install a method -% for the multiplication of an integer and a `HasMyOps' object; -% note that --contrary to the situation in {\GAP}~3-- -% such a method is independent from already existing methods -% in the sense that these need not be changed when -% new functionality is added. -% -% Another example that uses this part of the compatibility mode can be -% found in the file `tst/compat3.tst' of the {\GAP}~4 distribution. - -\EndOfBook - diff --git a/doc/tut/migrat.xml b/doc/tut/migrat.xml deleted file mode 100644 index cf182c4fc2..0000000000 --- a/doc/tut/migrat.xml +++ /dev/null @@ -1,1227 +0,0 @@ - - - - - - - - -Migrating to &GAP; 4 - -This chapter is intended to give users who have experience with &GAP; 3 -some information about what has changed in &GAP; 4. -

-In particular, it informs about changed command line options -(see ), -the new global variable fail (see ), -some functions that have changed their behaviour -(see ) or their names -(see ), -and some conventions used for variable names (see ). -

-Then the new concepts of &GAP; 4 are sketched, -first that of mutability or immutability (see ), -with the explanation of related changes in functions that copy objects -(see ), -then the concepts of operations and method selection, which are compared -with the use of operations records in &GAP; 3 -(see , , -and ). -

-More local changes affect the concepts of notions of generation -(see ), -of parents (see ), -of homomorphisms (see , -, -and ), -how elements in finitely presented groups are treated -(see ), -how information about progress of computations can be obtained -(see ), -and how one gets information in a break loop -(see ). -

-While a &GAP; 3 compatibility mode is provided -(see ), -its use will disable some of the new features of &GAP; 4. -Also it certainly can only try to provide partial compatibility. -

-For a detailed explanation of the new features and concepts of &GAP; 4, -see the manual Programming in GAP. - - - -

-Changed Command Line Options - -In &GAP; 4, the -l option is used to specify the root directory -(see ) -of the &GAP; distribution, -which is the directory containing the lib and doc subdirectories. -Note that in &GAP; 3 this option was used to specify the path to the -lib directory. -

-The -h option of &GAP; 3 has been removed, -the path(s) for the documentation are deduced automatically in &GAP; 4. -

-The option -g is now used to print information only about full garbage -collections. -The new option -g -g generates information about partial -garbage collections too. - -

- - - -
-Fail - -There is a new global variable -fail instead of false -

- - - -in &GAP; 4. -It is intended as a return value of a function for the case that it -could not perform its task. -For example, Inverse returns fail if it is called with a singular -matrix, and Position returns fail if the second argument is not -contained in the list given as first argument. -

-&GAP; 3 handled such situations by either signalling an error, -for example if it was asked for the inverse of a singular matrix, -or by (mis)using false as return value, as in the example Position. -Note that in the first example, in &GAP; 3 it was necessary to check -the invertibility of a matrix before one could safely ask for its -inverse, which meant that roughly the same work was done twice. - - - -

- - - -
-Changed Functionality - -Some functions that were already available in &GAP; 3 behave -differently in &GAP; 4. This section lists them. -

- - - -The &GAP; 3 manual promised that pnt would be the first entry of the -resulting orbit. This was wrong already there in a few cases, therefore -&GAP; 4 does not promise anything about the ordering of points in an orbit. - - -

- - - -only takes the element g and computes its multiplicative order. -Calling Order with two arguments is permitted only in the -&GAP; 3 compatibility mode, see . -(Note that it does not make sense anymore to specify a group as -first argument w.r.t. which the order of the second argument shall -be computed, see .) - - -

- - - -If obj is not contained in the list list then fail is returned -in &GAP; 4 (see ), whereas false was returned in &GAP; 3. - - -

- - - -In &GAP; 3, this function took either two or three arguments, -the optional argument K being a subgroup of G that stabilizes prop -in the sense that for any element g in G, -either all elements or no element in the coset g * K have the -property prop. -

-The &GAP; 4 function ElementProperty, however, -takes between two and four arguments, -and the subgroup K known from &GAP; 3 has to be entered as the fourth -argument not the third. -(The third argument in the &GAP; 4 function denotes a subgroup U -stabilizing prop in the sense that either all elements or no element -in right cosets U * g have the property prop.) -

-(This discrepancy was discovered only in March 2002, -short before the release of &GAP; 4.3.) - - -

- - - -Objects may appear on the screen in a different way, -depending on whether they are printed by the read eval print loop -or by an explicit call of Print. -The reason is that the read eval print loop calls the operation ViewObj -and not PrintObj, whereas Print calls PrintObj for each of its -arguments. -This permits the installation of methods for printing objects in a short form -in the read eval print loop while retaining Print to display -the object completely. -See also Section . -

-(PrintObj is installed as standard method ViewObj, so it is -not really necessary to have a ViewObj method for an object.) - - -

- - - -In &GAP; 3, PrintTo could be (mis)used to redirect the text -printed by a function (that is, not only the output of a function) -to a file by entering the function call as second argument. -This was used mainly in order to avoid many calls of AppendTo. -In &GAP; 4, this feature has disappeared. -One can use streams (see Chapter ) -instead in order to write files efficiently. - - - -

- - - -
-Changed Variable Names - -AgGroup -ApplyFunc -Backtrace -CharTable -Denominator -DepthVector -Elements -IsBijection -IsFunc -IsMat -IsRec -IsSet -LengthWord -NOfCyc -Numerator -RandomInvertableMat -RecFields -X - -Some functions have changed their name without changing the -functionality. -A -- probably incomplete -- list follows -

- -

-See Section  for a way to make the old names -available again. - -

- - - -
-Naming Conventions - -The way functions are named has been unified in &GAP; 4. -This might help to memorize or even guess names of library functions. -

-If a variable name consists of several words then the first -letter of each word is capitalized. -

-If the first part of the name of a function is a verb then the function -may modify its argument(s) but does not return anything, -for example Append appends the list given as second argument to the -list given as first argument. -Otherwise the function returns an object without changing the arguments, -for example Concatenation returns the concatenation of the lists -given as arguments. -

-If the name of a function contains the word By then the return value is -thought of as built in a certain way from the parts given as arguments. -For example, GroupByGenerators returns a group built from its group -generators, and creating a group as a factor group of a given group -by a normal subgroup can be done by taking the image of -NaturalHomomorphismByNormalSubgroup -(see also ). -Other examples of By functions are GroupHomomorphismByImages and -UnivariateLaurentPolynomialByCoefficients. -

-If the name of a function contains the word Of then the return value is -thought of as information deduced from the arguments. -Usually such functions are attributes -(see  in this Tutorial and ). -Examples are GeneratorsOfGroup, which returns a list of generators for -the group entered as argument, or DiagonalOfMat. -

-For the setter and tester functions of an attribute attr -(see  in this Tutorial -and ) -the names Setattr resp. Hasattr are available. -

-If the name of a function fun1 ends with NC then there is another -function fun2 with the same name except that the NC is missing. -NC stands for no check. -When fun2 is called then it checks whether its arguments are valid, -and if so then it calls fun1. -The functions SubgroupNC and Subgroup are a typical example. -

-The idea is that the possibly time consuming check of the arguments -can be omitted if one is sure that they are unnecessary. -For example, if an algorithm produces generators of the derived subgroup -of a group then it is guaranteed that they lie in the original group; -Subgroup would check this, and SubgroupNC omits the check. -

-Needless to say, all these rules are not followed slavishly, -for example there is one operation Zero instead of two operations -ZeroOfElement and ZeroOfAdditiveGroup. - -

- - - -
-Immutable Objects - -&GAP; 4 supports immutable objects. Such objects cannot be -changed, attempting to do so issues an error. Typically attribute -values are immutable, and also the results of those binary arithmetic -operations where both arguments are immutable, -see Section . -For example, [ 1 .. 100 ] + [ 1 .. 100 ] is a -mutable list and 2 * Immutable( [ 1 .. 100 ] ) is an immutable -list, both are equal to the (mutable) list [ 2, 4 .. 200 ]. -

-There is no way to make an immutable object mutable, one can only -get a mutable copy by ShallowCopy. The other way round, -MakeImmutable makes a (mutable or immutable) object and all its -subobjects immutable; one must be very careful to use MakeImmutable -only for those objects that are really newly created, for such objects -the advantage over Immutable is that no copy is made. -

-More about immutability can be found in Sections  in -this tutorial and . - -

- - - -
-Copy - -StructuralCopy -ShallowCopy -The function Copy of &GAP; 3 is not supported in &GAP; 4. This -function was used to create a copy cop of its argument obj with -the properties that cop and obj had no subobjects in common and -that if two subobjects of obj were identical then also the -corresponding subobjects of cop were identical. -

-The possibility of having immutable objects (see ) can and -should be used to avoid unnecessary copying. -Namely, given an immutable object one needs to copy it only if one wants -to get a modified object, and in such a situation usually it is -sufficient to use ShallowCopy, or at least one knows how deep one must -copy in order to do the changes one has in mind. -

-For example, suppose you have a matrix group, and you want to -construct a list of matrices by modifying the group generators. This -list of generators is immutable, so you call ShallowCopy to get a -mutable list that contains the same matrices. If you only want to -exchange some of them, or to append some other matrices, this shallow -copy is already what you need. So suppose that you are interested in -a list of matrices where some rows are also changed. For that, you -call ShallowCopy for the matrices in question, and you get matrices -whose rows can be changed. If you want to change single entries in -some rows, ShallowCopy must be called to get mutable copies of these -rows. Note that in all these situations there is no danger to change, -i.e., to destroy the original generators of the matrix group. -

-If one needs the facility of the Copy function of &GAP; 3 to get a -copy with the same structure then one can use the new &GAP; 4 -function StructuralCopy. It returns a structural copy that has no -mutable subobject in common with its argument. So if -StructuralCopy is called with an immutable object then this object -itself is returned, and if StructuralCopy is called with a mutable -list of immutable objects then a shallow copy of this list is -returned. -

-Note that ShallowCopy now is an operation. So if you create your -own type of (copyable) objects then you must define what a shallow -copy of these objects is, and install an appropriate method. - -

- - - -
-Attributes vs. Record Components - -In &GAP; 3, many complex objects were represented via records, for -example all domains. Information about these objects was stored in -components of these records. For the user, this was usually not -relevant, since there were functions for computing information about -the objects in question. For example, if one was interested in the -size of a group then one could call Size. -

-But since it was guaranteed that the size of a domain D was stored -as value of the component size, it was allowed to access D.size -if this component was bound, and a check for this was possible via -IsBound( D.size ). -

-In &GAP; 4, only the access via functions is admissible. One reason -is the following basic rule. -

-From the information that a given &GAP; 4 object is for example a -domain, one cannot conclude that this object has a certain -representation. -

-For attributes like Size, &GAP; 4 provides two related functions, -the setter and the tester of the attribute, which can be used to -set an attribute value and to check whether the value of an attribute -is already stored for an object (see also ). For example, if D is a domain in &GAP; 4 then -HasSize( D ) is true if the size of D is already stored, and -false otherwise. In the latter case, if you know that the size of -D is size then you may store it by SetSize( D, size ). -

-Besides the flexibility in the internal representation of objects, -storing information only via function calls has also the advantage -that &GAP; 4 is able to draw conclusions automatically. For example, -as soon as it is stored that a group is nilpotent, it is also stored -that it is solvable, see Chapters  and  -for the details. -

-As a consequence, you cannot put your favourite information into a -domain D by assigning it to a new component like -D.myPrivateInfo. Instead you can introduce a new attribute and -then use its setter, see . - -

- - - -
-Different Notions of Generation - -As in &GAP; 3, a domain in &GAP; 4 is a structured set. -

-The same set can have different structures, for example a field can be -regarded as a ring or as an algebra or vector space over a subfield. -

-In &GAP; 3, however, an object representing a ring did not represent -a field, and an object representing a field did not represent a ring. -One reason for this was that the record component generators was -used to denote the appropriate generators of the domain. For a ring -R, the component R.generators was a list of ring generators, and -for a field F, F.generators was a list of field generators. -

-&GAP; 4 cleans this up, see . It supports -many different notions of generation, for example one can ask for -magma generators of a group or for generators of a field as an additive -group. A subtle but important distinction is that between generators -of an algebra and of an algebra-with-one. -

-So the attributes GeneratorsOfGroup, GeneratorsOfMagma, -GeneratorsOfRing, GeneratorsOfField, GeneratorsOfVectorSpace, -and so on, replace the access to the generators component. - -

- - - -
-Operations Records - -Already in &GAP; 3 there were several functions that were applicable -to many different kinds of objects, for example Size could be -applied to any domain, and the binary infix multiplication * could -be used to multiply two matrices, an integer with a row vector, or a -permutation with a permutation group. This was implemented as -follows. Functions like Size and * tried to find out what -situation was described by its arguments, and then it called a more -specific function to compute the desired information. These more -specific functions, let us call them methods as they are also called -in &GAP; 4, were stored in so-called operations records of the -arguments. -

-For example, every domain in &GAP; 3 was represented as a record, and -the operations record was stored in the record component operations. -If Size was called for the domain then the method to compute the -size of the domain was found as value of the Size component of the -operations record. -

-This was fine for functions taking only one argument, and in principle -it is possible that for those functions an object stored an optimal -method in its operations record. But in the case of more arguments -this is not possible. In a multiplication of two objects in &GAP; 3, -one had to choose between the methods stored in the operations records -of the arguments, and if for example the method stored for the left -operand was called, this method had to handle all possible right -operands. -

-So operations records turned out to be not flexible enough. -In &GAP; 4, operations records are not supported -(see  for a possibility -to use your &GAP; 3 code that utilizes operations records, -at least to some extent). -A detailed description -of the new mechanism to select methods can be found in -Chapter . -

-An important point is that the new mechanism allows &GAP; to take the -relation between arguments into account. So it is possible (and -recommended) to install different methods for different relations -between the arguments. Note that such methods need not do the -extensive argument checking that was necessary in &GAP; 3, because -most of the checks are done already by the method selection mechanism. - -

- - - -
-Operations vs. Dispatcher Functions - -&GAP; 3 functions like Size, CommutatorSubgroup, or -SylowSubgroup did mainly call an appropriate method -(see ) -after they had checked their arguments. -Such functions were -called dispatchers in &GAP; 3. In &GAP; 4, many dispatchers have -been replaced by operations, due to the fact that methods are no -longer stored in operations records (see  for the details). -

-Most dispatchers taking only one argument were treated in a special -way in &GAP; 3, they had the additional task of storing computed -values and using these values in subsequent calls. For example, the -dispatcher Size first checked whether the size of the argument was -already stored, and if so then this value was returned; otherwise a -method was called, the value returned by this method was stored in the -argument, and then returned by Size. -

-In &GAP; 4, computed values of operations that take one argument -(these operations are called attributes) are also stored, only the -mechanism to achieve this has changed, see  -and . -

-So the behaviour of Size is the same in &GAP; 3 and &GAP; 4. But -note that in &GAP; 4, it is not possible to access D.size, -see . -As described in , -&GAP; 4 does not admit bypassing the dispatcher by -calling for example D.operations.Size. This was done in &GAP; 3 -often for efficiency reasons, but the method selection mechanism of -&GAP; 4 is fast enough to make this unnecessary. -

-If you had written your own dispatchers and put your own methods into -existing operations records then this code will not work in &GAP; 4. -See  -and  -for a description of how to define operations -and to install methods. -

-Finally, some functions in &GAP; 3 were hidden in -operations records, e.g., PermGroupOps.MovedPoints. -These functions became proper operations in &GAP; 4. - -

- - - -
-Parents and Subgroups - -In &GAP; 3 there was a strict distinction between parent groups and -subgroups. -The use of the name parent (instead of supergroup) -was chosen to indicate that the parent of an object was more than just -useful information. -In fact the main reason for the introduction of parents was to provide -a common roof for example for all groups of polycyclic words that -belonged to the same PC-presentation, or for all subgroups of a finitely -presented group (see ). -A subgroup was never a parent group, and it was possible to create -subgroups only of parent groups. -

-In &GAP; 4 this common roof is provided already by the concept of -families, see . -Thus it is no longer compulsory to use parent groups at all. -On the other hand, parents may be used in &GAP; 4 to provide -information about an object, for example the normalizer of a group in its -parent group may be stored as an attribute value. -Note that there is no restriction on the supergroup that is set to be -the parent, -it is possible to create a subgroup of -any group, this group then being the parent of the new subgroup. -This permits for example chains of subgroups with respective parents, -of arbitrary length. -

-As a consequence, the Parent command cannot be used in &GAP; 4 to -test whether the two arguments of CommutatorSubgroup fit together, -this is now a question that concerns the relation between the families -of the groups. So the 2-argument version of Parent and the now -meaningless function IsParent have been abolished. - -

- - - -
-Homomorphisms vs. General Mappings - -In &GAP; 3 there had been a confusion between group homomorphisms and -general mappings, as GroupHomomorphismByImages created only a -general mapping that did not store whether it was a mapping. This -caused expensive, unwanted, and unnecessary tests whether the mapping -was in fact a group homomorphism. Moreover, the official -workaround to set some components of the mapping record was quite -unwieldy. -

-In &GAP; 4, GroupHomomorphismByImages checks whether the desired -mapping is indeed a group homomorphism; if so then this property is -stored in the returned mapping, otherwise fail is returned. If you -want to avoid the checks then you can use -GroupHomomorphismByImagesNC. If you want to check whether a general -mapping that respects the group operations is really a group -homomorphism, you can construct it via GroupGeneralMappingByImages -and then call IsGroupHomomorphism for it. (Note that -IsGroupHomomorphism returns true if and only if both -IsGroupGeneralMapping and IsMapping do, so one does in fact check -IsMapping in this case.) -

-There is no function IsHomomorphism in &GAP; 4, -since there are several different operations with respect to which a -mapping can be a homomorphism. - -

- - - -
-Homomorphisms vs. Factor Structures - -If F is a factor structure of G, with kernel N, complete -information about the connection between F and G is provided by -the natural homomorphism. -

-In &GAP; 3, the official way to construct this natural homomorphism -was to create first the factor structure F, and then to call -NaturalHomomorphism with the arguments G and F. -For that, the data necessary to compute the homomorphism was stored in -F when F was constructed. -

-In &GAP; 4, factor structures are not treated in a special way, -in particular they do not store information about a homomorphism. -Instead, the more natural way is taken to construct the natural -homomorphism from G and N by NaturalHomomorphismByNormalSubgroup -if N is a normal subgroup of the group G, -or by NaturalHomomorphismByIdeal if N is an ideal in the ring G. -The factor F can then be accessed as the image of this homomorphism, -and of course G is the preimage and N is the kernel. -

-Note that &GAP; 4 does not guarantee anything about the representation -of the factor F, it may be a permutation group or a polycyclically -presented group or another kind of group. -Also note that a natural homomorphism need not be surjective. -

-A consequence of this change is that &GAP; 4 does not allow you to -construct a natural homomorphism from the groups G and F. -

-The other common type of homomorphism in &GAP; 3, operation -homomorphisms, have been replaced (just a name change) by action -homomorphisms, which are handled in a similar fashion. That is, an -action homomorphism is constructed from an acting group, an action -domain, and a function describing the operation. The permutation -group arising by the induced action is then the image of this -operation homomorphism. -

-The &GAP; 3 function Operation is still supported, under the name Action, -but from the original group and the result of Action it is not -possible to construct the action homomorphism. - -

- - - -
-Isomorphisms vs. Isomorphic Structures - -In &GAP; 3, a different representation of a group could be obtained by -calling AgGroup to get an isomorphic polycyclically presented group, -PermGroup to get an isomorphic permutation group, and so on. -The returned objects stored an isomorphism in the record component -bijection. -

-For the same reason as in , -&GAP; 4 puts emphasis on the isomorphism, -and the isomorphic object in the desired representation can be accessed -as its image. -So you can call IsomorphismPcGroup or IsomorphismPermGroup in order -to get an isomorphism to a polycyclically presented group or a -permutation group, respectively, and then call Image to get the -isomorphic group. -

-Note that the image of an action homomorphism with trivial kernel is -also an isomorphic permutation group, but an action homomorphism need -not be surjective, since it may be easier to define it into the full -symmetric group. -

-Further note that in &GAP; 3, a usual application of isomorphisms to -polycyclically presented groups was to utilize the usually more -effective algorithms for solvable groups. However, the new concept of -polycyclic generating systems in &GAP; 4 makes it possible to apply -these algorithms to arbitrary solvable groups, independent of the -representation. For example, &GAP; 4 can handle polycyclic -generating systems of solvable permutation groups. So in many cases, -a change of the representation for efficiency reasons may be not -necessary any longer. -

-In general IsomorphismFpGroup will define a presentation on generators -chosen by the algorithm. The corresponding elements of the original -group can be obtained by the command -

-PreImagesRepresentative(isofp,i)); -]]> -

-If a presentation in the given generators is needed, the command -IsomorphismFpGroupByGenerators(G, gens) will produce one. - -

- - - -
-Elements of Finitely Presented Groups - -Strictly speaking, &GAP; 3 did not support elements of finitely -presented groups. Instead, the words in abstract generators of -the underlying free groups were (mis)used. This caused problems -whenever calculations with elements were involved, the most obvious -ones being wrong results of element comparisons. Also functions -that should in principle work for any group were not applicable to -finitely presented groups. In effect, a finitely presented group had -to be treated in a special way in &GAP; 3. -

-&GAP; 4 distinguishes free groups and their elements from finitely -presented groups and their elements. Comparing two elements of a -finitely presented group will yield either the correct result or no -result at all. -

-Note that in &GAP; 4, the arithmetic and comparison operations for -group elements do not depend on a context provided by a group that -contains the elements. In particular, in &GAP; 4 it is not -meaningful to call Order( G, g ) for a group G and an element -g. - -

- - - -
-Polynomials - -In &GAP; 3, polynomials were defined over a field. So a polynomial over -GF(3) was different from a polynomial over GF(9), even if the -coefficients were exactly the same. -

-&GAP; 4 defines polynomials only over a characteristic. This makes it -possible for example to multiply a polynomial over GF(3) with a polynomial -over GF(9) without the need to convert the former to the larger field. -

-However it has an effect on the result of DefaultRing for polynomials: -In &GAP; 3 the default ring for a polynomial was the polynomial ring of the -field over which the polynomial was defined. In &GAP; 4 no field is -associated, so (to avoid having to define the algebraic closure as the only -other sensible alternative) the default ring of a polynomial is the -DefaultRing of its coefficients. -

-This has an effect on Factors: If no ring is given, a polynomial is -factorized over its DefaultRing and so Factors(poly) -might return different results. -

-To be safe from this problem, if you are not working over prime fields, -rather call Factors(pring,poly) with the appropriate polynomial ring -and change your code accordingly. - -

- - - -
-The Info Mechanism - -Sometimes it is useful to get information about the progress of a -calculation. -Many &GAP; functions contain statements to display such information -under certain conditions. -

-In &GAP; 3, these statements were calls to functions such as -InfoGroup1 or InfoGroup2, and if the user assigned Print to -these variables then this had the effect to switch on the printing of -information. -InfoGroup2 was used for more detailed information than InfoGroup1. -One could switch off the printing again by assigning Ignore to the -variables, and Ignore was also the default value. -

-&GAP; 4 uses one function Info for the same purpose, -which is a function that takes as first argument an info class such as -InfoGroup, as second argument an info level, and the print statements -as remaining arguments. -The level of an info class class is set to level by calling -SetInfoLevel( class, level ). -An Info statement is printed only if its second argument is smaller than -or equal to the current info level. -

- test:= function( obj ) -> Info( InfoGroup, 2, "This is useful, isn't it?" ); -> return obj; -> end;; -gap> test( 1 ); -1 -gap> SetInfoLevel( InfoGroup, 2 ); -gap> test( 1 ); -#I This is useful, isn't it? -1 -]]> -

-As in &GAP; 3, if an info statement is ignored then its arguments are -not evaluated. - -

- - - -
-Debugging - -Backtrace -DownEnv -Where -If &GAP; 4 runs into an error or is interrupted, -it enters a break loop. -The command Where( number ), which replaces Backtrace of &GAP; 3, -can be used to display number lines of information about the current -function call stack. -

-As in &GAP; 3, access is only possible to the variables of the current -level in the function stack, -but in &GAP; 4 the function DownEnv, with a positive or negative -integer as argument, permits one to step down or up in the -stack. -

-When interrupting, the first line printed by Where actually may be -one level higher, as shown below. -

- OnBreak := function() end;; # eliminate back-tracing on entry to break loop -gap> test:= function( n ) -> if n > 3 then Error( "!\n" ); fi; test( n+1 ); end;; -gap> test( 1 ); -Error, ! -you can enter 'quit;' to quit to outer loop, or -you can enter 'return;' to continue -brk> Where(); -Stack trace: -*[1] Error( "!\n" ); - @ *stdin*:3 - [2] test( n + 1 ); - @ *stdin*:3 - [3] test( n + 1 ); - @ *stdin*:3 - [4] test( n + 1 ); - @ *stdin*:3 -( ) - called from read-eval loop at *errin*:1 -brk> n; -4 -brk> DownEnv(); -brk> n; -3 -brk> Where(); -Stack trace: - [1] Error( "!\n" ); - @ *stdin*:3 -*[2] test( n + 1 ); - @ *stdin*:3 - [3] test( n + 1 ); - @ *stdin*:3 - [4] test( n + 1 ); - @ *stdin*:3 -( ) - called from read-eval loop at *errin*:5 -brk> DownEnv( 2 ); -brk> n; -1 -brk> Where(); -Stack trace: - [1] Error( "!\n" ); - @ *stdin*:3 - [2] test( n + 1 ); - @ *stdin*:3 - [3] test( n + 1 ); - @ *stdin*:3 -*[4] test( n + 1 ); - @ *stdin*:3 -( ) - called from read-eval loop at *errin*:8 -brk> DownEnv( -2 ); -brk> n; -3 -brk> quit; -gap> OnBreak := Where;; # restore OnBreak to its default value -]]> -

-For purposes of debugging, it can be helpful sometimes, to see what -information is stored within an object. In &GAP; 3 this was possible using -RecFields because the objects in question were represented via records. -For component objects, &GAP; 4 permits the same by -NamesOfComponents( object ), which will list all components present. - -

- - - -
-Compatibility Mode - -For users who want to use &GAP; 3 code with as little changes as -possible, a compatibility mode is provided by &GAP; 4. -This mode must be turned on explicitly by the user. -

-It should be noted that this compatibility mode has not been tested -thoroughly. -

-The compatibility mode can be turned on by loading some of the following -files with ReadLib. -The different files address different aspects of compatibility. -

- -compat3a.g - - makes some &GAP; 3 function names available that were changed - in &GAP; 4, - and provides code for some &GAP; 3 features that were - deliberately left out from the &GAP; 4 library. - For example, - almost all variable names concerning character theory that are - mentioned in the &GAP; 3 manual, - such as CharTable and SubgroupFusions, - are available after compat3a.g has been read; - the only exceptions are names of operations records. - -compat3b.g - - implements the availability of components of domains; - besides components that have no meaning for the rest of the &GAP; 4 - library, such as D.myInfo, there are components associated to - attributes; for example D.size is redirected to the call of the - attribute Size, IsBound( D.size ) to the call of its tester, - and D.size:= val to the call of its setter. - (An important special case is the component operations, see below.) - -compat3c.g - - permits you to implement your own elements represented as records, - and using operations records to provide a Print method and - the basic arithmetic operations. - When using operations records, it is probably a good idea to - use immutable operations records; for example, if the results - of arithmetic operations are records with operations records then - this avoids to create shallow copies of the operations records - in the call to Immutable for the results. - - -

-The following features are accessible only via starting &GAP; with -the command line option -O and may damage some features of &GAP; 4 -permanently for the current session. -

- With this option, also the files listed above are read automatically. -

- -compat3d.g - - provides some &GAP; 3 functions like Domain, simulates the - &GAP; 3 behaviour of IsString (to convert a list to string - representation if possible), and replaces fail by false; - these changes destroy parts of the functionality of &GAP; 4. - - -

-Some words concerning the simulation of operations records may be -necessary. -

-The operations records of the &GAP; 3 library, such as DomainOps -and GroupOps, are available only for access to their components, -whose values are &GAP; 4 operations; for example, the value of both -DomainOps.Size and GroupOps.Size is the operation Size. So it -is not safely possible to delegate from a Size method in another -operations record to DomainOps.Size. Also it is not possible to -change these predefined operations records. -

-If one wants to install individual methods for a given object obj -via the mechanism of operations records then one can construct a new -operations record with OperationsRecord, assign the desired methods -to components of this record, and then assign the operations record to -obj.operations. Whenever an operation that is associated with a -component nam of the operations record is called with obj as first -argument, the value of nam is chosen as the method. -

-In the case of the binary operations =, <, +, -, *, /, -Comm, and LeftQuotient, -this also happens if obj is the right-hand argument. -As in &GAP; 3, if both arguments of one of the above binary operations -have operations records containing a function for this operation, -then the function in the operations record of the right-hand argument -is chosen. -

-We give a small example how the compatibility mode works. -

-Suppose we want to deal with new objects that are derived from known -field elements by distorting their multiplication. Namely, let a' -and b' be the new objects corresponding to the field elements a, -b, and define a' * b' = a b - a - b + 2. -

-In &GAP; 3, this problem was solved by representing each new object -by a record that stored the corresponding old object and an -operations record, where the latter was a record containing the -functions applicable to the new object. After the library file -compat3c.g has been read, we can use this construction of the -operations record and of the new objects. Note that operations -records must be created with the function OperationsRecord (this was -also the norm in &GAP; 3), starting with an empty record would not work. -For our intended application, we thus start with the following two -lines of code. -

- ReadLib( "compat3c.g" ); -gap> MyOps:= OperationsRecord( "MyOps" );; -HasMyOps := NewFilter( "HasMyOps" ); -]]> -

-In order to make the translation from &GAP; 3 code to &GAP; 4 -easier, &GAP; prints the definition of filters associated with -operations records and the method installations for operations -corresponding to components of the operations records. The output -line printed by &GAP; after the call of OperationsRecord is one -such case. -

-Now we add our multiplication function to the operations record, -and again &GAP; 4 prints a translation to &GAP; 4 code. -

- MyOps.\* := function( a, b ) -> return rec( x:= a.x * b.x - a.x - b.x + 2, -> operations := MyOps ); -> end;; -# If the following method installation matches the requirements -# of the operation `PROD' then `InstallMethod' should be used. -# It might be useful to replace the rank `SUM_FLAGS' by `0'. -InstallOtherMethod( PROD, - "for object with `MyOps' as first argument", - true, - [ HasMyOps, IsObject ], SUM_FLAGS, - MyOps.\* ); - -# For binary infix operators, a second method is installed -# for the case that the object with `MyOps' is the right operand; -# since this case has higher priority in GAP 3, the method is -# installed with higher rank `SUM_FLAGS + 1'. -InstallOtherMethod( PROD, - "for object with `MyOps' as second argument", - true, - [ IsObject, HasMyOps ], SUM_FLAGS + 1, - MyOps.\* ); -]]> -

-Let us look how this installation works. -

- a:= rec( x:= 3, operations:= MyOps ); -rec( x := 3, operations := MyOps ) -gap> b:= rec( x:= 5, operations:= MyOps ); -rec( x := 5, operations := MyOps ) -gap> a * b; -rec( x := 9, operations := MyOps ) -]]> -

-(In more complicated cases, we might run into problems, but this was -already the case in &GAP; 3. For example, suppose we want to support -the multiplication of two operands having different operations -records; then it is not clear which of the two multiplication -functions is to be chosen, and in &GAP; 3, the only way out was to -change the multiplication functions, in order to make them aware of -such situations.) -

-If we are now interested to translate the code to &GAP; 4 in the -sense that no compatibility mode is needed, we can use what &GAP; 4 -has printed above. (The same example is dealt with in -Chapter .) -

-The objects will no longer be records with operations component. -Instead of records we may use so-called component objects -with record-like access to components, -and instead of the operations component, we give the objects a -type that has the filter HasMyOps set. -

- -

-(More about families and representations in this context can be found -in the chapter of Programming in &GAP; mentioned above.) -

-The next step is to write a function that creates a new object. -It may look as follows. -

- -

-The multiplication function shall return an object with the -filter HasMyOp, so we change it as follows. -

- MyMult := function( a, b ) -> return MyObject( x:= a!.x * b!.x - a!.x - b!.x + 2 ); -> end;; -]]> -

-Note that the component access for these objects -works via !. instead of .; -further note that no operations record needs to appear here, -the filter takes its role. -

-Finally, we install the multiplication for at least one argument -with the new filter, as had been printed by &GAP; 4 in the -session shown above. -

- -

-And now it works (again). -

- a:= MyObject( 3 ); - -gap> b:= MyObject( 5 ); - -gap> a * b; - -gap> last!.x -9 -]]> -

-We may install a method to print our objects in a nice way; -we could have done this for the operations record MyOps -in the compatibility mode, -the printed output would look similar to the following. -

- -

-Now output looks as follows. -

- a; b; a * b; -MyObject( 3 ) -MyObject( 5 ) -MyObject( 9 ) -]]> -

-Maybe now we want to improve the installation. -The multiplication function we want to use is apparently -thought only for the case that both operands have -the filter HasMyOps (and a component x). -So it is reasonable to replace the two methods for -the multiplication by one method for which both arguments -are required to have the filter. -

- -

-At first sight, the &GAP; 4 approach seems to be much more -complicated. -But the last example shows that in &GAP; 4, -each method can be installed more specifically for the appropriate -situation. -Moreover, it is for example possible to install a method -for the multiplication of an integer and a HasMyOps object; -note that --contrary to the situation in &GAP; 3-- -such a method is independent from already existing methods -in the sense that these need not be changed when -new functionality is added. -

-Another example that uses this part of the compatibility mode can be -found in the file tst/compat3.tst of the &GAP; 4 distribution. - - - - - - - - From bdcd086c471065b4c11e7aba8627586fe70d6744 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 11 Jun 2026 09:16:17 +0200 Subject: [PATCH 107/123] Remove SingleCollector_CollectWordRunning (#6426) It does not seem to serve any purpose (anymore?) --- lib/rwspcsng.gi | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/rwspcsng.gi b/lib/rwspcsng.gi index 19cd81bcec..81bfcdb7a3 100644 --- a/lib/rwspcsng.gi +++ b/lib/rwspcsng.gi @@ -71,8 +71,6 @@ DeclareFilter( "IsDefaultRhsTypeSingleCollector" ); ## describing the polycyclic presentation, an exponent vector and a word ## in the corresponding free group. It collects into . ## -SingleCollector_CollectWordRunning := false; - BindGlobal( "SingleCollector_CollectWord", function( sc, v, w ) local cnj, # [g][h] contains g^h for g > h @@ -92,13 +90,7 @@ BindGlobal( "SingleCollector_CollectWord", function( sc, v, w ) tmp, # temporary avc; # g_i .. g_n commutes with g_avc[i]+1 .. g_n - # the collector is not reentrant - if SingleCollector_CollectWordRunning then - SingleCollector_CollectWordRunning := false; - Error( "collector is not reentrant" ); - fi; #Print( "#I using the GAP level single collector\n" ); - SingleCollector_CollectWordRunning := true; # contains the stack of words to insert nw := []; nw[1] := w; @@ -108,7 +100,6 @@ BindGlobal( "SingleCollector_CollectWord", function( sc, v, w ) # if we got the identity return if lw[1] = 0 then - SingleCollector_CollectWordRunning := false; return true; fi; @@ -238,7 +229,6 @@ BindGlobal( "SingleCollector_CollectWord", function( sc, v, w ) fi; fi; od; - SingleCollector_CollectWordRunning := false; return true; end ); From 3e7d4fa9f02d65281c5630782c43527e868066fa Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 11 Jun 2026 13:29:42 +0200 Subject: [PATCH 108/123] kernel: cleanup CRC code (#6436) There was an incorrect comment claiming that SyGAPCRC only ever returns 0 in case of an error. There was also code that looked as if it ensured that (by checking if `crc` is 0 and if so replacing it by 1). But this code in fact was a no-op, and has been one since 1997, when the code was changed to return `crc >> 4` instead of `crc` -- yet both `0 >> 4` and `1 >> 4` are equal to 0. Regarding the other changes: - `(crc >> 8) & 0x00FFFFFFL` is the same as `crc >> 8` since `crc` is an unsigned 32 bit value - removed a comment from the 1990ies suggesting that `SyGAPCRC` should ignore whitespace and comment changes; but we will never do that (as it would be very difficult, break backwards compatibility, and have little practical use) - align right shift in SyGAPCRC and FuncCrcString: one was "emulating" a signed shift, the other didn't. This didn't cause a problem in practice because essentially every compiler in active uses nowadays implements signed right shifts; but the C standard does not require this. Now both use the same branchless emulation code which e.g. clang compiles down into a single instruction (GCC, MSVC, ICC do not, but that's fine, this code is not a bottleneck for anything) --- src/gap.c | 4 +--- src/sysfiles.c | 41 ++++++++++++++++++----------------------- src/sysfiles.h | 3 +-- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/gap.c b/src/gap.c index 711c0eb142..e88bcc8711 100644 --- a/src/gap.c +++ b/src/gap.c @@ -409,7 +409,6 @@ int realmain(int argc, const char * argv[]) { UInt type; // result of compile Obj func; // function (compiler) - Int4 crc; // crc of file to compile // initialize everything and read init.g which runs the GAP session InitializeGap(&argc, argc, argv, 1); @@ -425,12 +424,11 @@ int realmain(int argc, const char * argv[]) if (!CloseInput(&input)) { return 2; } - crc = SyGAPCRC(SyCompileInput); type = CompileFunc( MakeImmString(SyCompileOutput), func, MakeImmString(SyCompileName), - crc, + SyGAPCRC(SyCompileInput), MakeImmString(SyCompileMagic1) ); return ( type == 0 ) ? 1 : 0; } diff --git a/src/sysfiles.c b/src/sysfiles.c index b65033dbe1..98aeb14694 100644 --- a/src/sysfiles.c +++ b/src/sysfiles.c @@ -191,10 +191,7 @@ static ssize_t echoandcheck(int fid, const char *buf, size_t count) ** *F SyGAPCRC( ) . . . . . . . . . . . . . . . . . . crc of a GAP file ** -** This function should be clever and handle white spaces and comments but -** one has to make certain that such characters are not ignored in strings. -** -** This function *never* returns a 0 unless an error occurred. +** This function returns 0 for missing or unreadable files. */ static const UInt4 syCcitt32[ 256 ] = { @@ -248,7 +245,7 @@ Int4 SyGAPCRC( const Char * name ) UInt4 crc; UInt4 old; UInt4 new; - Int4 ch; + Int ch; Int fid; BOOL seen_nl; @@ -273,21 +270,18 @@ Int4 SyGAPCRC( const Char * name ) } else seen_nl = FALSE; - old = (crc >> 8) & 0x00FFFFFFL; - new = syCcitt32[ ( (UInt4)( crc ^ ch ) ) & 0xff ]; + old = crc >> 8; + new = syCcitt32[(crc ^ ch) & 0xff]; crc = old ^ new; } - if ( crc == 0 ) { - crc = 1; - } // and close it again SyFclose( fid ); - // Emulate a signed shift: - if (crc & 0x80000000L) - return (Int4) ((crc >> 4) | 0xF0000000L); - else - return (Int4) (crc >> 4); + + // Emulate a signed shift (the C compiler does not specify whether right + // shifts preserve signs or not; it seems more or less all compilers in + // active use these days do, but better safe than sorry) + return ((Int)((crc >> 4) ^ 0x08000000U)) - 0x08000000; } @@ -320,7 +314,7 @@ static Obj FuncCrcString(Obj self, Obj str) UInt4 new; UInt4 i, len; const Char *ptr; - Int4 ch; + Int ch; BOOL seen_nl; RequireStringRep(SELF_NAME, str); @@ -330,7 +324,7 @@ static Obj FuncCrcString(Obj self, Obj str) crc = 0x12345678L; seen_nl = FALSE; for (i = 0; i < len; i++) { - ch = (Int4)(ptr[i]); + ch = (Int)(ptr[i]); if ( ch == '\377' || ch == '\n' || ch == '\r' ) ch = '\n'; if ( ch == '\n' ) { @@ -341,14 +335,15 @@ static Obj FuncCrcString(Obj self, Obj str) } else seen_nl = FALSE; - old = (crc >> 8) & 0x00FFFFFFL; - new = syCcitt32[ ( (UInt4)( crc ^ ch ) ) & 0xff ]; + old = crc >> 8; + new = syCcitt32[(crc ^ ch) & 0xff]; crc = old ^ new; } - if ( crc == 0 ) { - crc = 1; - } - return INTOBJ_INT(((Int4) crc) >> 4); + + // Emulate a signed shift (the C compiler does not specify whether right + // shifts preserve signs or not; it seems more or less all compilers in + // active use these days do, but better safe than sorry) + return INTOBJ_INT(((Int)((crc >> 4) ^ 0x08000000U)) - 0x08000000); } // Get OS Kernel version. Used to discover if GAP is running inside diff --git a/src/sysfiles.h b/src/sysfiles.h index 046ea30b68..96799788ee 100644 --- a/src/sysfiles.h +++ b/src/sysfiles.h @@ -23,8 +23,7 @@ ** *F SyGAPCRC( ) . . . . . . . . . . . . . . . . . . crc of a GAP file ** -** This function should be clever and handle white spaces and comments but -** one has to certain that such characters are not ignored in strings. +** This function returns 0 for missing or unreadable files. */ Int4 SyGAPCRC(const Char * name); From 13de58c049a955fe0bd5c3a56a4916e99309bddd Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 11 Jun 2026 22:40:12 +0200 Subject: [PATCH 109/123] doc: fix typo (#6438) --- doc/ref/helpintf.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ref/helpintf.xml b/doc/ref/helpintf.xml index 6ed9b9be27..3daccf2773 100644 --- a/doc/ref/helpintf.xml +++ b/doc/ref/helpintf.xml @@ -164,7 +164,7 @@ gap> stream := InputTextFile( file );; This must return a text string or list of text lines which contains the chapter headers of the book info.bookname. -ShowSection( info ) +ShowSections( info ) This must return a text string or list of text lines which contains the section (and chapter) headers of the book info.bookname. From 9627bebc2863092be234739102bf5a77e35b9805 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:20:59 +0200 Subject: [PATCH 110/123] build(deps): bump actions/checkout from 6 to 7 (#6444) Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 6 +++--- .github/workflows/gapjl.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/release.yml | 6 +++--- .github/workflows/update-gh-pages.yml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index e9937fed7f..e2586f8e27 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -141,7 +141,7 @@ jobs: TEST_SUITES: ${{ matrix.test-suites }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: "Set up Python" uses: actions/setup-python@v6 @@ -341,7 +341,7 @@ jobs: - name: Install cross compile dependencies run: sudo apt-get install -q -y libgmp-dev:s390x libreadline-dev:s390x zlib1g-dev:s390x - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - run: ./autogen.sh @@ -407,7 +407,7 @@ jobs: env: AUTOCONF_VERSION: 2.71 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Download required GAP packages run: | diff --git a/.github/workflows/gapjl.yml b/.github/workflows/gapjl.yml index 626f1a52a1..54032f9ed4 100644 --- a/.github/workflows/gapjl.yml +++ b/.github/workflows/gapjl.yml @@ -44,7 +44,7 @@ jobs: steps: - name: Checkout GAP - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: path: 'GAPROOT' - name: "Set up Julia" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index bbf8e68ac8..63eca8aeb6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-slim steps: - name: "Check out the repository" - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: "Set up Python" uses: actions/setup-python@v6 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eb4ce3c91b..8c2b84a1ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,7 +35,7 @@ jobs: name: "Validate release scripts" runs-on: ubuntu-slim steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: "Set up Python" uses: actions/setup-python@v6 @@ -72,7 +72,7 @@ jobs: # requires fetching the entire history. Therefore, we might as well do # that here when checking out the repo, which is what setting fetch-depth # to 0 accomplishes here. - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 0 @@ -207,7 +207,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: "Clone the Windows installer maker scripts" - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: repository: gap-system/gap-windows ref: main diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index e1ebb2c57b..cbafbb0093 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -41,7 +41,7 @@ jobs: sudo apt-get update sudo apt-get install --no-install-recommends "${packages[@]}" - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Configure GAP run: | ./autogen.sh && ./configure From 3df611bc157913272ebbc0d09a31e1cb164ac320 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 23 Jun 2026 11:10:59 +0200 Subject: [PATCH 111/123] Remove InfoData, make INFO_CLASSES readonly (#6443) --- lib/info.gi | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/info.gi b/lib/info.gi index 7436dfa86b..7c873f9661 100644 --- a/lib/info.gi +++ b/lib/info.gi @@ -45,11 +45,7 @@ DeclareRepresentation("IsInfoClassListRep", IsAtomicPositionalObjectRep); # A list of all created InfoClassListReps -INFO_CLASSES := []; - -# InfoData is unused, but we keep it for now, to avoid warnings in GAPDoc. -# TODO: remove InfoData -InfoData := rec(); +BIND_GLOBAL( "INFO_CLASSES", [] ); if IsHPCGAP then ShareInternalObj(INFO_CLASSES); From 951ebaa86f1b4fa5941b1949957a16acdb8b06c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Wed, 24 Jun 2026 15:32:06 +0200 Subject: [PATCH 112/123] Move over changes to the GAP.jl-CI job (#6445) Also treat readline headers as system includes. This avoids Homebrew readline header warnings under --enable-Werror. Co-authored-by: Max Horn Co-authored-by: Codex --- .github/workflows/gapjl.yml | 22 +++++++++++++++++++++- configure.ac | 4 ++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gapjl.yml b/.github/workflows/gapjl.yml index 54032f9ed4..f23b79ddab 100644 --- a/.github/workflows/gapjl.yml +++ b/.github/workflows/gapjl.yml @@ -67,11 +67,31 @@ jobs: - name: "Install dependencies (for macOS)" if: runner.os == 'macOS' run: | - brew install autoconf zlib # gmp pkg-config + # - autoconf, gmp, zlib are needed by GAP's build system + # - coreutils provides nproc + # - force use of Homebrew gcc to build GAP for proper stacktrace support + # Homebrew installs versioned binaries such as gcc-14 and g++-14, + # while later scripts expect unversioned gcc and g++ in PATH. + brew install autoconf gmp zlib gcc@14 coreutils + + # ensure gcc and g++ are available under those names (on macOS, + # these names are aliases for clang / clang++ out of the box) + shimdir="${HOME}/bin" + mkdir -p "${shimdir}" + ln -sf "$(brew --prefix)/bin/gcc-14" "${shimdir}/gcc" + ln -sf "$(brew --prefix)/bin/g++-14" "${shimdir}/g++" + echo "${shimdir}" >> "${GITHUB_PATH}" - name: "Build GAP" run: | mv GAPROOT /tmp/GAPROOT cd /tmp/GAPROOT + patchdir=$GAPJLPATH/.github/workflows/GAP_patches/master + if [ -d $patchdir ]; then + for f in $patchdir/*.patch; do + echo "Applying patch ${f}" + patch -p1 -d . < ${f} + done + fi ./autogen.sh ./configure --enable-Werror make -j`nproc` diff --git a/configure.ac b/configure.ac index 9320f18ce0..10b9b528f8 100644 --- a/configure.ac +++ b/configure.ac @@ -727,12 +727,12 @@ for READLINE_PREFIX in ${READLINE_SEARCH_PATH} ; do [DEFAULTS_EREADLINE],[ dnl ereadline is the name of GNU readline library on OpenBSD READLINE_PREFIX="" - READLINE_CPPFLAGS="-I/usr/local/include/ereadline" + READLINE_CPPFLAGS="-isystem /usr/local/include/ereadline" READLINE_LDFLAGS="" READLINE_LIBS="-lereadline" ], [*],[ - READLINE_CPPFLAGS="-I${READLINE_PREFIX}/include" + READLINE_CPPFLAGS="-isystem ${READLINE_PREFIX}/include" READLINE_LDFLAGS="-L${READLINE_PREFIX}/lib" READLINE_LIBS="-lreadline" ] From 7248631cb7656361e06f7fd4a05ba9cc0bf2fc38 Mon Sep 17 00:00:00 2001 From: Alexander Hulpke Date: Wed, 1 Jul 2026 05:15:02 -0600 Subject: [PATCH 113/123] Perfect groups data is licensed under GPL 2.0 or later (#6450) --- grp/perf13.grp | 2 +- grp/perf14.grp | 2 +- grp/perf15.grp | 2 +- grp/perf16.grp | 2 +- grp/perf17.grp | 2 +- grp/perf18.grp | 2 +- grp/perf19.grp | 2 +- grp/perf20.grp | 2 +- grp/perf21.grp | 2 +- grp/perf22.grp | 2 +- grp/perf23.grp | 2 +- grp/perf24.grp | 2 +- grp/perf25.grp | 2 +- grp/perf26.grp | 2 +- grp/perf28.grp | 2 +- grp/perf29.grp | 2 +- grp/perf30.grp | 2 +- grp/perf31.grp | 2 +- grp/perf32.grp | 2 +- grp/perf34.grp | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/grp/perf13.grp b/grp/perf13.grp index 0f9a715bf9..9a66aacec6 100644 --- a/grp/perf13.grp +++ b/grp/perf13.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[96]:=[# 61440.1 [[1,"abcde", diff --git a/grp/perf14.grp b/grp/perf14.grp index eccd748827..fe20d8d587 100644 --- a/grp/perf14.grp +++ b/grp/perf14.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[111]:=[# 86016.1 [[1,"abcd", diff --git a/grp/perf15.grp b/grp/perf15.grp index 3e466c5c5b..96880d1a09 100644 --- a/grp/perf15.grp +++ b/grp/perf15.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[131]:=[# 122880.1 [[1,"abcdef", diff --git a/grp/perf16.grp b/grp/perf16.grp index 31da9f936f..3d74dd9c6e 100644 --- a/grp/perf16.grp +++ b/grp/perf16.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[150]:=[# 172032.1 [[1,"abc", diff --git a/grp/perf17.grp b/grp/perf17.grp index dce726788d..9f569b8930 100644 --- a/grp/perf17.grp +++ b/grp/perf17.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[179]:=[# 245760.1 [[1,"abcde", diff --git a/grp/perf18.grp b/grp/perf18.grp index e142e995b2..66d6548ebd 100644 --- a/grp/perf18.grp +++ b/grp/perf18.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[200]:=[# 344064.1 [[1,"abcd", diff --git a/grp/perf19.grp b/grp/perf19.grp index abcc2320e7..cbe80ff733 100644 --- a/grp/perf19.grp +++ b/grp/perf19.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[210]:=[# 368640.1 [[1,"abcdef", diff --git a/grp/perf20.grp b/grp/perf20.grp index d9fec32164..d14b2567e8 100644 --- a/grp/perf20.grp +++ b/grp/perf20.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[244]:=[# 491520.1 [[1,"abcde", diff --git a/grp/perf21.grp b/grp/perf21.grp index 5488fdc506..0a723692a3 100644 --- a/grp/perf21.grp +++ b/grp/perf21.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[276]:=[# 688128.1 [[1,"abcde", diff --git a/grp/perf22.grp b/grp/perf22.grp index ab14628e3f..873de9394a 100644 --- a/grp/perf22.grp +++ b/grp/perf22.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later number:=[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 7, 1, 1, 1, 1, 3, 1, 1, 1, 7, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 5, 1, 1, 3, 1, 1, 9, 4, 1, 1, diff --git a/grp/perf23.grp b/grp/perf23.grp index b260d3a331..e7cc9f0523 100644 --- a/grp/perf23.grp +++ b/grp/perf23.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[330]:=[# 983040.1 [[1,"abcdef", diff --git a/grp/perf24.grp b/grp/perf24.grp index 672b2f4d84..b48d5514f9 100644 --- a/grp/perf24.grp +++ b/grp/perf24.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[332]:=[# 1008000.1 [[1,"abcdef", diff --git a/grp/perf25.grp b/grp/perf25.grp index 1e51e86fc2..a3967e1db6 100644 --- a/grp/perf25.grp +++ b/grp/perf25.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[355]:=[# 1180980.1 [[1,"abcde", diff --git a/grp/perf26.grp b/grp/perf26.grp index f7486d8e91..7af1e2a545 100644 --- a/grp/perf26.grp +++ b/grp/perf26.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[371]:=[# 1290240.1 [[1,"abcdefg", diff --git a/grp/perf28.grp b/grp/perf28.grp index 69b0382d26..c9f45efb72 100644 --- a/grp/perf28.grp +++ b/grp/perf28.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[382]:=[# 1382400.1 [[1,"abcdefg", diff --git a/grp/perf29.grp b/grp/perf29.grp index fcffbacfd0..dcdc30b9e0 100644 --- a/grp/perf29.grp +++ b/grp/perf29.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[396]:=[# 1474560.1 [[1,"abcdefg", diff --git a/grp/perf30.grp b/grp/perf30.grp index 09144844f8..948a0c1e02 100644 --- a/grp/perf30.grp +++ b/grp/perf30.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[421]:=[# 1749600.1 [[1,"abcdefgh", diff --git a/grp/perf31.grp b/grp/perf31.grp index ca3418d68a..afc2d69797 100644 --- a/grp/perf31.grp +++ b/grp/perf31.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[435]:=[# 1843200.1 [[1,"abcdef", diff --git a/grp/perf32.grp b/grp/perf32.grp index a33d812d03..ee0f128a89 100644 --- a/grp/perf32.grp +++ b/grp/perf32.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[436]:=[# 1843968.1 [[1,"abcdef", diff --git a/grp/perf34.grp b/grp/perf34.grp index e78fe08416..683173f859 100644 --- a/grp/perf34.grp +++ b/grp/perf34.grp @@ -5,7 +5,7 @@ ## This data was computed by Alexander Hulpke ## It is distributed under the artistic license 2.0 ## https://opensource.org/licenses/Artistic-2.0 -## as well as (dual licensing) under GPL 2 +## as well as (dual licensing) under GPL-2.0-or-later PERFGRP[452]:=[# 1975680.1 [[1,"abcd", From b0c58f75595d7d90394478ce024fdfa81018c338 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 1 Jul 2026 13:17:18 +0200 Subject: [PATCH 114/123] Add an argument check to `CodePcgs` (#6451) --- lib/randiso.gi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/randiso.gi b/lib/randiso.gi index 5331eb51c3..15b1d8c520 100644 --- a/lib/randiso.gi +++ b/lib/randiso.gi @@ -240,6 +240,11 @@ end ); InstallGlobalFunction( CodePcgs, function( pcgs ) local code, indices, l, mi, i, base, nt, r, j, size; + # Check the argument. + if not ( IsPcgs( pcgs ) and IsPrimeOrdersPcgs( pcgs ) ) then + Error( " must be a pcgs in 'IsPrimeOrdersPcgs'" ); + fi; + # basic structures l := Length( pcgs ); if l = 0 then From 2c4fc4334e54319f238a7496672e5245935c5abf Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 1 Jul 2026 14:43:49 +0200 Subject: [PATCH 115/123] kernel: make FormatOutput handle %g with null pointer (#6446) In case someone uses '%g' in a format string but fails to provide a matching argument. Moreover, make sure we don't use `arg2` more then once. --- src/io.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/io.c b/src/io.c index 9484c39a01..eac2600859 100644 --- a/src/io.c +++ b/src/io.c @@ -1513,8 +1513,6 @@ static Obj FuncALL_KEYWORDS(Obj self) ** '%g' the corresponding argument is the address of a T_STRING string ** object which is printed. This is similar to using '%s' to print ** CSTR_STRING(arg), but is safe during garbage collection. -** '%G' the corresponding argument is the address of an Obj which points -** to a string in STRING_REP format which is printed in '%S' format ** '%C' the corresponding argument is the address of an Obj which points ** to a string in STRING_REP format which is printed with C escapes ** '%d' the corresponding argument is a signed integer, which is printed. @@ -1556,7 +1554,7 @@ static inline void FormatOutput( } // handle the case of a missing argument - if (arg1 == 0 && (*p == 's' || *p == 'S' || *p == 'C' || *p == 'I')) { + if (arg1 == 0 && (*p == 's' || *p == 'g' || *p == 'C' || *p == 'I')) { put_a_char(state, '<'); put_a_char(state, 'n'); put_a_char(state, 'u'); @@ -1566,6 +1564,7 @@ static inline void FormatOutput( // on to the next argument arg1 = arg2; + arg2 = 0; } // '%d' print an integer @@ -1591,6 +1590,7 @@ static inline void FormatOutput( // on to the next argument arg1 = arg2; + arg2 = 0; } // '%s' or '%g' print a string @@ -1650,6 +1650,7 @@ static inline void FormatOutput( // on to the next argument arg1 = arg2; + arg2 = 0; } // '%C' print a string with the necessary C escapes @@ -1699,6 +1700,7 @@ static inline void FormatOutput( // on to the next argument arg1 = arg2; + arg2 = 0; } // '%I' print an identifier @@ -1742,12 +1744,14 @@ static inline void FormatOutput( // on to the next argument arg1 = arg2; + arg2 = 0; } // '%c' print a character else if ( *p == 'c' ) { put_a_char(state, (Char)arg1); arg1 = arg2; + arg2 = 0; } // '%%' print a '%' character From 9a9ee6fd62ba5b91ff86dd878200781887d44808 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 1 Jul 2026 15:18:55 +0200 Subject: [PATCH 116/123] turn the global variable `RUN_IN_GGMBI` into a global option `Run_In_GGMBI` (#6442) --- doc/ref/grphomom.xml | 11 ++++++++ grp/glzmodmz.gi | 8 +++--- lib/fitfree.gi | 52 ++++++++++++++++++------------------ lib/grpmat.gi | 6 ++--- lib/grpnice.gd | 3 +++ lib/grpnice.gi | 41 ++++++++++++++++------------ lib/maxsub.gi | 4 +-- lib/oprt.gi | 10 +++---- lib/schursym.gi | 10 +++---- tst/testinstall/ggmbi.tst | 56 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 134 insertions(+), 67 deletions(-) create mode 100644 tst/testinstall/ggmbi.tst diff --git a/doc/ref/grphomom.xml b/doc/ref/grphomom.xml index 9e4536c88a..3878ed73a0 100644 --- a/doc/ref/grphomom.xml +++ b/doc/ref/grphomom.xml @@ -372,6 +372,17 @@ are satisfied. +A technical remark:Run_In_GGMBI + +

+ +In order to avoid infinite recursions when constructing nice monomorphisms, +the global option Run_In_GGMBI is set to true in certain +situations. +The value of this option is checked in methods for the operations + and +. + <#Include Label="IsHandledByNiceMonomorphism"> <#Include Label="NiceMonomorphism"> <#Include Label="NiceObject"> diff --git a/grp/glzmodmz.gi b/grp/glzmodmz.gi index 9271ea6976..97d5e7ca77 100644 --- a/grp/glzmodmz.gi +++ b/grp/glzmodmz.gi @@ -379,7 +379,7 @@ local oper,n,R,o,nrit, if fp <>fail then # extend presentation bas:=Basis(sub,bas); - RUN_IN_GGMBI:=true; + PushOptions( rec( Run_In_GGMBI:= true ) ); hom:=GroupGeneralMappingByImagesNC(g,fp,gens,GeneratorsOfGroup(fp)); hom:=LiftFactorFpHom(hom,g,SubgroupNC(g,basm),rec( pcgs:=basm, @@ -392,7 +392,7 @@ local oper,n,R,o,nrit, return List(Coefficients(bas,e),Int); end )); - RUN_IN_GGMBI:=false; + PopOptions(); #simplify Image to avoid explosion of generator number fp:=Range(hom); if true then @@ -412,11 +412,9 @@ local oper,n,R,o,nrit, k:=TzPreImagesNewGens(e); k:=List(k,x->j[1][Position(OldGeneratorsOfPresentation(e),x)]); - RUN_IN_GGMBI:=true; hom:=GroupHomomorphismByImagesNC(g,fp, k, - GeneratorsOfGroup(fp)); - RUN_IN_GGMBI:=false; + GeneratorsOfGroup(fp) : Run_In_GGMBI:= true ); fi; SetIsomorphismFpGroup(g,hom); diff --git a/lib/fitfree.gi b/lib/fitfree.gi index d68681ea93..2e549bf08f 100644 --- a/lib/fitfree.gi +++ b/lib/fitfree.gi @@ -54,10 +54,10 @@ local ffs,pcisom,rest,kpc,k,x,ker,r,pool,i,xx,pregens,iso; rest:=GroupHomomorphismByImages(U,Range(ffs.factorhom),GeneratorsOfGroup(U), List(GeneratorsOfGroup(U),x->ImagesRepresentative(ffs.factorhom,x))); else - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment rest:=GroupHomomorphismByImagesNC(U,Range(ffs.factorhom),GeneratorsOfGroup(U), List(GeneratorsOfGroup(U),x->ImagesRepresentative(ffs.factorhom,x))); - RUN_IN_GGMBI:=false; + PopOptions(); fi; Assert(1,rest<>fail); @@ -276,9 +276,9 @@ local ffs,hom,U,rest,ker,r,p,l,i,depths,pcisom,subsz,pcimgs; if IsPermGroup(U) and AssertionLevel()>1 then rest:=GroupHomomorphismByImages(U,Range(hom),gens,imgs); else - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment rest:=GroupHomomorphismByImagesNC(U,Range(hom),gens,imgs); - RUN_IN_GGMBI:=false; + PopOptions(); fi; Assert(1,rest<>fail); @@ -319,11 +319,11 @@ local ffs,hom,U,rest,ker,r,p,l,i,depths,pcisom,subsz,pcimgs; else r:=SubgroupNC(G,ipcgs); fi; - RUN_IN_GGMBI:=true; + PushOptions( rec( Run_In_GGMBI:= true ) ); pcisom:=GroupHomomorphismByImagesNC(r, SubgroupNC(Range(ffs.pcisom),pcisom), ipcgs,pcisom); - RUN_IN_GGMBI:=false; + PopOptions(); fi; r:=rec(inducedfrom:=ffs, pcgs:=ipcgs, @@ -919,10 +919,10 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs,gens; sf:=List(GeneratorsOfGroup(Image(fphom)),x->PreImagesRepresentative(fphom,x)); sg:=List(sf,x->PreImagesRepresentative(hom,x)); sp:=[]; - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(Group(sg,One(G)),fp,sg, GeneratorsOfGroup(fp)); - RUN_IN_GGMBI:=false; + PopOptions(); @@ -939,9 +939,9 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs,gens; Append(sp,mpcgs); else # extend presentation - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=LiftFactorFpHom(fphom,Source(fphom),false,mpcgs); - RUN_IN_GGMBI:=false; + PopOptions(); fp:=Image(fphom); sp:=Concatenation(sp,mpcgs); fi; @@ -953,10 +953,10 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs,gens; gens:=GeneratorsOfGroup(ocr.complement); sg:=gens{[1..Length(sg)]}; sp:=gens{[Length(sg)+1..Length(gens)]}; - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(ocr.complement,fp,gens, GeneratorsOfGroup(fp)); - RUN_IN_GGMBI:=false; + PopOptions(); fi; od; @@ -1240,11 +1240,11 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, # now do complements one by one for j in [1..Length(pcgs)] do h:=ClosureGroup(dser[j],gens); - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(h,fp, Concatenation(GeneratorsOfGroup(dser[j]),gens), Concatenation(List(GeneratorsOfGroup(dser[j]),x->One(fp)),imgs)); - RUN_IN_GGMBI:=false; + PopOptions(); ocr:=rec(group:=h,modulePcgs:=pcgs[j], factorfphom:=fphom); @@ -1256,18 +1256,18 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, if Size(b)>Size(s) then h:=ClosureGroup(b,gens); - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(h,fp, Concatenation(GeneratorsOfGroup(b),gens), Concatenation(List(GeneratorsOfGroup(b),x->One(fp)),imgs)); - RUN_IN_GGMBI:=false; + PopOptions(); # get elementary abelian series from b to s dser:=elabser(b,s); pcgs:=List([2..Length(dser)],x->ModuloPcgs(dser[x-1],dser[x])); for j in pcgs do - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=LiftFactorFpHom(fphom,Source(fphom),false,j); - RUN_IN_GGMBI:=false; + PopOptions(); od; gens:=MappingGeneratorsImages(fphom); imgs:=gens[2];gens:=gens[1]; @@ -1325,12 +1325,12 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, # now do complement to NS(k)/k for z in [1..Length(pcgs)] do h:=ClosureGroup(dser[z],cgens); - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(h,fp, Concatenation(GeneratorsOfGroup(dser[z]),cgens), Concatenation(List(GeneratorsOfGroup(dser[z]),x->One(fp)), imgs)); - RUN_IN_GGMBI:=false; + PopOptions(); ocr:=rec(group:=h,modulePcgs:=pcgs[z], factorfphom:=fphom); @@ -1411,10 +1411,10 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs, sf:=List(GeneratorsOfGroup(Image(fphom)),x->PreImagesRepresentative(fphom,x)); sg:=List(sf,x->PreImagesRepresentative(hom,x)); sp:=[]; - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(Group(sg,One(G)),fp,sg, GeneratorsOfGroup(fp)); - RUN_IN_GGMBI:=false; + PopOptions(); for d in [2..Length(ser.depths)] do mran:=[ser.depths[d-1]..len]; @@ -1429,9 +1429,9 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs, Append(sp,mpcgs); else # extend presentation - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=LiftFactorFpHom(fphom,Source(fphom),false,mpcgs); - RUN_IN_GGMBI:=false; + PopOptions(); fp:=Image(fphom); sp:=Concatenation(sp,mpcgs); fi; @@ -1443,10 +1443,10 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs, gens:=GeneratorsOfGroup(ocr.complement); sg:=gens{[1..Length(sg)]}; sp:=gens{[Length(sg)+1..Length(gens)]}; - RUN_IN_GGMBI:=true; # hack to skip Nice treatment + PushOptions( rec( Run_In_GGMBI:= true ) ); # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(ocr.complement,fp,gens, GeneratorsOfGroup(fp)); - RUN_IN_GGMBI:=false; + PopOptions(); fi; od; diff --git a/lib/grpmat.gi b/lib/grpmat.gi index fa6128959f..86dcc4a815 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -424,13 +424,11 @@ local field, dict, acts, start, j, zerov, zero, dim, base, partbas, heads, SetRange(hom,R); SetImagesSource(hom,R); SetMappingGeneratorsImages(hom,[acts,permimg]); -# p:=RUN_IN_GGMBI; # no niceomorphism translation here -# RUN_IN_GGMBI:=true; +# # no niceomorphism translation here # SetAsGroupGeneralMappingByImages ( hom, GroupHomomorphismByImagesNC -# ( G, R, acts, permimg ) ); +# ( G, R, acts, permimg : Run_In_GGMBI:= true ) ); # # SetFilterObj( hom, IsActionHomomorphismByBase ); -# RUN_IN_GGMBI:=p; if act=OnRight or act=OnPoints then # only store for action on right. projective action needs is own call to # `LinearActionBase' as this will set other needed parameters. diff --git a/lib/grpnice.gd b/lib/grpnice.gd index 5a9480fd86..c813ee5f63 100644 --- a/lib/grpnice.gd +++ b/lib/grpnice.gd @@ -189,6 +189,9 @@ InstallSubsetMaintenance( IsHandledByNiceMonomorphism, IsHandledByNiceMonomorphism and IsGroup, IsGroup); +# We recommend the (documented) global option `Run_In_GGMBI` +# instead of the global variable `RUN_IN_GGMBI`, +# but `RUN_IN_GGMBI` is still supported because GAP packages might use it. RUN_IN_GGMBI:=false; # If somebody would call `GHBI' to make a # NiceMonomorphism, we would get an infinite recursion. # This flag can be set to avoid GHBIs to be translated diff --git a/lib/grpnice.gi b/lib/grpnice.gi index f72d348e81..c7ed3a5a34 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -927,16 +927,22 @@ InstallMethod( GroupGeneralMappingByImagesNC, "from a group handled by a niceomorphism",true, [ IsGroup and IsHandledByNiceMonomorphism, IsGroup, IsList, IsList ], 0, function( G, H, gens, imgs ) -local nice,geni,map2,tmp; - if RUN_IN_GGMBI=true then +local nice,geni,map2; + if ValueOption( "Run_In_GGMBI" ) = true then + TryNextMethod(); + elif RUN_IN_GGMBI = true then + # Code was called that does not know about the global option. + # Make it work but print a warning. + Info( InfoWarning, 1, + "use the global option 'Run_In_GGMBI' not the global variable ", + "'RUN_IN_GGMBI', see '?Run_In_GGMBI'" ); TryNextMethod(); fi; - tmp := RUN_IN_GGMBI; - RUN_IN_GGMBI:=true; + PushOptions( rec( Run_In_GGMBI:= true ) ); nice:=RestrictedNiceMonomorphism(G); geni:=List(gens,i->ImageElm(nice,i)); map2:=GroupGeneralMappingByImagesNC(NiceObject(G),H,geni,imgs); - RUN_IN_GGMBI:=tmp; + PopOptions(); return CompositionMapping(map2,nice); end ); @@ -956,18 +962,20 @@ InstallMethod( AsGroupGeneralMappingByImages, [IsGroupGeneralMapping and IsNiceMonomorphism], {} -> RankFilter( IsHandledByNiceMonomorphism ), function(hom) -local h, tmp; - # we actually want to use the next method with `RUN_IN_GGMBI' set to + # we actually want to use the next method with `Run_In_GGMBI' set to # `true'. Therefore we redispatch, but will skip this method the second # time. - if RUN_IN_GGMBI=true then + if ValueOption( "Run_In_GGMBI" ) = true then + TryNextMethod(); + elif RUN_IN_GGMBI = true then + # Code was called that does not know about the global option. + # Make it work but print a warning. + Info( InfoWarning, 1, + "use the global option 'Run_In_GGMBI' not the global variable ", + "'RUN_IN_GGMBI', see '?Run_In_GGMBI'" ); TryNextMethod(); fi; - tmp := RUN_IN_GGMBI; - RUN_IN_GGMBI:=true; - h:=AsGroupGeneralMappingByImages(hom); - RUN_IN_GGMBI:=tmp; - return h; + return AsGroupGeneralMappingByImages( hom : Run_In_GGMBI:= true ); end); ############################################################################# @@ -979,12 +987,11 @@ InstallMethod( PreImagesRepresentative, "for PBG-Niceo", [ IsPreimagesByAsGroupGeneralMappingByImages and IsNiceMonomorphism, IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) -local p, tmp; +local p; # avoid the double dispatch for `AsGroupGeneralMappingByImages' - tmp := RUN_IN_GGMBI; - RUN_IN_GGMBI:=true; + PushOptions( rec( Run_In_GGMBI:= true ) ); p:=PreImagesRepresentative( AsGroupGeneralMappingByImages( hom ), elm ); - RUN_IN_GGMBI:=tmp; + PopOptions(); return p; end ); diff --git a/lib/maxsub.gi b/lib/maxsub.gi index e04c94eaa5..5c823e4fd9 100644 --- a/lib/maxsub.gi +++ b/lib/maxsub.gi @@ -219,10 +219,8 @@ BindGlobal("MaximalSubgroupClassesSol",function(G) # if necessary extent the fphom if homliftlevel+1 START_TEST( "ggmbi.tst" ); + +# Test the situations where the global option 'Run_In_GGMBI' occurs. +# - Print warnings when the deprecated global variable is used. +# (Do not use groups that are larger than their natural modules, +# since they could be cached.) +gap> G:= Group( [ [ 0, -1 ], [ 1, 0 ] ] );; +gap> nice:= NiceMonomorphism( G );; +gap> RUN_IN_GGMBI:= true;; +gap> AsGroupGeneralMappingByImages( nice );; +#I use the global option 'Run_In_GGMBI' not the global variable 'RUN_IN_GGMBI', see '?Run_In_GGMBI' +#I use the global option 'Run_In_GGMBI' not the global variable 'RUN_IN_GGMBI', see '?Run_In_GGMBI' +gap> G:= Group( [ [ 0, -1 ], [ 1, 0 ] ] );; +gap> gens:= GeneratorsOfGroup( G );; +gap> IsHandledByNiceMonomorphism( G ); +true +gap> GroupGeneralMappingByImagesNC( G, G, gens, gens );; +#I use the global option 'Run_In_GGMBI' not the global variable 'RUN_IN_GGMBI', see '?Run_In_GGMBI' +gap> RUN_IN_GGMBI:= false;; + +# - Run some examples where the option gets set, +# and where no other tests were available. +gap> G:= GL( IsPermGroup, 2, 5 );; +gap> U:= SL( IsPermGroup, 2, 5 );; +gap> Size( FittingFreeSubgroupSetup( G, U ).ker ); +2 + +# +gap> G:= Image( IsomorphismPermGroup( SchurCover( AlternatingGroup( 6 ) ) ) );; +gap> Size( SylowViaRadical( G, 3 ) ); +27 + +# +gap> G:= GL( IsPermGroup, 2, 5 );; +gap> Length( HallViaRadical( G, [ 2 ] ) ); +1 +gap> Length( HallViaRadical( G, [ 3 ] ) ); +1 + +# +gap> G:= SymmetricGroup( 5 );; +gap> Size( Source( EpimorphismSchurCover( G ) ) ); +240 +gap> G:= AlternatingGroup( 5 );; +gap> Size( Source( EpimorphismSchurCover( G ) ) ); +120 + +# +gap> G:= Group( Z(3) * [ [ [ 1, 1 ], [ 0, 1 ] ] ] );; +gap> Size( Image( SparseActionHomomorphism( G, +> Elements( GF(3)^2 ), [ Z(3) * [ 1, 0 ] ], OnRight ) ) ); +6 + +# +gap> STOP_TEST( "ggmbi.tst" ); From 54bf057cc5ef8e4648bfaa40e1ae0e0682bb2979 Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Wed, 1 Jul 2026 09:42:08 -0700 Subject: [PATCH 117/123] Document the encoding used by CodePcGroup & PcGroupCode (#6441) --- lib/randiso.gd | 77 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/lib/randiso.gd b/lib/randiso.gd index 2a33d8b415..5f66f30e93 100644 --- a/lib/randiso.gd +++ b/lib/randiso.gd @@ -21,13 +21,63 @@ DeclareAttribute( "OmegaAndLowerPCentralSeries", IsGroup ); ## ## ## -## returns the code corresponding to pcgs. +## returns the non-negative integer code corresponding to the finite pcgs +## pcgs, which must be in . +## The code stores the relative orders of pcgs and +## the right hand sides of the nontrivial power and commutator relations +## of the pc presentation defined by pcgs. This integer encoding of +## pc groups underlies the group construction method described in +## . +##

+## More precisely, let +## g_1,\ldots,g_l be the entries of pcgs, and let +## r_1,\ldots,r_l be their relative orders. If l=0, +## the code is 0. Otherwise put +## m = \max_i r_i - 1. If the relative orders are not all equal, +## the first l base m digits are +## r_1-2,\ldots,r_l-2, so the relative order part is +## \sum_{i=1}^l (r_i-2)m^{l-i}. If the relative orders are all +## equal, this part is omitted; on decoding the relative orders are then +## read from the factorisation of the supplied group order. +##

+## After the relative order part comes a bit mask of length +## l(l+1)/2-1. The bits, from least significant to most +## significant, correspond first to the power relations +## g_1^{r_1},\ldots,g_{l-1}^{r_{l-1}}, and then to the +## commutators [g_j,g_i] for +## 1 \leq i < j \leq l, ordered by increasing i and, for +## fixed i, increasing j. A bit is 1 exactly when +## the corresponding right hand side is nontrivial. The final power +## relation g_l^{r_l}=1 is not stored separately. +##

+## The nontrivial right hand sides, in the same order as their set bits, +## are stored as base |G| digits, where G is the group +## generated by pcgs. If +## x = g_1^{e_1} \cdots g_l^{e_l}, with +## 0 \leq e_i < r_i, then the digit for x is +## \sum_{i=1}^l e_i\prod_{k=i+1}^l r_k. Equivalently, this is +## the zero-based position of x in the canonical list +## g_1^{e_1}\cdots g_l^{e_l}, ordered according to the +## lexicographic order of the tuples e_1,\dots,e_l. +##

+## Thus if b is m^l when the relative order part is present +## and 1 otherwise, if u is the bit mask, and if +## a_1,\ldots,a_t are the digits for the nontrivial right hand +## sides, then the complete code is +## A + b(u + 2^{l(l+1)/2-1}(a_1 + |G|a_2 + \cdots + +## |G|^{t-1}a_t)), where A is the relative order part, or +## 0 if that part is omitted. ## G := CyclicGroup(512);; +## gap> G := CyclicGroup(8);; ## gap> p := Pcgs( G );; ## gap> CodePcgs( p ); -## 162895587718739690298008513020159 +## 323 ## ]]> +## In this example the relative orders are [2,2,2], so there is +## no relative order part. The nontrivial power tails are g_2 +## and g_3, with digits 2 and 1 in the canonical +## list. Hence the code is +## 1 + 2 + 2^5(2 + 8\cdot 1) = 323. ## ## ## <#/GAPDoc> @@ -43,11 +93,15 @@ DeclareGlobalFunction( "CodePcgs" ); ## ## ## -## returns the code for a pcgs of G. +## returns the code for the pcgs returned by Pcgs for G. +## The encoding is the one described for . ## G := DihedralGroup(512);; -## gap> CodePcGroup( G ); -## 2940208627577393070560341803949986912431725641726 +## gap> G := CyclicGroup(8);; +## gap> code := CodePcGroup( G ); +## 323 +## gap> H := PcGroupCode( code, Size( G ) );; +## gap> IsCyclic( H ) and Size( H ) = Size( G ); +## true ## ]]> ## ## @@ -69,6 +123,15 @@ DeclareGlobalFunction( "CodePcGroup" ); ## otherwise anything may happen. ## Valid codes are usually obtained by one of the functions ## or . +## The inverse construction uses the integer format described for +## . The length of the pcgs, and in the case where +## all relative orders are equal also the relative orders themselves, are +## recovered from the prime factorisation of size. +##

+## The same integer format is also used by Magma's +## SmallGroupEncoding and SmallGroupDecoding, and by +## OSCAR's encode for pc groups and +## pc_group( order, code ). ## G := SmallGroup( 24, 12 );; ## gap> p := Pcgs( G );; From e4dab6525c1423b69156834655dae77f2152e6b1 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 30 Apr 2026 15:04:45 +0100 Subject: [PATCH 118/123] examples for Matrix --- lib/matobj2.gd | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 6a153401e2..6ff3dee12f 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1790,6 +1790,185 @@ DeclareOperation( "CompanionMatrix", [ IsUnivariatePolynomial, IsSemiring ] ); +############################################################################# +## +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , ) +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , ) +#O Matrix( ) +#O Matrix( , ) +#O Matrix( , , ) +#O Matrix( , , , ) +#O Matrix( , , ) +## +## <#GAPDoc Label="MatObj_Matrix"> +## +## Matrix +## +## +## +## +## +## +## a matrix object +## +## If a semiring R is given as the first argument then +## a matrix object is returned whose +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the matrix object +## matobj, respectively. +## Here list can be either a list of plain lists that describe the +## entries of the rows, or a flat list of the entries in row major order, +## where ncols defines the number of columns. +##

+## In those cases where the last argument is a matrix object, +## the first argument is a list or a matrix object +## that defines (together with ncols if applicable) the entries of +## the result, and the +## and +## of the last argument +## are taken for the result. +##

+## If only a list list and perhaps ncols is given +## then both the +## and the +## are guessed from +## the list. +##

+## In the remaining cases a filter filt is given as the +## first argument and a matrix object is returned that has +## +## value filt, is defined over the base domain R, +## and has the entries given by the list list or the matrix object +## M, respectively. +##

+## If the global option check is set to false then +## +## need not perform consistency checks. +##

+## If the +## value of the result implies then the result is +## mutable if and only if the argument that determines the entries of the +## result (list or matobj) is mutable. +##

+## In the case of a mutable result, it is guaranteed that the given list +## list is copied in the sense of , +## and if list is a nested list then it is not guaranteed +## that also the entries of list are copied. +##

+## Default methods for +## +## delegate to . +## m1 := Matrix( Integers, [ [3,4,5], [6,7,8] ] );; Print( m1 ); +## NewMatrix(IsPlistMatrixRep,Integers,3,[ [ 3, 4, 5 ], [ 6, 7, 8 ] ]) +## gap> m2 := Matrix( Rationals, [10..30], 7 );; Display( m2 ); +## <3x7-matrix over Rationals: +## [[ 10 .. 16 ] +## [ 17 .. 23 ] +## [ 24 .. 30 ] +## ]> +gap> Print( Matrix( Integers, m2 ) ); +NewMatrix(IsPlistMatrixRep,Integers,7, +[ [ 10 .. 16 ], [ 17 .. 23 ], [ 24 .. 30 ] ]) +gap> m3 := Matrix( [[7,6],[4,3]], m2 );; Print(m3); +NewMatrix(IsPlistMatrixRep,Rationals,2,[ [ 7, 6 ], [ 4, 3 ] ]) +gap> m4 := Matrix( [-7..-2], 3, m2 );; Print(m4); +NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ -7, -6, -5 ], [ -4, -3, -2 ] ]) +gap> m0 := [[-1,-2],[-3,-4]];; IsMatrix(m0); +true +gap> Print( Matrix( m0, m1 ) ); +NewMatrix(IsPlistMatrixRep,Integers,2,[ [ -1, -2 ], [ -3, -4 ] ]) +gap> Print( Matrix( [-9..-4], 3, m1 ) ); +NewMatrix(IsPlistMatrixRep,Integers,3,[ [ -9, -8, -7 ], [ -6, -5, -4 ] ]) +gap> m5 := Matrix( [ [0,1,2], [7,8,9] ] );; Print( m5 ); +NewMatrix(IsPlistMatrixRep,Rationals,3,[ [ 0, 1, 2 ], [ 7, 8, 9 ] ]) +gap> m6 := Matrix( IsGF2MatrixRep, GF(2), [[1,0,1],[0,1,0]]*Z(2)^0 );; +gap> Display( m6 ); + 1 . 1 + . 1 . +gap> m7 := Matrix( IsZmodnZMatrixRep, ZmodnZ(8), [1..6], 3 ); + +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsList ] ); +DeclareOperation( "Matrix", [ IsOperation, IsSemiring, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsList ] ); +DeclareOperation( "Matrix", [ IsSemiring, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj ] ); +DeclareOperation( "Matrix", [ IsList, IsInt ] ); +DeclareOperation( "Matrix", [ IsList ]); + + +############################################################################ +## +#A CompatibleVector( ) +## +## <#GAPDoc Label="CompatibleVector"> +## +## +## +## a vector object +## +## +## Called with a matrix object M with m rows, +## this operation returns a mutable zero vector object v of length +## m and in the representation given by the +## value +## of M (provided that such a representation exists). +##

+## The idea is that there should be an efficient way to +## form the product vM. +## +## +## <#/GAPDoc> +## +DeclareOperation( "CompatibleVector", [ IsMatrixOrMatrixObj ] ); + + +############################################################################ +## +#A RowsOfMatrix( ) +## +## <#GAPDoc Label="RowsOfMatrix"> +## +## +## +## a plain list +## +## +## Called with a matrix object M, this operation +## returns a plain list of objects in the representation given by the +## value +## of M (provided that such a representation exists), +## where the i-th entry describes the i-th row of the input. +## +## +## <#/GAPDoc> +## +## This function is used for creating an isomorphic permutation group +## of a matrix group that consists of matrix objects. +## +## +## We assume that the matrix knows how to create suitable vector objects; +## entering a template vector as the second argument is not an option +## in this situation. +## +DeclareAttribute( "RowsOfMatrix", IsMatrixOrMatrixObj ); + + ############################################################################# ## #F DefaultVectorRepForBaseDomain( ) From a2108fb3eefffd9a10940f359949d07ef2add64b Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 6 May 2026 02:43:15 +0200 Subject: [PATCH 119/123] Add `RandomMatrix`, `RandomInvertibleMatrix`; and fix a problem with a new feature for matrix groups (#6232) - add a description of the cache `FULLGLNICOCACHE` in the code; it is used only by `NicomorphismFFMatGroupOnFullSpace` - change the keys of `FULLGLNICOCACHE`: take the field of the matrix entries into account (not only its size), take the `ConstructingFilter` of the matrices into account - in `NicomorphismFFMatGroupOnFullSpace`, deal with special cases of matrices in `IsBlockMatrixRep` (which have no `ConstructingFilter`) and in `Is8BitMatrixRep` in the situation that the group itself lives over `GF(2)` - in order to admit the action of `IsMatrixObj` matrices on vectors supported by GAP's `Enumerator`s of vector spaces, add a `\^` method that `Unpack`s the matrix object (Eventually we want to avoid this overhead, but then we need `Enumerator`s consisting of vector objects corresponding to the matrix objects.) - add `Matrix` calls in the function that computes preimages under an action homomorphism with `Source` a matrix group, in order to support matrix group elements of prescribed kinds of `IsMatrixObj`. - add tests for the new supported situations (most of the changes were actually forced by already available tests) * add `\in` methods for matrix object and (`GL` or `SL`) * avoid some `Unpack` hacks - introduce `NormedRowVectors_internal( F, base )`, and `AsListOfFreeLeftModule_internal( F, base, zero )`, in order to admit `IsVectorObj`s in `base` without supporting the whole vector space machinery for these objects - introduce `ExternalSet( G )` for matrix groups `G`, meaning the natural `G`-set (an undocumented method for permutation groups `G` was already available) - change `NicomorphismFFMatGroupOnFullSpace` such that we can act with the `IsMatrixObj` matrices on their `IsVectorObj` vectors, without unpacking the matrices - support `IsMatrixObj` matrices in the `Random` methods for GL and SL * adjust also `IsProjectiveActionHomomorphism` methods * add `RandomMatrix`, `RandomInvertibleMatrix` and fix the `RankMat` method for `IsPlistMatrixRep` --- tst/testinstall/grpmat.tst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index eea0eb9834..8ac7e4db9e 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -107,5 +107,21 @@ true gap> IsSubset( Source( nice2 ), G2 ); true +# 'NiceMonomorphism' behaves well w.r.t. 'ConstructingFilter' +gap> G:= SP( 4, 2 );; +gap> nice:= NiceMonomorphism( G );; +gap> G2:= SP( 4, 2 : ConstructingFilter:= IsPlistMatrixRep );; +gap> nice2:= NiceMonomorphism( G2 );; +gap> IsPlistMatrixRep( One( G ) ); +false +gap> IsPlistMatrixRep( One( G2 ) ); +true +gap> IsIdenticalObj( nice, nice2 ); +false +gap> IsSubset( Source( nice ), G ); +true +gap> IsSubset( Source( nice2 ), G2 ); +true + # gap> STOP_TEST( "grpmat.tst" ); From 6af878f7f86c328405516f99b2df3686ccb3a3e9 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 7 May 2026 13:09:51 +0100 Subject: [PATCH 120/123] added examples for 26.13 and 26.14 --- lib/matobj.gi | 3 ++- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/matobj.gi b/lib/matobj.gi index 83807f6fb5..c2302ec5bf 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1155,8 +1155,9 @@ InstallMethod( MultVectorRight, ## gap> m4 := Matrix( Integers, [ [3,5], [4,7] ] );; ## gap> Print( m3 * m4 ); ## NewMatrix(IsPlistMatrixRep,Integers,2,[ [ 7, 12 ], [ 4, 7 ] ]) -## gap> Unpack( m3 * m4 ); Unpack( m3^6 ); Unpack( m4^-1 ); +## gap> Unpack( m3 * m4 ); ## [ [ 7, 12 ], [ 4, 7 ] ] +## gap> Unpack( m3^6 ); Unpack( m4^-1 ); ## [ [ 1, 6 ], [ 0, 1 ] ] ## [ [ 7, -5 ], [ -4, 3 ] ] ## ]]> diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 445c4d82e8..897430ac91 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -10,7 +10,6 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] - # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -18,7 +17,6 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true - # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) > From 3adf59bef89aa3aa0ede013a85f56a59209fa243 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 7 May 2026 14:55:59 +0100 Subject: [PATCH 121/123] added examples for 26.13 and 26.14 --- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 897430ac91..445c4d82e8 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -10,6 +10,7 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] + # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -17,6 +18,7 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true + # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) > From ce4d933f90b7fc93e7e6f2297cb0d51fbdbb67d0 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 19:07:28 +0100 Subject: [PATCH 122/123] remove blank lines in test file --- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 2 -- 1 file changed, 2 deletions(-) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 445c4d82e8..897430ac91 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -10,7 +10,6 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] - # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -18,7 +17,6 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true - # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) > From f64b904e8a37676bac4b0f42b0af80f34b1435e7 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Fri, 8 May 2026 20:08:28 +0100 Subject: [PATCH 123/123] finding it hard to fix ExtractSubMatrix.tst --- tst/testinstall/MatrixObj/ExtractSubMatrix.tst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 897430ac91..445c4d82e8 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -10,6 +10,7 @@ gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); gap> m2 := IdentityMatrix( Integers, 4 );; gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); [ [ 0, 1 ], [ 1, 0 ] ] + # IsGF2MatrixRep gap> m1 := IdentityMatrix( GF(2), 100 ); @@ -17,6 +18,7 @@ gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); gap> IsOne(m2); true + # Is8BitMatrixRep gap> m1 := IdentityMatrix( GF(3), 100 ); < mutable compressed matrix 100x100 over GF(3) >