From 7e47c83cffa9d1eb5512ba078799bd27294e3020 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 1 Sep 2026 10:23:02 +0100 Subject: [PATCH 01/10] removing files superceded by utils0-.tst --- doc/groups.xml | 27 ++++++------ doc/iterator.xml | 26 ++++++++++- doc/matrix.xml | 10 ++++- tst/gslp.tst | 3 ++ tst/iterator.tst | 100 ------------------------------------------- tst/lists.tst | 109 ----------------------------------------------- tst/manual.g | 24 +++++++++++ tst/matrix.tst | 80 ---------------------------------- tst/number.tst | 80 ---------------------------------- tst/others.tst | 79 ---------------------------------- tst/print.tst | 48 --------------------- tst/record.tst | 65 ---------------------------- 12 files changed, 74 insertions(+), 577 deletions(-) delete mode 100644 tst/iterator.tst delete mode 100644 tst/lists.tst create mode 100755 tst/manual.g delete mode 100644 tst/matrix.tst delete mode 100644 tst/number.tst delete mode 100644 tst/others.tst delete mode 100644 tst/print.tst delete mode 100644 tst/record.tst diff --git a/doc/groups.xml b/doc/groups.xml index e253ca7..2218f74 100644 --- a/doc/groups.xml +++ b/doc/groups.xml @@ -401,24 +401,25 @@ The first of these is the zero map, the last is the identity.

gens := [ (1,2,3,4), (1,2)(3,4) ];; -gap> d8 := Group( gens );; -gap> SetName( d8, "d8" ); +gap> d8 := Group( gens );; SetName( d8, "d8" ); gap> c2 := Subgroup( d8, [ (2,4) ] );; gap> SortedList( IdempotentEndomorphismsWithImage( gens, c2 ) ); [ [ (), (2,4) ], [ (2,4), () ] ] gap> data:= IdempotentEndomorphismsData( d8 );; -gap> data.images[1]; -[ [ (), () ] ] -gap> List( data.images, Length ); -[ 1, 2, 2, 2, 2, 1 ] +gap> data.images; +[ [ [ (), () ] ], [ [ (), (2,4) ], [ (2,4), () ] ], + [ [ (), (1,3) ], [ (1,3), () ] ], + [ [ (), (1,2)(3,4) ], [ (1,2)(3,4), (1,2)(3,4) ] ], + [ [ (), (1,4)(2,3) ], [ (1,4)(2,3), (1,4)(2,3) ] ], + [ [ (1,2,3,4), (1,2)(3,4) ] ] ] gap> all:= IdempotentEndomorphisms( d8 );; -gap> Length( all ); -10 -gap> all[1]; -[ (1,2,3,4), (1,2)(3,4) ] -> [ (), () ] -gap> Size( Image( all[1] ) ); -1 -gap> Last( all ) = IdentityMapping( d8 ); +gap> allim := List( all, m -> MappingGeneratorsImages(m)[2] );; +gap> ## the list of 10 sets of images sorted: +gap> allimpairs := +> [ [ (), () ], [ (), (2,4) ], [ (2,4), () ], [ (), (1,3) ], [ (1,3), () ], +> [ (), (1,2)(3,4) ], [ (1,2)(3,4), (1,2)(3,4) ], [ (), (1,4)(2,3) ], +> [ (1,4)(2,3), (1,4)(2,3) ], [ (1,2,3,4), (1,2)(3,4) ] ];; +gap> ForAll( allim, m -> ( m in allimpairs ) ); true ]]> diff --git a/doc/iterator.xml b/doc/iterator.xml index 9eba053..d3109a8 100644 --- a/doc/iterator.xml +++ b/doc/iterator.xml @@ -2,7 +2,7 @@ - + @@ -51,9 +51,13 @@ gap> AllIsomorphisms( G, s3 ); [ [ f1, f2 ] -> [ (6,7), (5,6,7) ], [ f1, f2 ] -> [ (5,7), (5,6,7) ], [ f1, f2 ] -> [ (5,6), (5,7,6) ], [ f1, f2 ] -> [ (6,7), (5,7,6) ], [ f1, f2 ] -> [ (5,7), (5,7,6) ], [ f1, f2 ] -> [ (5,6), (5,6,7) ] ] -gap> iter := AllIsomorphismsIterator( G, s3 );; gap> for h in iter do Print( ImageElm( h, G.1 ) = (6,7), ", " ); od; true, false, false, true, false, false, +gap> s4 := Group( (1,2),(2,3),(3,4) );; +gap> AllIsomorphismsNumber( s3, s4 ); +0 +gap> AllIsomorphisms( s3, s4 ); +[ ] ]]> @@ -156,6 +160,24 @@ gap> NextIterator( pairs4 ); gap> IsDoneIterator( pairs4 ); true ]]> + +Some trivial cases: + iter0 := IteratorList( [ ] );; +gap> iter4 := IteratorList( [ 4 ] );; +gap> cart := CartesianIterator( iter0, iter0 );; +gap> IsDoneIterator( cart ); +true +gap> cart := CartesianIterator( iter0, iter4 );; +gap> IsDoneIterator( cart ); +true +gap> cart := CartesianIterator( iter4, iter0 );; +gap> IsDoneIterator( cart ); +true +gap> pairs0 := UnorderedPairsIterator( iter0 );; +gap> IsDoneIterator( pairs0 ); +true +]]> diff --git a/doc/matrix.xml b/doc/matrix.xml index 13f7433..894c044 100644 --- a/doc/matrix.xml +++ b/doc/matrix.xml @@ -2,7 +2,7 @@ - + @@ -83,6 +83,14 @@ gap> Display( M8 ); gap> L8 := DirectSumDecompositionMatrices( M8 );; gap> Length( L8 ); 16 + +gap> M3 := [ [0,0,7,0,0,0,0], [0,0,0,8,0,0,0], [0,0,0,0,9,0,0] ];; +gap> Display( M3 ); +[ [ 0, 0, 7, 0, 0, 0, 0 ], + [ 0, 0, 0, 8, 0, 0, 0 ], + [ 0, 0, 0, 0, 9, 0, 0] ] +gap> L3 := DirectSumDecompositionMatrices( M3 ); +[ [ [ [ 0, 0, 7 ] ], [ [ 8 ] ], [ [ 9, 0, 0 ] ] ] ] ]]>

diff --git a/tst/gslp.tst b/tst/gslp.tst index 5d4f7bf..b2ec1a9 100644 --- a/tst/gslp.tst +++ b/tst/gslp.tst @@ -5,6 +5,9 @@ ## #Y Copyright (C) 2026, The GAP Group ## +## +## some tests other than those in the manual + gap> START_TEST( "gslp.tst" ); # diff --git a/tst/iterator.tst b/tst/iterator.tst deleted file mode 100644 index 36a8799..0000000 --- a/tst/iterator.tst +++ /dev/null @@ -1,100 +0,0 @@ -#@local c3c3, cart, G, h, it1, it2, iter, iter0, iter4, iterL -#@local L, n, pairs0, pairs4, pairsL, s3, s4 - -############################################################################## -## -#W iterator.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 7.1.1 -gap> G := DihedralGroup(6);; -gap> s3 := Group( (5,6), (6,7) );; -gap> iter := AllIsomorphismsIterator( G, s3 );; -gap> NextIterator( iter ); -[ f1, f2 ] -> [ (6,7), (5,6,7) ] -gap> n := AllIsomorphismsNumber( G, s3 ); -6 -gap> AllIsomorphisms( G, s3 ); -[ [ f1, f2 ] -> [ (6,7), (5,6,7) ], [ f1, f2 ] -> [ (5,7), (5,6,7) ], - [ f1, f2 ] -> [ (5,6), (5,7,6) ], [ f1, f2 ] -> [ (6,7), (5,7,6) ], - [ f1, f2 ] -> [ (5,7), (5,7,6) ], [ f1, f2 ] -> [ (5,6), (5,6,7) ] ] -gap> iter := AllIsomorphismsIterator( G, s3 );; -gap> for h in iter do Print( ImageElm( h, G.1 ) = (6,7), ", " ); od; -true, false, false, true, false, false, -gap> s4 := Group( (1,2),(2,3),(3,4) );; -gap> AllIsomorphismsNumber( s3, s4 ); -0 -gap> AllIsomorphisms( s3, s4 ); -[ ] - -## SubSection 7.1.2 -gap> c3c3 := Group( (1,2,3), (4,5,6) );; -gap> iter := AllSubgroupsIterator( c3c3 ); - -gap> while not IsDoneIterator(iter) do Print(NextIterator(iter),"\n"); od; -Group( () ) -Group( [ (4,5,6) ] ) -Group( [ (1,2,3) ] ) -Group( [ (1,2,3)(4,5,6) ] ) -Group( [ (1,3,2)(4,5,6) ] ) -Group( [ (4,5,6), (1,2,3) ] ) - -## Subsection 7.2.1 -gap> it1 := Iterator( [ 1, 2, 3 ] );; -gap> it2 := Iterator( [ 4, 5, 6 ] );; -gap> iter := CartesianIterator( it1, it2 );; -gap> while not IsDoneIterator(iter) do Print(NextIterator(iter),"\n"); od; -[ 1, 4 ] -[ 1, 5 ] -[ 1, 6 ] -[ 2, 4 ] -[ 2, 5 ] -[ 2, 6 ] -[ 3, 4 ] -[ 3, 5 ] -[ 3, 6 ] -gap> ## try some trivial cases -gap> iter0 := IteratorList( [ ] );; -gap> iter4 := IteratorList( [ 4 ] );; -gap> cart := CartesianIterator( iter0, iter0 );; -gap> IsDoneIterator( cart ); -true -gap> cart := CartesianIterator( iter0, iter4 );; -gap> IsDoneIterator( cart ); -true -gap> cart := CartesianIterator( iter4, iter0 );; -gap> IsDoneIterator( cart ); -true - -## Subsection 6.2.2 -gap> L := [6,7,8,9];; -gap> iterL := IteratorList( L );; -gap> pairsL := UnorderedPairsIterator( iterL );; -gap> while not IsDoneIterator(pairsL) do Print(NextIterator(pairsL),"\n"); od; -[ 6, 6 ] -[ 6, 7 ] -[ 7, 7 ] -[ 6, 8 ] -[ 7, 8 ] -[ 8, 8 ] -[ 6, 9 ] -[ 7, 9 ] -[ 8, 9 ] -[ 9, 9 ] -gap> iter4 := IteratorList( [ 4 ] ); - -gap> pairs4 := UnorderedPairsIterator(iter4); - -gap> NextIterator( pairs4 ); -[ 4, 4 ] -gap> IsDoneIterator( pairs4 ); -true -gap> pairs0 := UnorderedPairsIterator( iter0 );; -gap> IsDoneIterator( pairs0 ); -true diff --git a/tst/lists.tst b/tst/lists.tst deleted file mode 100644 index 6407a69..0000000 --- a/tst/lists.tst +++ /dev/null @@ -1,109 +0,0 @@ -#@local C, c4, d16, gens, i, J, K, L, n, P, trans - -############################################################################## -## -#W lists.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 3.1.1 -gap> List( [1..12], n->n^3 ); -[ 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331, 1728 ] -gap> DifferencesList( last ); -[ 7, 19, 37, 61, 91, 127, 169, 217, 271, 331, 397 ] -gap> DifferencesList( last ); -[ 12, 18, 24, 30, 36, 42, 48, 54, 60, 66 ] -gap> DifferencesList( last ); -[ 6, 6, 6, 6, 6, 6, 6, 6, 6 ] -gap> L := [ 0 ];; -gap> DifferencesList( L ); -[ ] -gap> L := [ ];; -gap> DifferencesList( L ); -[ ] - -## SubSection 3.1.2 -gap> List( [0..10], n -> Factorial(n) ); -[ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800 ] -gap> QuotientsList( last ); -[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] -gap> L := [ 1, 3, 5, -1, -3, -5 ];; -gap> QuotientsList( L ); -[ 3, 5/3, -1/5, 3, 5/3 ] -gap> FloatQuotientsList( L ); -[ 3., 1.66667, -0.2, 3., 1.66667 ] -gap> QuotientsList( [ 2, 1, 0, -1, -2 ] ); -[ 1/2, 0, fail, 2 ] -gap> FloatQuotientsList( [1..10] ); -[ 2., 1.5, 1.33333, 1.25, 1.2, 1.16667, 1.14286, 1.125, 1.11111 ] -gap> Product( last ); -10. - -## SubSection 3.1.3 -gap> L := [1..20];; L[1]:=13;; -gap> for i in [1..19] do -> if IsOddInt(L[i]) then L[i+1]:=3*L[i]+1; else L[i+1]:=L[i]/2; fi; -> od; -gap> L; -[ 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4 ] -gap> SearchCycle( L ); -[ 1, 4, 2 ] -gap> n := 1;; L := [n];; -gap> for i in [1..100] do n:=(n^2+1) mod 1093; Add(L,n); od; -gap> L; -[ 1, 2, 5, 26, 677, 363, 610, 481, 739, 715, 795, 272, 754, 157, 604, 848, - 1004, 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004, 271, - 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004, 271, 211, 802, 521, - 378, 795, 272, 754, 157, 604, 848, 1004, 271, 211, 802, 521, 378, 795, 272, - 754, 157, 604, 848, 1004, 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, - 848, 1004, 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004, - 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004 ] -gap> C := SearchCycle( L ); -[ 157, 604, 848, 1004, 271, 211, 802, 521, 378, 795, 272, 754 ] -gap> P := Positions( L, 157 ); -[ 14, 26, 38, 50, 62, 74, 86, 98 ] -gap> Length( C ); DifferencesList( P ); -12 -[ 12, 12, 12, 12, 12, 12, 12 ] - -## SubSection 3.1.4 -## this manual example not tested as answers vary from run to run -## gap> RandomCombination( [1..49], 6 ); -## [ 3, 5, 21, 24, 27, 31 ] - - -## SubSection 3.2.1 -gap> J := [ [1,2,3], [3,4], [3,4], [1,2,4] ];; -gap> DistinctRepresentatives( J ); -[ 1, 3, 4, 2 ] -gap> K := [ [3,4], [1,2], [2,3], [2,3,4] ];; -gap> CommonRepresentatives( J, K ); -[ [ 3, 3, 3, 1 ], [ 1, 3, 4, 2 ] ] -gap> d16 := DihedralGroup( IsPermGroup, 16 ); SetName( d16, "d16" ); -Group([ (1,2,3,4,5,6,7,8), (2,8)(3,7)(4,6) ]) -gap> c4 := Subgroup( d16, [ d16.1^2 ] ); SetName( c4, "c4" ); -Group([ (1,3,5,7)(2,4,6,8) ]) -gap> RightCosets( d16, c4 ); -[ RightCoset(c4,()), RightCoset(c4,(2,8)(3,7)(4,6)), RightCoset(c4,(1,8,7,6,5, - 4,3,2)), RightCoset(c4,(1,8)(2,7)(3,6)(4,5)) ] -gap> trans := CommonTransversal( d16, c4 ); -[ (), (2,8)(3,7)(4,6), (1,2,3,4,5,6,7,8), (1,2)(3,8)(4,7)(5,6) ] -gap> IsCommonTransversal( d16, c4, trans ); -true - -## SubSection 3.3.1 -gap> gens := GeneratorsOfGroup( DihedralGroup(12) ); -[ f1, f2, f3 ] -gap> String( gens ); -"[ f1, f2, f3 ]" -gap> BlankFreeString( gens ); -"[f1,f2,f3]" - -############################################################################# -## -#E lists.tst . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/manual.g b/tst/manual.g new file mode 100755 index 0000000..e8aedd6 --- /dev/null +++ b/tst/manual.g @@ -0,0 +1,24 @@ +## utils.g +LoadPackage("utils"); +Print( "running utils01.tst\n" ); +Test( "tst/utils01.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils02.tst\n" ); +Test( "tst/utils02.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils03.tst\n" ); +Test( "tst/utils03.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils04.tst\n" ); +Test( "tst/utils04.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils05.tst\n" ); +Test( "tst/utils05.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils06.tst\n" ); +Test( "tst/utils06.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils07.tst\n" ); +Test( "tst/utils07.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils08.tst\n" ); +Test( "tst/utils08.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils09.tst\n" ); +Test( "tst/utils09.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils10.tst\n" ); +Test( "tst/utils10.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils11.tst\n" ); +Test( "tst/utils11.tst", rec(compareFunction := "uptowhitespace") ); diff --git a/tst/matrix.tst b/tst/matrix.tst deleted file mode 100644 index 78da41d..0000000 --- a/tst/matrix.tst +++ /dev/null @@ -1,80 +0,0 @@ -#@local M6, L6, M4, L4, M8, L8, L, A, M3, L3, M5, L5; -############################################################################## -## -#W matrix.tst Utils Package -## -#Y Copyright (C) 2015-2023, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 9.1.1 -gap> M6 := [ [1,2,0,0,0,0], [3,4,0,0,0,0], [5,6,0,0,0,0], -> [0,0,9,0,0,0], [0,0,0,1,2,3], [0,0,0,4,5,6] ];; -gap> Display( M6 ); -[ [ 1, 2, 0, 0, 0, 0 ], - [ 3, 4, 0, 0, 0, 0 ], - [ 5, 6, 0, 0, 0, 0 ], - [ 0, 0, 9, 0, 0, 0 ], - [ 0, 0, 0, 1, 2, 3 ], - [ 0, 0, 0, 4, 5, 6 ] ] -gap> L6 := DirectSumDecompositionMatrices( M6 ); -[ [ [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ], [ [ 9 ] ], [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] - ] ] - -gap> M4 := [ [0,3,0,0], [0,0,0,0], [0,0,0,0], [0,0,4,0] ];; -gap> Display( M4 ); -[ [ 0, 3, 0, 0 ], - [ 0, 0, 0, 0 ], - [ 0, 0, 0, 0 ], - [ 0, 0, 4, 0 ] ] -gap> L4 := DirectSumDecompositionMatrices( M4 ); -[ [ [ [ 0, 3 ] ], [ [ 0, 0 ], [ 0, 0 ], [ 4, 0 ] ] ], - [ [ [ 0, 3 ], [ 0, 0 ] ], [ [ 0, 0 ], [ 4, 0 ] ] ], - [ [ [ 0, 3 ], [ 0, 0 ], [ 0, 0 ] ], [ [ 4, 0 ] ] ] ] -gap> for L in L4 do -> A := DirectSumMat( L );; -> if ( A = M4 ) then Print( "yes, A = M4\n" ); fi; -> od; -yes, A = M4 -yes, A = M4 -yes, A = M4 - -gap> M8 := DirectSumMat( M4, M4 );; -gap> Display( M8 ); -[ [ 0, 3, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 4, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 3, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 4, 0 ] ] -gap> L8 := DirectSumDecompositionMatrices( M8 );; -gap> Length( L8 ); -16 - -gap> M3 := [ [0,0,0,7,0,0,0], [0,0,0,0,8,0,0], [0,0,0,0,0,9,0] ];; -gap> Display( M3 ); -[ [ 0, 0, 0, 7, 0, 0, 0 ], - [ 0, 0, 0, 0, 8, 0, 0 ], - [ 0, 0, 0, 0, 0, 9, 0 ] ] -gap> L3 := DirectSumDecompositionMatrices( M3 ); -[ [ [ [ 0, 0, 0, 7 ] ], [ [ 8 ] ], [ [ 9, 0 ] ] ] ] - -gap> M5 := [ [1,2,0,0,0], [3,4,0,0,0], [0,0,0,0,0], -> [0,0,0,6,7], [0,0,0,8,9] ];; -gap> Display(M5); -[ [ 1, 2, 0, 0, 0 ], - [ 3, 4, 0, 0, 0 ], - [ 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 6, 7 ], - [ 0, 0, 0, 8, 9 ] ] -gap> L5 := DirectSumDecompositionMatrices( M5 ); -[ [ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 0 ] ], [ [ 6, 7 ], [ 8, 9 ] ] ] ] - -############################################################################# -## -#E matrix.tst . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/number.tst b/tst/number.tst deleted file mode 100644 index b61c7b8..0000000 --- a/tst/number.tst +++ /dev/null @@ -1,80 +0,0 @@ -#@local i, iter, n, p, sum - -############################################################################## -## -#W number.tst Utils Package Stefan Kohl -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 4.1.1 -gap> AllSmoothIntegers( 3, 1000 ); -[ 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 54, 64, 72, 81, 96, - 108, 128, 144, 162, 192, 216, 243, 256, 288, 324, 384, 432, 486, 512, 576, - 648, 729, 768, 864, 972 ] -gap> AllSmoothIntegers( [5,11,17], 1000 ); -[ 1, 5, 11, 17, 25, 55, 85, 121, 125, 187, 275, 289, 425, 605, 625, 935 ] -gap> Length( last ); -16 -gap> List( [3..20], n -> Length( AllSmoothIntegers( [5,11,17], 10^n ) ) ); -[ 16, 29, 50, 78, 114, 155, 212, 282, 359, 452, 565, 691, 831, 992, 1173, - 1374, 1595, 1843 ] - -## SubSection 4.1.2 -gap> AllProducts([1..4],3); -[ 1, 2, 3, 4, 2, 4, 6, 8, 3, 6, 9, 12, 4, 8, 12, 16, 2, 4, 6, 8, 4, 8, 12, - 16, 6, 12, 18, 24, 8, 16, 24, 32, 3, 6, 9, 12, 6, 12, 18, 24, 9, 18, 27, - 36, 12, 24, 36, 48, 4, 8, 12, 16, 8, 16, 24, 32, 12, 24, 36, 48, 16, 32, - 48, 64 ] -gap> Set(last); -[ 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 64 ] -gap> AllProducts( [(1,2,3),(2,3,4)], 2 ); -[ (2,4,3), (1,2)(3,4), (1,3)(2,4), (1,3,2) ] - -## SubSection 4.1.3 -gap> RestrictedPartitions( 20, [4..10] ); -[ [ 4, 4, 4, 4, 4 ], [ 5, 5, 5, 5 ], [ 6, 5, 5, 4 ], [ 6, 6, 4, 4 ], - [ 7, 5, 4, 4 ], [ 7, 7, 6 ], [ 8, 4, 4, 4 ], [ 8, 6, 6 ], [ 8, 7, 5 ], - [ 8, 8, 4 ], [ 9, 6, 5 ], [ 9, 7, 4 ], [ 10, 5, 5 ], [ 10, 6, 4 ], - [ 10, 10 ] ] -gap> RestrictedPartitionsWithoutRepetitions( 20, [4..10] ); -[ [ 10, 6, 4 ], [ 9, 7, 4 ], [ 9, 6, 5 ], [ 8, 7, 5 ] ] -gap> RestrictedPartitionsWithoutRepetitions( 10^2, List([1..10], n->n^2 ) ); -[ [ 100 ], [ 64, 36 ], [ 49, 25, 16, 9, 1 ] ] - -## SubSection 4.1.4 -gap> n := 2^251;; -gap> NextProbablyPrimeInt( n ); -3618502788666131106986593281521497120414687020801267626233049500247285301313 - -## SubSection 4.1.6 -gap> iter := PrimeNumbersIterator();; -gap> for i in [1..100] do p := NextIterator(iter); od; -gap> p; -541 -gap> sum := 0;; -gap> ## "prime number race" 1 vs. 3 mod 4 -gap> for p in PrimeNumbersIterator() do -> if p <> 2 then sum := sum + E(4)^(p-1); fi; -> if sum > 0 then break; fi; -> od; -gap> p; -26861 - -## this final example takes quite a while: use examples/number.g -## gap> sum := 0;; -## gap> ## "prime number race" 1 vs. 5 mod 8 -## gap> for p in PrimeNumbersIterator() do -## > if p mod 8 in [1,5] then sum := sum + E(4)^((p-1)/2); fi; -## > if sum > 0 then break; fi; -## > od; -## gap> p; -## 588067889 - -############################################################################# -## -#E number.tst . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/others.tst b/tst/others.tst deleted file mode 100644 index 4a07480..0000000 --- a/tst/others.tst +++ /dev/null @@ -1,79 +0,0 @@ -#@local a, F2, f, g, relq8, q8, M, s1, n1, n2, N, s2; -############################################################################ -## -#W others.tst Utils Package -## -#Y Copyright (C) 2015-2025, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 10.1.1 -## this manual example is not tested to avoid creating files triv.* -## gap> LogTo( "triv.log" ); -## gap> a := 33^5; -## 39135393 -## gap> LogTo(); -## gap> Log2HTML( "triv.log" ); - -## SubSection 10.2.1 -gap> IntOrInfinityToLaTeX( 10^3 ); -"1000" -gap> IntOrInfinityToLaTeX( infinity ); -"\\infty" - -## SubSection 10.2.2 -gap> LaTeXStringFactorsInt( Factorial(12) ); -"2^{10} \\cdot 3^5 \\cdot 5^2 \\cdot 7 \\cdot 11" - -## SubSection 10.3.1 -gap> ## permutation groups -gap> ConvertToMagmaInputString( Group( (1,2,3,4,5), (3,4,5) ) ); -"PermutationGroup<5|(1,2,3,4,5),\n(3,4,5)>;\n" -gap> ConvertToMagmaInputString( Group( (1,2,3,4,5) ), "c5" ); -"c5 := PermutationGroup<5|(1,2,3,4,5)>;\n" -gap> ## pc-group -gap> ConvertToMagmaInputString( DihedralGroup( IsPcGroup, 10 ) ); -"PolycyclicGroup< f1,f2 |\nf1^2,\nf2^5,\nf2^f1 = f2^4\n>;\n" -gap> ## fp-group -gap> F2 := FreeGroup( 2 );; -gap> f := F2.1;; g := F2.2;; -gap> relq8 := [ f^4, g^4, f*g*f*g^-1, f^2*g^2 ];; -gap> q8 := F2/relq8;; -gap> ConvertToMagmaInputString( q8 ); -no conversion function yet available for fp-groups -fail -gap> ## matrix group -gap> M := GL(2,5);; Size(M); -480 -gap> s1 := ConvertToMagmaInputString( M ); -"F := GF(5);\nP := GL(2,F);\ngens := [\nP![2,0,0,1],\nP![4,1,4,0]\n];\nsub

;\n" -gap> Print( s1 ); -F := GF(5); -P := GL(2,F); -gens := [ -P![2,0,0,1], -P![4,1,4,0] -]; -sub

; -gap> n1 := [ [ Z(9)^0, Z(9)^0 ], [ Z(9)^0, Z(9) ] ];; -gap> n2 := [ [ Z(9)^0, Z(9)^3 ], [ Z(9)^4, Z(9)^2 ] ];; -gap> N := Group( n1, n2 );; Size( N ); -5760 -gap> s2 := ConvertToMagmaInputString( N, "gpN" );; -gap> Print( s2 ); -F := GF(3^2); -P := GL(2,F); -w := PrimitiveElement(F); -gens := [ -P![ 1, 1, 1,w^1], -P![ 1,w^3, 2,w^2] -]; -gpN := sub

; - -############################################################################# -## -#E others.tst . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/print.tst b/tst/print.tst deleted file mode 100644 index 5a8a57b..0000000 --- a/tst/print.tst +++ /dev/null @@ -1,48 +0,0 @@ -#@local L, s5 - -############################################################################## -## -#W print.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 2.1.1 -gap> L := List( [1..20], n -> n^5 );; -gap> PrintSelection( L, [18..20] ); -18 : 1889568 -19 : 2476099 -20 : 3200000 -gap> PrintSelection( L, 2, 9 ); -2 : 32 -11 : 161051 -20 : 3200000 -gap> PrintSelection( L, 2, 3, 11 ); -2 : 32 -5 : 3125 -8 : 32768 -11 : 161051 -gap> s5 := SymmetricGroup( 5 );; -gap> PrintSelection( s5, [30,31,100,101] ); -30 : (1,5)(3,4) -31 : (1,5,2) -100 : (1,4,3) -101 : (1,4)(3,5) -gap> PrintSelection( s5, 1, 30 ); -1 : () -31 : (1,5,2) -61 : (1,2,3) -91 : (1,3,5,2,4) -gap> PrintSelection( s5, 9, 11, 43 ); -9 : (2,5,3) -20 : (2,4) -31 : (1,5,2) -42 : (1,5,2,3,4) - -############################################################################# -## -#E print.tst . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/record.tst b/tst/record.tst deleted file mode 100644 index 8799aef..0000000 --- a/tst/record.tst +++ /dev/null @@ -1,65 +0,0 @@ -#@local r, defaults, PrintDimensions, mydim - -############################################################################## -## -#W record.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 8.1.1 -gap> r := rec( a := 1, b := 2, c := 3 );; -gap> AssignGlobals( r ); -The following global variables have been assigned: -[ "a", "b", "c" ] -gap> [ a, b, c ]; -[ 1, 2, 3 ] - -## SubSection 8.2.1 -gap> defaults := rec( a := 1, b := 2, c := 3 );; -gap> OptionRecordWithDefaults( defaults, rec( a := 6) ); -rec( a := 6, b := 2, c := 3 ) -gap> OptionRecordWithDefaults( defaults, rec( b := 7, c := 8 ) ); -rec( a := 1, b := 7, c := 8 ) -gap> OptionRecordWithDefaults( defaults, [ ] ); -rec( a := 1, b := 2, c := 3 ) -gap> OptionRecordWithDefaults( defaults, [ rec( c := 8 ) ] ); -rec( a := 1, b := 2, c := 8 ) -gap> OptionRecordWithDefaults( defaults, rec( d := 9 ) ); -Error, Unknown option: d -gap> OptionRecordWithDefaults( defaults, [ rec( b := 7 ), rec( c := 8 ) ] ); -Error, Too many arguments for function -gap> OptionRecordWithDefaults( defaults, 5 ); -Error, Options should be a record -gap> OptionRecordWithDefaults( defaults, [6,7,8] ); -Error, Too many arguments for function - -gap> PrintDimensions := function( arg ) -> local nargs, dim, order, V, L, len, K, i; -> nargs := Length( arg ); -> dim := [ arg[1]!.height, arg[1]!.width, arg[1]!.depth ]; -> order := rec( h := 1, w := 2, d := 3 ); -> V := [ "height", "width", "depth" ]; -> if ( nargs > 1 ) and IsRecord( arg[2] ) then -> order := OptionRecordWithDefaults( order, arg[2] ); -> fi; -> L := [ order!.h, order!.w, order!.d ]; -> len := Length( L ); -> K := [ 1..len ]; -> SortParallel( L, K ); -> Print( "dimensions: " ); -> Print( V[K[1]], " = ", dim[K[1]], ", " ); -> Print( V[K[2]], " = ", dim[K[2]], ", " ); -> Print( V[K[3]], " = ", dim[K[3]], "\n" ); -> end;; - -gap> mydim := rec( height := 45, width := 31, depth := 17 ); -rec( depth := 17, height := 45, width := 31 ) -gap> PrintDimensions( mydim ); -dimensions: height = 45, width = 31, depth = 17 -gap> PrintDimensions( mydim, rec( h:=3, w:=1, d:=2 ) ); -dimensions: width = 31, depth = 17, height = 45 From 17417f44521933231fe0918e3ef502fb55a7fb81 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 1 Sep 2026 16:01:11 +0100 Subject: [PATCH 02/10] fixed unintended change in iterator.xml --- doc/iterator.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/iterator.xml b/doc/iterator.xml index d3109a8..ea4589a 100644 --- a/doc/iterator.xml +++ b/doc/iterator.xml @@ -51,6 +51,7 @@ gap> AllIsomorphisms( G, s3 ); [ [ f1, f2 ] -> [ (6,7), (5,6,7) ], [ f1, f2 ] -> [ (5,7), (5,6,7) ], [ f1, f2 ] -> [ (5,6), (5,7,6) ], [ f1, f2 ] -> [ (6,7), (5,7,6) ], [ f1, f2 ] -> [ (5,7), (5,7,6) ], [ f1, f2 ] -> [ (5,6), (5,6,7) ] ] +gap> iter := AllIsomorphismsIterator( G, s3 );; gap> for h in iter do Print( ImageElm( h, G.1 ) = (6,7), ", " ); od; true, false, false, true, false, false, gap> s4 := Group( (1,2),(2,3),(3,4) );; From 08c131bc413ae1d056b961a8d5a818d8c35b367c Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 2 Sep 2026 12:17:56 +0100 Subject: [PATCH 03/10] fixed minor problem in groups test --- doc/groups.xml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/groups.xml b/doc/groups.xml index 2218f74..35f0cf2 100644 --- a/doc/groups.xml +++ b/doc/groups.xml @@ -406,12 +406,8 @@ gap> c2 := Subgroup( d8, [ (2,4) ] );; gap> SortedList( IdempotentEndomorphismsWithImage( gens, c2 ) ); [ [ (), (2,4) ], [ (2,4), () ] ] gap> data:= IdempotentEndomorphismsData( d8 );; -gap> data.images; -[ [ [ (), () ] ], [ [ (), (2,4) ], [ (2,4), () ] ], - [ [ (), (1,3) ], [ (1,3), () ] ], - [ [ (), (1,2)(3,4) ], [ (1,2)(3,4), (1,2)(3,4) ] ], - [ [ (), (1,4)(2,3) ], [ (1,4)(2,3), (1,4)(2,3) ] ], - [ [ (1,2,3,4), (1,2)(3,4) ] ] ] +gap> Length( data.images ); +6 gap> all:= IdempotentEndomorphisms( d8 );; gap> allim := List( all, m -> MappingGeneratorsImages(m)[2] );; gap> ## the list of 10 sets of images sorted: From 645c1f3f6cc0de438a116e15551bec8fa6d5dbae Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 9 Sep 2026 00:20:21 +0200 Subject: [PATCH 04/10] Download: pass 'target' on to curlInterface as 'targetFile' (#104) Since curlInterface can write the body to a file itself, let it: the file then never passes through memory. Older versions ignore the option and still return the contents, which are written here as before. Co-authored-by: Claude Opus 5 --- lib/download.gi | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/download.gi b/lib/download.gi index 4b9a6ce..429f6dc 100644 --- a/lib/download.gi +++ b/lib/download.gi @@ -40,11 +40,18 @@ Add( Download_Methods, rec( if not IsBound( opt.failOnError ) then opt.failOnError:= true; fi; - # 'DownloadURL' handles the options 'verifyCert' and 'maxTime'. + # 'DownloadURL' handles the options 'verifyCert' and 'maxTime'. Newer + # versions can write the body to a file themselves, which keeps it out of + # memory; they call that option 'targetFile'. + if IsBound( opt.target ) and IsString( opt.target ) then + opt.targetFile:= opt.target; + fi; res:= ValueGlobal( "DownloadURL" )( url, opt ); if res.success = true and - IsBound( opt.target ) and IsString( opt.target ) then + IsBound( opt.target ) and IsString( opt.target ) and + IsBound( res.result ) then + # an older 'DownloadURL' ignored 'targetFile' and returned the contents FileString( opt.target, res.result ); Unbind( res.result ); fi; From 7f42b1c71a6dd840ce87502a43c04e5ee4cc9279 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 9 Sep 2026 00:20:52 +0200 Subject: [PATCH 05/10] Download: add a 'resume' option (#105) A download interrupted halfway currently starts again from zero, which for a data set of any size is the difference between a retry and an afternoon. With 'resume' set and a target given, the curl and wget methods continue the partial file. The clean-up in 'Download' skips the target for the same reason: otherwise it would throw away the very thing the next attempt is meant to continue. Methods that cannot resume decline the request rather than proceeding to avoid destroying the partial file the resuming methods need. 'resume' is deliberately left unbound when the caller does not ask for it, rather than defaulted to false. Co-authored-by: Claude Opus 5 --- doc/download.xml | 23 ++++++++++++++++++++- lib/download.gi | 29 +++++++++++++++++++++++++-- tst/download.tst | 51 ++++++++++++++++++++++++++++++++++++++++++++++- tst/http-server.g | 27 ++++++++++++++++++++++++- 4 files changed, 125 insertions(+), 5 deletions(-) diff --git a/doc/download.xml b/doc/download.xml index cf8548c..0d2afde 100644 --- a/doc/download.xml +++ b/doc/download.xml @@ -69,7 +69,28 @@ The following components are supported. and the function writes the downloaded contents to this file; the returned record does not have a result component in this case.

- If the download fails then this file is not left behind. + If the download fails then this file is not left behind, + unless resume is set. + +resume + + If this component is bound and has the value true, + and target is given, + then a partially downloaded file is continued rather than fetched again, + and it is kept if the download fails again. +

+ Methods that cannot resume decline the request, since they would discard + the partial file that a method which can resume needs; currently the + methods based on the external programs curl and wget resume. + If none is available the download fails, and the caller can retry without + resume. +

+ It is the caller's responsibility that an existing target really is + a prefix of what url delivers; otherwise the two get concatenated. +

+ If the server does not support range requests then no data is lost: + wget fetches the file again from the start, and curl fails + and leaves the partial file alone. verifyCert diff --git a/lib/download.gi b/lib/download.gi index 429f6dc..49f97ca 100644 --- a/lib/download.gi +++ b/lib/download.gi @@ -36,6 +36,13 @@ Add( Download_Methods, rec( download:= function( url, opt ) local res; + if IsBound( opt.resume ) and opt.resume = true and + IsBound( opt.target ) and IsString( opt.target ) then + # Declining matters: this method would truncate the partial file that a + # method which can resume needs. + return rec( success:= false, error:= "no support for resuming" ); + fi; + opt:= ShallowCopy( opt ); if not IsBound( opt.failOnError ) then opt.failOnError:= true; @@ -68,6 +75,11 @@ Add( Download_Methods, rec( return rec( success:= false, error:= "protocol is not http" ); elif IsBound( opt.maxTime ) and opt.maxTime <> 0 then return rec( success:= false, error:= "no support for given timeout" ); + elif IsBound( opt.resume ) and opt.resume = true and + IsBound( opt.target ) and IsString( opt.target ) then + # No range request, so this would overwrite the partial file that a + # method which can resume needs. + return rec( success:= false, error:= "no support for resuming" ); fi; # Split the URL after 'http://' into the authority and HTTP request target. @@ -171,6 +183,10 @@ Add( Download_Methods, rec( else args:= [ "--quiet", "-O", "-", url ]; fi; + if IsBound( opt.resume ) and opt.resume = true and + IsBound( opt.target ) and IsString( opt.target ) then + Add( args, "-c" ); + fi; if IsBound( opt.verifyCert ) and opt.verifyCert = false then Add( args, "--no-check-certificate" ); fi; @@ -180,8 +196,10 @@ Add( Download_Methods, rec( code:= Process( DirectoryCurrent(), exec, InputTextNone(), outstream, args ); CloseStream( outstream ); if code <> 0 then - # wget may have created the target file; try to remove it + # wget may have created the target file; try to remove it, unless the + # caller wants to resume from what is there if IsBound( opt.target ) and IsString( opt.target ) and + not ( IsBound( opt.resume ) and opt.resume = true ) and IsExistingFile( opt.target ) and RemoveFile( opt.target ) <> true then Error( "Download cannot remove unwanted file ", opt.target ); fi; @@ -218,6 +236,11 @@ Add( Download_Methods, rec( else Add( args, "-" ); fi; + if IsBound( opt.resume ) and opt.resume = true and + IsBound( opt.target ) and IsString( opt.target ) then + Add( args, "-C" ); + Add( args, "-" ); + fi; if IsBound( opt.maxTime ) and IsPosInt( opt.maxTime ) then Add( args, "--max-time" ); Add( args, opt.maxTime ); @@ -282,8 +305,10 @@ InstallMethod( Download, fi; # A failed method may have left a partial or bogus target file behind. # Remove it here, so that the guarantee holds for every method, - # including ones added to 'Download_Methods' from outside. + # including ones added to 'Download_Methods' from outside -- but not + # when resuming, where the partial file is the whole point. if IsBound( opt.target ) and IsString( opt.target ) and + not ( IsBound( opt.resume ) and opt.resume = true ) and IsExistingFile( opt.target ) then RemoveFile( opt.target ); fi; diff --git a/tst/download.tst b/tst/download.tst index 02856d3..afa6b4b 100644 --- a/tst/download.tst +++ b/tst/download.tst @@ -1,4 +1,4 @@ -#@local meths, i, urls, pair, url, expected, res1, good1, n, file, res2, good2, contents, r, res3, good3, bad, server, baseurl, iometh, opt, oldpref +#@local meths, i, urls, pair, url, expected, res1, good1, n, file, res2, good2, contents, r, res3, good3, bad, server, baseurl, iometh, opt, oldpref, resumers, name ############################################################################ ## #W download.tst Utils Package Thomas Breuer @@ -164,6 +164,55 @@ true gap> IsExistingFile( file ); false +## 'resume' continues a partial file rather than fetching it again. The +## test server answers a Range request with the remainder in upper case, so +## a resumed download is distinguishable from a restarted one. +gap> resumers:= Filtered( meths, r -> r.name in [ "via curl", "via wget" ] );; +gap> for r in resumers do +> FileString( file, "abcde" );; +> res1:= r.download( Concatenation( baseurl, "/resumable" ), +> rec( target:= file, resume:= true ) ); +> if res1.success <> true then +> Print( "resume failed for ", r.name, ": ", res1.error, "\n" ); +> elif StringFile( file ) <> "abcdeFGHIJKLMNOPQRST" then +> Print( "did not resume for ", r.name, ": ", StringFile( file ), "\n" ); +> fi; +> RemoveFile( file ); +> od; + +## Without 'resume' the target is replaced, not appended to. +gap> FileString( file, "abcde" );; +gap> res1:= Download( Concatenation( baseurl, "/resumable" ), +> rec( target:= file ) );; +gap> StringFile( file ); +"abcdefghijklmnopqrst" + +## Methods that cannot resume decline, rather than discarding the partial +## file that a method which can resume needs. +gap> iometh.download( Concatenation( baseurl, "/resumable" ), +> rec( target:= file, resume:= true ) ).error; +"no support for resuming" + +## With 'resume', a failed download keeps the partial file to continue from. +## Without this, the clean-up in 'Download' would throw away the very thing +## the next attempt is meant to continue. +gap> FileString( file, "abcde" );; +gap> res1:= Download( Concatenation( baseurl, "/missing" ), +> rec( target:= file, resume:= true ) );; +gap> res1.success; +false +gap> StringFile( file ); +"abcde" +gap> RemoveFile( file );; + +## 'resume' is only declined when it is actually requested: a method must +## not be skipped merely because the component is present. +gap> res1:= Download( Concatenation( baseurl, "/file" ), +> rec( target:= file, resume:= false ) );; +gap> res1.success; +true +gap> RemoveFile( file );; + ## test errors and redirects gap> res1:= Download( Concatenation( baseurl, "/missing" ) );; gap> res1.success = false; diff --git a/tst/http-server.g b/tst/http-server.g index 40a532a..ad2b0b4 100644 --- a/tst/http-server.g +++ b/tst/http-server.g @@ -4,7 +4,7 @@ ## BindGlobal( "UTILS_HandleHTTPTestRequest", function( listener, socket ) - local connection, line, parts, uri, body, status, location; + local connection, line, parts, uri, body, status, location, range, from; IO_close( listener ); connection:= IO_WrapFD( socket, IO.DefaultBufSize, IO.DefaultBufSize ); @@ -16,8 +16,12 @@ BindGlobal( "UTILS_HandleHTTPTestRequest", function( listener, socket ) fi; uri:= parts[2]; + range:= fail; repeat line:= IO_ReadLine( connection ); + if IsString( line ) and StartsWith( LowercaseString( line ), "range:" ) then + range:= line; + fi; until line = fail or line = "" or line = "\n" or line = "\r\n"; body:= "download test response\n"; @@ -32,6 +36,27 @@ BindGlobal( "UTILS_HandleHTTPTestRequest", function( listener, socket ) body:= ""; status:= "302 Found"; location:= "Location: /success\r\n"; + elif StartsWith( uri, "/resumable" ) then + # Answer a 'Range: bytes=N-' request with the remainder, but in upper + # case, so that a test can tell a resumed download from a restarted one. + body:= "abcdefghijklmnopqrst"; + if range <> fail then + from:= Int( Filtered( range, c -> c in "0123456789" ) ); + if from <> fail and 0 < from and from < Length( body ) then + IO_Write( connection, + "HTTP/1.1 206 Partial Content\r\n", + "Content-Type: text/plain\r\n", + "Content-Range: bytes ", String( from ), "-", + String( Length( body ) - 1 ), "/", String( Length( body ) ), + "\r\n", + "Content-Length: ", String( Length( body ) - from ), "\r\n", + "Connection: close\r\n\r\n", + UppercaseString( body{ [ from+1 .. Length( body ) ] } ) ); + IO_Flush( connection ); + IO_Close( connection ); + IO_exit( 0 ); + fi; + fi; fi; IO_Write( connection, From d4743e59e4ff9fbd24c0269d5299b67b02b89a50 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 9 Sep 2026 00:56:55 +0200 Subject: [PATCH 06/10] Download: do not remove a target file the caller brought (#107) The clean-up added in #103 removes 'opt.target' after any failed method, which also removes a file that was there before the call. A failed download then destroys a file it never created. Remember whether the file existed when 'Download' was entered, and remove it only if it did not. This also lets the wget method drop its own removal: with the caller's file protected in one place, the per-method clean-up is redundant, and 'RemoveFile' is now called from exactly one place instead of two that disagreed about whether to signal an error when it fails. Co-authored-by: Claude Opus 5 --- doc/download.xml | 7 +++++-- lib/download.gi | 22 +++++++++++----------- tst/download.tst | 11 +++++++++++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/doc/download.xml b/doc/download.xml index 0d2afde..138f9f9 100644 --- a/doc/download.xml +++ b/doc/download.xml @@ -69,8 +69,11 @@ The following components are supported. and the function writes the downloaded contents to this file; the returned record does not have a result component in this case.

- If the download fails then this file is not left behind, - unless resume is set. + If the download fails then a file created by the attempt is not left + behind, unless resume is set. A file that was already there + before the call is not removed, since it is not ours to delete – + but note that a failed attempt may well have overwritten it, so its old + contents are not guaranteed either. resume diff --git a/lib/download.gi b/lib/download.gi index 49f97ca..de3fa60 100644 --- a/lib/download.gi +++ b/lib/download.gi @@ -196,13 +196,6 @@ Add( Download_Methods, rec( code:= Process( DirectoryCurrent(), exec, InputTextNone(), outstream, args ); CloseStream( outstream ); if code <> 0 then - # wget may have created the target file; try to remove it, unless the - # caller wants to resume from what is there - if IsBound( opt.target ) and IsString( opt.target ) and - not ( IsBound( opt.resume ) and opt.resume = true ) and - IsExistingFile( opt.target ) and RemoveFile( opt.target ) <> true then - Error( "Download cannot remove unwanted file ", opt.target ); - fi; return rec( success:= false, error:= Concatenation( "Process returned ", String( code ) ) ); elif not ( IsBound( opt.target ) and IsString( opt.target ) ) then @@ -275,7 +268,7 @@ InstallMethod( Download, InstallMethod( Download, [ "IsString", "IsRecord" ], function( url, opt ) - local timeout, errors, r, res; + local timeout, hadTarget, errors, r, res; # Do not modify the caller's record when filling in the defaults below. opt:= ShallowCopy( opt ); @@ -294,6 +287,11 @@ InstallMethod( Download, fi; fi; + # Whether the caller brought the target file, as opposed to a method + # creating it below. We remove only what we created. + hadTarget:= IsBound( opt.target ) and IsString( opt.target ) and + IsExistingFile( opt.target ); + # Run over the methods. errors:= []; for r in Download_Methods do @@ -305,10 +303,12 @@ InstallMethod( Download, fi; # A failed method may have left a partial or bogus target file behind. # Remove it here, so that the guarantee holds for every method, - # including ones added to 'Download_Methods' from outside -- but not - # when resuming, where the partial file is the whole point. - if IsBound( opt.target ) and IsString( opt.target ) and + # including ones added to 'Download_Methods' from outside. Two + # files are not ours to delete: one the caller brought, and the + # partial one that a resumed download continues from. + if not hadTarget and not ( IsBound( opt.resume ) and opt.resume = true ) and + IsBound( opt.target ) and IsString( opt.target ) and IsExistingFile( opt.target ) then RemoveFile( opt.target ); fi; diff --git a/tst/download.tst b/tst/download.tst index afa6b4b..e80c402 100644 --- a/tst/download.tst +++ b/tst/download.tst @@ -213,6 +213,17 @@ gap> res1.success; true gap> RemoveFile( file );; +## A file that was already there is not removed by a failed download: +## 'Download' only cleans up after itself. +gap> FileString( file, "mine" );; +gap> res1:= Download( Concatenation( baseurl, "/missing" ), +> rec( target:= file ) );; +gap> res1.success; +false +gap> IsExistingFile( file ); +true +gap> RemoveFile( file );; + ## test errors and redirects gap> res1:= Download( Concatenation( baseurl, "/missing" ) );; gap> res1.success = false; From 89337a80886a599a647006cd9bb6d0a473b57881 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 1 Sep 2026 10:23:02 +0100 Subject: [PATCH 07/10] removing files superceded by utils0-.tst --- doc/groups.xml | 27 ++++++------ doc/iterator.xml | 26 ++++++++++- doc/matrix.xml | 10 ++++- tst/gslp.tst | 3 ++ tst/iterator.tst | 100 ------------------------------------------- tst/lists.tst | 109 ----------------------------------------------- tst/manual.g | 24 +++++++++++ tst/matrix.tst | 80 ---------------------------------- tst/number.tst | 80 ---------------------------------- tst/others.tst | 79 ---------------------------------- tst/print.tst | 48 --------------------- tst/record.tst | 65 ---------------------------- 12 files changed, 74 insertions(+), 577 deletions(-) delete mode 100644 tst/iterator.tst delete mode 100644 tst/lists.tst create mode 100755 tst/manual.g delete mode 100644 tst/matrix.tst delete mode 100644 tst/number.tst delete mode 100644 tst/others.tst delete mode 100644 tst/print.tst delete mode 100644 tst/record.tst diff --git a/doc/groups.xml b/doc/groups.xml index e253ca7..2218f74 100644 --- a/doc/groups.xml +++ b/doc/groups.xml @@ -401,24 +401,25 @@ The first of these is the zero map, the last is the identity.

gens := [ (1,2,3,4), (1,2)(3,4) ];; -gap> d8 := Group( gens );; -gap> SetName( d8, "d8" ); +gap> d8 := Group( gens );; SetName( d8, "d8" ); gap> c2 := Subgroup( d8, [ (2,4) ] );; gap> SortedList( IdempotentEndomorphismsWithImage( gens, c2 ) ); [ [ (), (2,4) ], [ (2,4), () ] ] gap> data:= IdempotentEndomorphismsData( d8 );; -gap> data.images[1]; -[ [ (), () ] ] -gap> List( data.images, Length ); -[ 1, 2, 2, 2, 2, 1 ] +gap> data.images; +[ [ [ (), () ] ], [ [ (), (2,4) ], [ (2,4), () ] ], + [ [ (), (1,3) ], [ (1,3), () ] ], + [ [ (), (1,2)(3,4) ], [ (1,2)(3,4), (1,2)(3,4) ] ], + [ [ (), (1,4)(2,3) ], [ (1,4)(2,3), (1,4)(2,3) ] ], + [ [ (1,2,3,4), (1,2)(3,4) ] ] ] gap> all:= IdempotentEndomorphisms( d8 );; -gap> Length( all ); -10 -gap> all[1]; -[ (1,2,3,4), (1,2)(3,4) ] -> [ (), () ] -gap> Size( Image( all[1] ) ); -1 -gap> Last( all ) = IdentityMapping( d8 ); +gap> allim := List( all, m -> MappingGeneratorsImages(m)[2] );; +gap> ## the list of 10 sets of images sorted: +gap> allimpairs := +> [ [ (), () ], [ (), (2,4) ], [ (2,4), () ], [ (), (1,3) ], [ (1,3), () ], +> [ (), (1,2)(3,4) ], [ (1,2)(3,4), (1,2)(3,4) ], [ (), (1,4)(2,3) ], +> [ (1,4)(2,3), (1,4)(2,3) ], [ (1,2,3,4), (1,2)(3,4) ] ];; +gap> ForAll( allim, m -> ( m in allimpairs ) ); true ]]> diff --git a/doc/iterator.xml b/doc/iterator.xml index 9eba053..d3109a8 100644 --- a/doc/iterator.xml +++ b/doc/iterator.xml @@ -2,7 +2,7 @@ - + @@ -51,9 +51,13 @@ gap> AllIsomorphisms( G, s3 ); [ [ f1, f2 ] -> [ (6,7), (5,6,7) ], [ f1, f2 ] -> [ (5,7), (5,6,7) ], [ f1, f2 ] -> [ (5,6), (5,7,6) ], [ f1, f2 ] -> [ (6,7), (5,7,6) ], [ f1, f2 ] -> [ (5,7), (5,7,6) ], [ f1, f2 ] -> [ (5,6), (5,6,7) ] ] -gap> iter := AllIsomorphismsIterator( G, s3 );; gap> for h in iter do Print( ImageElm( h, G.1 ) = (6,7), ", " ); od; true, false, false, true, false, false, +gap> s4 := Group( (1,2),(2,3),(3,4) );; +gap> AllIsomorphismsNumber( s3, s4 ); +0 +gap> AllIsomorphisms( s3, s4 ); +[ ] ]]> @@ -156,6 +160,24 @@ gap> NextIterator( pairs4 ); gap> IsDoneIterator( pairs4 ); true ]]> + +Some trivial cases: + iter0 := IteratorList( [ ] );; +gap> iter4 := IteratorList( [ 4 ] );; +gap> cart := CartesianIterator( iter0, iter0 );; +gap> IsDoneIterator( cart ); +true +gap> cart := CartesianIterator( iter0, iter4 );; +gap> IsDoneIterator( cart ); +true +gap> cart := CartesianIterator( iter4, iter0 );; +gap> IsDoneIterator( cart ); +true +gap> pairs0 := UnorderedPairsIterator( iter0 );; +gap> IsDoneIterator( pairs0 ); +true +]]> diff --git a/doc/matrix.xml b/doc/matrix.xml index 13f7433..894c044 100644 --- a/doc/matrix.xml +++ b/doc/matrix.xml @@ -2,7 +2,7 @@ - + @@ -83,6 +83,14 @@ gap> Display( M8 ); gap> L8 := DirectSumDecompositionMatrices( M8 );; gap> Length( L8 ); 16 + +gap> M3 := [ [0,0,7,0,0,0,0], [0,0,0,8,0,0,0], [0,0,0,0,9,0,0] ];; +gap> Display( M3 ); +[ [ 0, 0, 7, 0, 0, 0, 0 ], + [ 0, 0, 0, 8, 0, 0, 0 ], + [ 0, 0, 0, 0, 9, 0, 0] ] +gap> L3 := DirectSumDecompositionMatrices( M3 ); +[ [ [ [ 0, 0, 7 ] ], [ [ 8 ] ], [ [ 9, 0, 0 ] ] ] ] ]]>

diff --git a/tst/gslp.tst b/tst/gslp.tst index 5d4f7bf..b2ec1a9 100644 --- a/tst/gslp.tst +++ b/tst/gslp.tst @@ -5,6 +5,9 @@ ## #Y Copyright (C) 2026, The GAP Group ## +## +## some tests other than those in the manual + gap> START_TEST( "gslp.tst" ); # diff --git a/tst/iterator.tst b/tst/iterator.tst deleted file mode 100644 index 36a8799..0000000 --- a/tst/iterator.tst +++ /dev/null @@ -1,100 +0,0 @@ -#@local c3c3, cart, G, h, it1, it2, iter, iter0, iter4, iterL -#@local L, n, pairs0, pairs4, pairsL, s3, s4 - -############################################################################## -## -#W iterator.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 7.1.1 -gap> G := DihedralGroup(6);; -gap> s3 := Group( (5,6), (6,7) );; -gap> iter := AllIsomorphismsIterator( G, s3 );; -gap> NextIterator( iter ); -[ f1, f2 ] -> [ (6,7), (5,6,7) ] -gap> n := AllIsomorphismsNumber( G, s3 ); -6 -gap> AllIsomorphisms( G, s3 ); -[ [ f1, f2 ] -> [ (6,7), (5,6,7) ], [ f1, f2 ] -> [ (5,7), (5,6,7) ], - [ f1, f2 ] -> [ (5,6), (5,7,6) ], [ f1, f2 ] -> [ (6,7), (5,7,6) ], - [ f1, f2 ] -> [ (5,7), (5,7,6) ], [ f1, f2 ] -> [ (5,6), (5,6,7) ] ] -gap> iter := AllIsomorphismsIterator( G, s3 );; -gap> for h in iter do Print( ImageElm( h, G.1 ) = (6,7), ", " ); od; -true, false, false, true, false, false, -gap> s4 := Group( (1,2),(2,3),(3,4) );; -gap> AllIsomorphismsNumber( s3, s4 ); -0 -gap> AllIsomorphisms( s3, s4 ); -[ ] - -## SubSection 7.1.2 -gap> c3c3 := Group( (1,2,3), (4,5,6) );; -gap> iter := AllSubgroupsIterator( c3c3 ); - -gap> while not IsDoneIterator(iter) do Print(NextIterator(iter),"\n"); od; -Group( () ) -Group( [ (4,5,6) ] ) -Group( [ (1,2,3) ] ) -Group( [ (1,2,3)(4,5,6) ] ) -Group( [ (1,3,2)(4,5,6) ] ) -Group( [ (4,5,6), (1,2,3) ] ) - -## Subsection 7.2.1 -gap> it1 := Iterator( [ 1, 2, 3 ] );; -gap> it2 := Iterator( [ 4, 5, 6 ] );; -gap> iter := CartesianIterator( it1, it2 );; -gap> while not IsDoneIterator(iter) do Print(NextIterator(iter),"\n"); od; -[ 1, 4 ] -[ 1, 5 ] -[ 1, 6 ] -[ 2, 4 ] -[ 2, 5 ] -[ 2, 6 ] -[ 3, 4 ] -[ 3, 5 ] -[ 3, 6 ] -gap> ## try some trivial cases -gap> iter0 := IteratorList( [ ] );; -gap> iter4 := IteratorList( [ 4 ] );; -gap> cart := CartesianIterator( iter0, iter0 );; -gap> IsDoneIterator( cart ); -true -gap> cart := CartesianIterator( iter0, iter4 );; -gap> IsDoneIterator( cart ); -true -gap> cart := CartesianIterator( iter4, iter0 );; -gap> IsDoneIterator( cart ); -true - -## Subsection 6.2.2 -gap> L := [6,7,8,9];; -gap> iterL := IteratorList( L );; -gap> pairsL := UnorderedPairsIterator( iterL );; -gap> while not IsDoneIterator(pairsL) do Print(NextIterator(pairsL),"\n"); od; -[ 6, 6 ] -[ 6, 7 ] -[ 7, 7 ] -[ 6, 8 ] -[ 7, 8 ] -[ 8, 8 ] -[ 6, 9 ] -[ 7, 9 ] -[ 8, 9 ] -[ 9, 9 ] -gap> iter4 := IteratorList( [ 4 ] ); - -gap> pairs4 := UnorderedPairsIterator(iter4); - -gap> NextIterator( pairs4 ); -[ 4, 4 ] -gap> IsDoneIterator( pairs4 ); -true -gap> pairs0 := UnorderedPairsIterator( iter0 );; -gap> IsDoneIterator( pairs0 ); -true diff --git a/tst/lists.tst b/tst/lists.tst deleted file mode 100644 index 6407a69..0000000 --- a/tst/lists.tst +++ /dev/null @@ -1,109 +0,0 @@ -#@local C, c4, d16, gens, i, J, K, L, n, P, trans - -############################################################################## -## -#W lists.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 3.1.1 -gap> List( [1..12], n->n^3 ); -[ 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331, 1728 ] -gap> DifferencesList( last ); -[ 7, 19, 37, 61, 91, 127, 169, 217, 271, 331, 397 ] -gap> DifferencesList( last ); -[ 12, 18, 24, 30, 36, 42, 48, 54, 60, 66 ] -gap> DifferencesList( last ); -[ 6, 6, 6, 6, 6, 6, 6, 6, 6 ] -gap> L := [ 0 ];; -gap> DifferencesList( L ); -[ ] -gap> L := [ ];; -gap> DifferencesList( L ); -[ ] - -## SubSection 3.1.2 -gap> List( [0..10], n -> Factorial(n) ); -[ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800 ] -gap> QuotientsList( last ); -[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] -gap> L := [ 1, 3, 5, -1, -3, -5 ];; -gap> QuotientsList( L ); -[ 3, 5/3, -1/5, 3, 5/3 ] -gap> FloatQuotientsList( L ); -[ 3., 1.66667, -0.2, 3., 1.66667 ] -gap> QuotientsList( [ 2, 1, 0, -1, -2 ] ); -[ 1/2, 0, fail, 2 ] -gap> FloatQuotientsList( [1..10] ); -[ 2., 1.5, 1.33333, 1.25, 1.2, 1.16667, 1.14286, 1.125, 1.11111 ] -gap> Product( last ); -10. - -## SubSection 3.1.3 -gap> L := [1..20];; L[1]:=13;; -gap> for i in [1..19] do -> if IsOddInt(L[i]) then L[i+1]:=3*L[i]+1; else L[i+1]:=L[i]/2; fi; -> od; -gap> L; -[ 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4 ] -gap> SearchCycle( L ); -[ 1, 4, 2 ] -gap> n := 1;; L := [n];; -gap> for i in [1..100] do n:=(n^2+1) mod 1093; Add(L,n); od; -gap> L; -[ 1, 2, 5, 26, 677, 363, 610, 481, 739, 715, 795, 272, 754, 157, 604, 848, - 1004, 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004, 271, - 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004, 271, 211, 802, 521, - 378, 795, 272, 754, 157, 604, 848, 1004, 271, 211, 802, 521, 378, 795, 272, - 754, 157, 604, 848, 1004, 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, - 848, 1004, 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004, - 271, 211, 802, 521, 378, 795, 272, 754, 157, 604, 848, 1004 ] -gap> C := SearchCycle( L ); -[ 157, 604, 848, 1004, 271, 211, 802, 521, 378, 795, 272, 754 ] -gap> P := Positions( L, 157 ); -[ 14, 26, 38, 50, 62, 74, 86, 98 ] -gap> Length( C ); DifferencesList( P ); -12 -[ 12, 12, 12, 12, 12, 12, 12 ] - -## SubSection 3.1.4 -## this manual example not tested as answers vary from run to run -## gap> RandomCombination( [1..49], 6 ); -## [ 3, 5, 21, 24, 27, 31 ] - - -## SubSection 3.2.1 -gap> J := [ [1,2,3], [3,4], [3,4], [1,2,4] ];; -gap> DistinctRepresentatives( J ); -[ 1, 3, 4, 2 ] -gap> K := [ [3,4], [1,2], [2,3], [2,3,4] ];; -gap> CommonRepresentatives( J, K ); -[ [ 3, 3, 3, 1 ], [ 1, 3, 4, 2 ] ] -gap> d16 := DihedralGroup( IsPermGroup, 16 ); SetName( d16, "d16" ); -Group([ (1,2,3,4,5,6,7,8), (2,8)(3,7)(4,6) ]) -gap> c4 := Subgroup( d16, [ d16.1^2 ] ); SetName( c4, "c4" ); -Group([ (1,3,5,7)(2,4,6,8) ]) -gap> RightCosets( d16, c4 ); -[ RightCoset(c4,()), RightCoset(c4,(2,8)(3,7)(4,6)), RightCoset(c4,(1,8,7,6,5, - 4,3,2)), RightCoset(c4,(1,8)(2,7)(3,6)(4,5)) ] -gap> trans := CommonTransversal( d16, c4 ); -[ (), (2,8)(3,7)(4,6), (1,2,3,4,5,6,7,8), (1,2)(3,8)(4,7)(5,6) ] -gap> IsCommonTransversal( d16, c4, trans ); -true - -## SubSection 3.3.1 -gap> gens := GeneratorsOfGroup( DihedralGroup(12) ); -[ f1, f2, f3 ] -gap> String( gens ); -"[ f1, f2, f3 ]" -gap> BlankFreeString( gens ); -"[f1,f2,f3]" - -############################################################################# -## -#E lists.tst . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/manual.g b/tst/manual.g new file mode 100755 index 0000000..e8aedd6 --- /dev/null +++ b/tst/manual.g @@ -0,0 +1,24 @@ +## utils.g +LoadPackage("utils"); +Print( "running utils01.tst\n" ); +Test( "tst/utils01.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils02.tst\n" ); +Test( "tst/utils02.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils03.tst\n" ); +Test( "tst/utils03.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils04.tst\n" ); +Test( "tst/utils04.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils05.tst\n" ); +Test( "tst/utils05.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils06.tst\n" ); +Test( "tst/utils06.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils07.tst\n" ); +Test( "tst/utils07.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils08.tst\n" ); +Test( "tst/utils08.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils09.tst\n" ); +Test( "tst/utils09.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils10.tst\n" ); +Test( "tst/utils10.tst", rec(compareFunction := "uptowhitespace") ); +Print( "running utils11.tst\n" ); +Test( "tst/utils11.tst", rec(compareFunction := "uptowhitespace") ); diff --git a/tst/matrix.tst b/tst/matrix.tst deleted file mode 100644 index 78da41d..0000000 --- a/tst/matrix.tst +++ /dev/null @@ -1,80 +0,0 @@ -#@local M6, L6, M4, L4, M8, L8, L, A, M3, L3, M5, L5; -############################################################################## -## -#W matrix.tst Utils Package -## -#Y Copyright (C) 2015-2023, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 9.1.1 -gap> M6 := [ [1,2,0,0,0,0], [3,4,0,0,0,0], [5,6,0,0,0,0], -> [0,0,9,0,0,0], [0,0,0,1,2,3], [0,0,0,4,5,6] ];; -gap> Display( M6 ); -[ [ 1, 2, 0, 0, 0, 0 ], - [ 3, 4, 0, 0, 0, 0 ], - [ 5, 6, 0, 0, 0, 0 ], - [ 0, 0, 9, 0, 0, 0 ], - [ 0, 0, 0, 1, 2, 3 ], - [ 0, 0, 0, 4, 5, 6 ] ] -gap> L6 := DirectSumDecompositionMatrices( M6 ); -[ [ [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ], [ [ 9 ] ], [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] - ] ] - -gap> M4 := [ [0,3,0,0], [0,0,0,0], [0,0,0,0], [0,0,4,0] ];; -gap> Display( M4 ); -[ [ 0, 3, 0, 0 ], - [ 0, 0, 0, 0 ], - [ 0, 0, 0, 0 ], - [ 0, 0, 4, 0 ] ] -gap> L4 := DirectSumDecompositionMatrices( M4 ); -[ [ [ [ 0, 3 ] ], [ [ 0, 0 ], [ 0, 0 ], [ 4, 0 ] ] ], - [ [ [ 0, 3 ], [ 0, 0 ] ], [ [ 0, 0 ], [ 4, 0 ] ] ], - [ [ [ 0, 3 ], [ 0, 0 ], [ 0, 0 ] ], [ [ 4, 0 ] ] ] ] -gap> for L in L4 do -> A := DirectSumMat( L );; -> if ( A = M4 ) then Print( "yes, A = M4\n" ); fi; -> od; -yes, A = M4 -yes, A = M4 -yes, A = M4 - -gap> M8 := DirectSumMat( M4, M4 );; -gap> Display( M8 ); -[ [ 0, 3, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 4, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 3, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 4, 0 ] ] -gap> L8 := DirectSumDecompositionMatrices( M8 );; -gap> Length( L8 ); -16 - -gap> M3 := [ [0,0,0,7,0,0,0], [0,0,0,0,8,0,0], [0,0,0,0,0,9,0] ];; -gap> Display( M3 ); -[ [ 0, 0, 0, 7, 0, 0, 0 ], - [ 0, 0, 0, 0, 8, 0, 0 ], - [ 0, 0, 0, 0, 0, 9, 0 ] ] -gap> L3 := DirectSumDecompositionMatrices( M3 ); -[ [ [ [ 0, 0, 0, 7 ] ], [ [ 8 ] ], [ [ 9, 0 ] ] ] ] - -gap> M5 := [ [1,2,0,0,0], [3,4,0,0,0], [0,0,0,0,0], -> [0,0,0,6,7], [0,0,0,8,9] ];; -gap> Display(M5); -[ [ 1, 2, 0, 0, 0 ], - [ 3, 4, 0, 0, 0 ], - [ 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 6, 7 ], - [ 0, 0, 0, 8, 9 ] ] -gap> L5 := DirectSumDecompositionMatrices( M5 ); -[ [ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 0 ] ], [ [ 6, 7 ], [ 8, 9 ] ] ] ] - -############################################################################# -## -#E matrix.tst . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/number.tst b/tst/number.tst deleted file mode 100644 index b61c7b8..0000000 --- a/tst/number.tst +++ /dev/null @@ -1,80 +0,0 @@ -#@local i, iter, n, p, sum - -############################################################################## -## -#W number.tst Utils Package Stefan Kohl -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 4.1.1 -gap> AllSmoothIntegers( 3, 1000 ); -[ 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 54, 64, 72, 81, 96, - 108, 128, 144, 162, 192, 216, 243, 256, 288, 324, 384, 432, 486, 512, 576, - 648, 729, 768, 864, 972 ] -gap> AllSmoothIntegers( [5,11,17], 1000 ); -[ 1, 5, 11, 17, 25, 55, 85, 121, 125, 187, 275, 289, 425, 605, 625, 935 ] -gap> Length( last ); -16 -gap> List( [3..20], n -> Length( AllSmoothIntegers( [5,11,17], 10^n ) ) ); -[ 16, 29, 50, 78, 114, 155, 212, 282, 359, 452, 565, 691, 831, 992, 1173, - 1374, 1595, 1843 ] - -## SubSection 4.1.2 -gap> AllProducts([1..4],3); -[ 1, 2, 3, 4, 2, 4, 6, 8, 3, 6, 9, 12, 4, 8, 12, 16, 2, 4, 6, 8, 4, 8, 12, - 16, 6, 12, 18, 24, 8, 16, 24, 32, 3, 6, 9, 12, 6, 12, 18, 24, 9, 18, 27, - 36, 12, 24, 36, 48, 4, 8, 12, 16, 8, 16, 24, 32, 12, 24, 36, 48, 16, 32, - 48, 64 ] -gap> Set(last); -[ 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 64 ] -gap> AllProducts( [(1,2,3),(2,3,4)], 2 ); -[ (2,4,3), (1,2)(3,4), (1,3)(2,4), (1,3,2) ] - -## SubSection 4.1.3 -gap> RestrictedPartitions( 20, [4..10] ); -[ [ 4, 4, 4, 4, 4 ], [ 5, 5, 5, 5 ], [ 6, 5, 5, 4 ], [ 6, 6, 4, 4 ], - [ 7, 5, 4, 4 ], [ 7, 7, 6 ], [ 8, 4, 4, 4 ], [ 8, 6, 6 ], [ 8, 7, 5 ], - [ 8, 8, 4 ], [ 9, 6, 5 ], [ 9, 7, 4 ], [ 10, 5, 5 ], [ 10, 6, 4 ], - [ 10, 10 ] ] -gap> RestrictedPartitionsWithoutRepetitions( 20, [4..10] ); -[ [ 10, 6, 4 ], [ 9, 7, 4 ], [ 9, 6, 5 ], [ 8, 7, 5 ] ] -gap> RestrictedPartitionsWithoutRepetitions( 10^2, List([1..10], n->n^2 ) ); -[ [ 100 ], [ 64, 36 ], [ 49, 25, 16, 9, 1 ] ] - -## SubSection 4.1.4 -gap> n := 2^251;; -gap> NextProbablyPrimeInt( n ); -3618502788666131106986593281521497120414687020801267626233049500247285301313 - -## SubSection 4.1.6 -gap> iter := PrimeNumbersIterator();; -gap> for i in [1..100] do p := NextIterator(iter); od; -gap> p; -541 -gap> sum := 0;; -gap> ## "prime number race" 1 vs. 3 mod 4 -gap> for p in PrimeNumbersIterator() do -> if p <> 2 then sum := sum + E(4)^(p-1); fi; -> if sum > 0 then break; fi; -> od; -gap> p; -26861 - -## this final example takes quite a while: use examples/number.g -## gap> sum := 0;; -## gap> ## "prime number race" 1 vs. 5 mod 8 -## gap> for p in PrimeNumbersIterator() do -## > if p mod 8 in [1,5] then sum := sum + E(4)^((p-1)/2); fi; -## > if sum > 0 then break; fi; -## > od; -## gap> p; -## 588067889 - -############################################################################# -## -#E number.tst . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/others.tst b/tst/others.tst deleted file mode 100644 index 4a07480..0000000 --- a/tst/others.tst +++ /dev/null @@ -1,79 +0,0 @@ -#@local a, F2, f, g, relq8, q8, M, s1, n1, n2, N, s2; -############################################################################ -## -#W others.tst Utils Package -## -#Y Copyright (C) 2015-2025, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 10.1.1 -## this manual example is not tested to avoid creating files triv.* -## gap> LogTo( "triv.log" ); -## gap> a := 33^5; -## 39135393 -## gap> LogTo(); -## gap> Log2HTML( "triv.log" ); - -## SubSection 10.2.1 -gap> IntOrInfinityToLaTeX( 10^3 ); -"1000" -gap> IntOrInfinityToLaTeX( infinity ); -"\\infty" - -## SubSection 10.2.2 -gap> LaTeXStringFactorsInt( Factorial(12) ); -"2^{10} \\cdot 3^5 \\cdot 5^2 \\cdot 7 \\cdot 11" - -## SubSection 10.3.1 -gap> ## permutation groups -gap> ConvertToMagmaInputString( Group( (1,2,3,4,5), (3,4,5) ) ); -"PermutationGroup<5|(1,2,3,4,5),\n(3,4,5)>;\n" -gap> ConvertToMagmaInputString( Group( (1,2,3,4,5) ), "c5" ); -"c5 := PermutationGroup<5|(1,2,3,4,5)>;\n" -gap> ## pc-group -gap> ConvertToMagmaInputString( DihedralGroup( IsPcGroup, 10 ) ); -"PolycyclicGroup< f1,f2 |\nf1^2,\nf2^5,\nf2^f1 = f2^4\n>;\n" -gap> ## fp-group -gap> F2 := FreeGroup( 2 );; -gap> f := F2.1;; g := F2.2;; -gap> relq8 := [ f^4, g^4, f*g*f*g^-1, f^2*g^2 ];; -gap> q8 := F2/relq8;; -gap> ConvertToMagmaInputString( q8 ); -no conversion function yet available for fp-groups -fail -gap> ## matrix group -gap> M := GL(2,5);; Size(M); -480 -gap> s1 := ConvertToMagmaInputString( M ); -"F := GF(5);\nP := GL(2,F);\ngens := [\nP![2,0,0,1],\nP![4,1,4,0]\n];\nsub

;\n" -gap> Print( s1 ); -F := GF(5); -P := GL(2,F); -gens := [ -P![2,0,0,1], -P![4,1,4,0] -]; -sub

; -gap> n1 := [ [ Z(9)^0, Z(9)^0 ], [ Z(9)^0, Z(9) ] ];; -gap> n2 := [ [ Z(9)^0, Z(9)^3 ], [ Z(9)^4, Z(9)^2 ] ];; -gap> N := Group( n1, n2 );; Size( N ); -5760 -gap> s2 := ConvertToMagmaInputString( N, "gpN" );; -gap> Print( s2 ); -F := GF(3^2); -P := GL(2,F); -w := PrimitiveElement(F); -gens := [ -P![ 1, 1, 1,w^1], -P![ 1,w^3, 2,w^2] -]; -gpN := sub

; - -############################################################################# -## -#E others.tst . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/print.tst b/tst/print.tst deleted file mode 100644 index 5a8a57b..0000000 --- a/tst/print.tst +++ /dev/null @@ -1,48 +0,0 @@ -#@local L, s5 - -############################################################################## -## -#W print.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 2.1.1 -gap> L := List( [1..20], n -> n^5 );; -gap> PrintSelection( L, [18..20] ); -18 : 1889568 -19 : 2476099 -20 : 3200000 -gap> PrintSelection( L, 2, 9 ); -2 : 32 -11 : 161051 -20 : 3200000 -gap> PrintSelection( L, 2, 3, 11 ); -2 : 32 -5 : 3125 -8 : 32768 -11 : 161051 -gap> s5 := SymmetricGroup( 5 );; -gap> PrintSelection( s5, [30,31,100,101] ); -30 : (1,5)(3,4) -31 : (1,5,2) -100 : (1,4,3) -101 : (1,4)(3,5) -gap> PrintSelection( s5, 1, 30 ); -1 : () -31 : (1,5,2) -61 : (1,2,3) -91 : (1,3,5,2,4) -gap> PrintSelection( s5, 9, 11, 43 ); -9 : (2,5,3) -20 : (2,4) -31 : (1,5,2) -42 : (1,5,2,3,4) - -############################################################################# -## -#E print.tst . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here diff --git a/tst/record.tst b/tst/record.tst deleted file mode 100644 index 8799aef..0000000 --- a/tst/record.tst +++ /dev/null @@ -1,65 +0,0 @@ -#@local r, defaults, PrintDimensions, mydim - -############################################################################## -## -#W record.tst Utils Package -## -#Y Copyright (C) 2015-2022, The GAP Group -## - -gap> ReadPackage( "utils", "tst/loadall.g" );; -gap> UtilsLoadingComplete; -true - -## SubSection 8.1.1 -gap> r := rec( a := 1, b := 2, c := 3 );; -gap> AssignGlobals( r ); -The following global variables have been assigned: -[ "a", "b", "c" ] -gap> [ a, b, c ]; -[ 1, 2, 3 ] - -## SubSection 8.2.1 -gap> defaults := rec( a := 1, b := 2, c := 3 );; -gap> OptionRecordWithDefaults( defaults, rec( a := 6) ); -rec( a := 6, b := 2, c := 3 ) -gap> OptionRecordWithDefaults( defaults, rec( b := 7, c := 8 ) ); -rec( a := 1, b := 7, c := 8 ) -gap> OptionRecordWithDefaults( defaults, [ ] ); -rec( a := 1, b := 2, c := 3 ) -gap> OptionRecordWithDefaults( defaults, [ rec( c := 8 ) ] ); -rec( a := 1, b := 2, c := 8 ) -gap> OptionRecordWithDefaults( defaults, rec( d := 9 ) ); -Error, Unknown option: d -gap> OptionRecordWithDefaults( defaults, [ rec( b := 7 ), rec( c := 8 ) ] ); -Error, Too many arguments for function -gap> OptionRecordWithDefaults( defaults, 5 ); -Error, Options should be a record -gap> OptionRecordWithDefaults( defaults, [6,7,8] ); -Error, Too many arguments for function - -gap> PrintDimensions := function( arg ) -> local nargs, dim, order, V, L, len, K, i; -> nargs := Length( arg ); -> dim := [ arg[1]!.height, arg[1]!.width, arg[1]!.depth ]; -> order := rec( h := 1, w := 2, d := 3 ); -> V := [ "height", "width", "depth" ]; -> if ( nargs > 1 ) and IsRecord( arg[2] ) then -> order := OptionRecordWithDefaults( order, arg[2] ); -> fi; -> L := [ order!.h, order!.w, order!.d ]; -> len := Length( L ); -> K := [ 1..len ]; -> SortParallel( L, K ); -> Print( "dimensions: " ); -> Print( V[K[1]], " = ", dim[K[1]], ", " ); -> Print( V[K[2]], " = ", dim[K[2]], ", " ); -> Print( V[K[3]], " = ", dim[K[3]], "\n" ); -> end;; - -gap> mydim := rec( height := 45, width := 31, depth := 17 ); -rec( depth := 17, height := 45, width := 31 ) -gap> PrintDimensions( mydim ); -dimensions: height = 45, width = 31, depth = 17 -gap> PrintDimensions( mydim, rec( h:=3, w:=1, d:=2 ) ); -dimensions: width = 31, depth = 17, height = 45 From f3c3645f367dd6a7ed9b7a77ff0e26da8aceeb98 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 1 Sep 2026 16:01:11 +0100 Subject: [PATCH 08/10] fixed unintended change in iterator.xml --- doc/iterator.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/iterator.xml b/doc/iterator.xml index d3109a8..ea4589a 100644 --- a/doc/iterator.xml +++ b/doc/iterator.xml @@ -51,6 +51,7 @@ gap> AllIsomorphisms( G, s3 ); [ [ f1, f2 ] -> [ (6,7), (5,6,7) ], [ f1, f2 ] -> [ (5,7), (5,6,7) ], [ f1, f2 ] -> [ (5,6), (5,7,6) ], [ f1, f2 ] -> [ (6,7), (5,7,6) ], [ f1, f2 ] -> [ (5,7), (5,7,6) ], [ f1, f2 ] -> [ (5,6), (5,6,7) ] ] +gap> iter := AllIsomorphismsIterator( G, s3 );; gap> for h in iter do Print( ImageElm( h, G.1 ) = (6,7), ", " ); od; true, false, false, true, false, false, gap> s4 := Group( (1,2),(2,3),(3,4) );; From 694516c3ef00f1431de7e19432177e1c896a1f7b Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 2 Sep 2026 12:17:56 +0100 Subject: [PATCH 09/10] fixed minor problem in groups test --- doc/groups.xml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/groups.xml b/doc/groups.xml index 2218f74..35f0cf2 100644 --- a/doc/groups.xml +++ b/doc/groups.xml @@ -406,12 +406,8 @@ gap> c2 := Subgroup( d8, [ (2,4) ] );; gap> SortedList( IdempotentEndomorphismsWithImage( gens, c2 ) ); [ [ (), (2,4) ], [ (2,4), () ] ] gap> data:= IdempotentEndomorphismsData( d8 );; -gap> data.images; -[ [ [ (), () ] ], [ [ (), (2,4) ], [ (2,4), () ] ], - [ [ (), (1,3) ], [ (1,3), () ] ], - [ [ (), (1,2)(3,4) ], [ (1,2)(3,4), (1,2)(3,4) ] ], - [ [ (), (1,4)(2,3) ], [ (1,4)(2,3), (1,4)(2,3) ] ], - [ [ (1,2,3,4), (1,2)(3,4) ] ] ] +gap> Length( data.images ); +6 gap> all:= IdempotentEndomorphisms( d8 );; gap> allim := List( all, m -> MappingGeneratorsImages(m)[2] );; gap> ## the list of 10 sets of images sorted: From cdd2ee056b2960eed247ec29ab3a4a91fae80a20 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 9 Sep 2026 17:12:41 +0100 Subject: [PATCH 10/10] note on extracted files in the manual introduction --- CHANGES.md | 5 +++++ doc/intro.xml | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f575b28..71e9ecd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ # CHANGES log for the 'Utils' package +## Version 0.99 for GAP 4.16.1 (09/09/26) + * (09/09/26) since now using AutoDoc to extract tests from the manual, + many of the original tests are no longer needed, so removed. + * (08/09/26) extensive changes to the Download function + ## Version 0.98 for GAP 4.16.0 (04/08/26) * (04/08/26) changed Fitting series examples to just show StructureDescription diff --git a/doc/intro.xml b/doc/intro.xml index 3556f41..071a406 100644 --- a/doc/intro.xml +++ b/doc/intro.xml @@ -2,7 +2,7 @@ - + @@ -78,8 +78,16 @@ may be rebuilt as follows: gap> ReadPackage( "utils", "makedoc.g" ); ]]>

-It is possible to check that the package has been installed correctly -by running the test files (which terminates the &GAP; session): + +This package now uses the AutoDoc package +to extract test files from the examples in the manual. +Many of the original test files, +which duplicated these examples, have now been deleted. +The user can ensure that the full set of test files exists on their system +by rebuilding the manual, as described above. +

+It is then possible to check that the package has been installed correctly +by running the test suite (this terminates the &GAP; session):

ReadPackage( "utils", "tst/testall.g" );