From a9d1bb127c45520ccc324f4bc50a82186c68b742 Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Tue, 12 Nov 2019 16:52:20 +0000 Subject: [PATCH 1/3] Convert tabs to spaces in DoStringPerm --- lib/permutat.g | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/permutat.g b/lib/permutat.g index 797a8ad129..06a12a6f14 100644 --- a/lib/permutat.g +++ b/lib/permutat.g @@ -742,24 +742,24 @@ local str, i, j; else str := ""; for i in [ 1 .. LargestMovedPoint( perm ) ] do - j := i ^ perm; - while j > i do j := j ^ perm; od; - if j = i and i ^ perm <> i then - Append( str, "(" ); - Append( str, String( i ) ); - j := i ^ perm; - while j > i do - Append( str, "," ); - if hint then Append(str,"\<\>"); fi; - Append( str, String( j ) ); - j := j ^ perm; - od; - Append( str, ")" ); - if hint then Append(str,"\<\<\>\>"); fi; - fi; + j := i ^ perm; + while j > i do j := j ^ perm; od; + if j = i and i ^ perm <> i then + Append( str, "(" ); + Append( str, String( i ) ); + j := i ^ perm; + while j > i do + Append( str, "," ); + if hint then Append(str,"\<\>"); fi; + Append( str, String( j ) ); + j := j ^ perm; + od; + Append( str, ")" ); + if hint then Append(str,"\<\<\>\>"); fi; + fi; od; if Length(str)>4 and str{[Length(str)-3..Length(str)]}="\<\<\>\>" then - str:=str{[1..Length(str)-4]}; # remove tailing line breaker + str:=str{[1..Length(str)-4]}; # remove tailing line breaker fi; ConvertToStringRep( str ); fi; From ff4c134951308a171dc0a6ceb02aaa3c59ad160c Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Tue, 12 Nov 2019 16:54:24 +0000 Subject: [PATCH 2/3] Speed up converting permutations to strings Remove old O(n^2) algorithm with O(n) algorithm --- lib/permutat.g | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/permutat.g b/lib/permutat.g index 06a12a6f14..cfea2b9cb7 100644 --- a/lib/permutat.g +++ b/lib/permutat.g @@ -735,20 +735,22 @@ end ); #m String( ) . . . . . . . . . . . . . . . . . . . for a permutation ## BIND_GLOBAL("DoStringPerm",function( perm,hint ) -local str, i, j; +local str, i, j, maxpnt, blist; if IsOne( perm ) then str := "()"; else str := ""; + maxpnt := LargestMovedPoint( perm ); + blist := BlistList([1..maxpnt], []); for i in [ 1 .. LargestMovedPoint( perm ) ] do - j := i ^ perm; - while j > i do j := j ^ perm; od; - if j = i and i ^ perm <> i then + if not blist[i] and i ^ perm <> i then + blist[i] := true; Append( str, "(" ); Append( str, String( i ) ); j := i ^ perm; while j > i do + blist[j] := true; Append( str, "," ); if hint then Append(str,"\<\>"); fi; Append( str, String( j ) ); From b12bffe75b81019f3f6ca190f48f10e086e74957 Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Tue, 12 Nov 2019 17:00:34 +0000 Subject: [PATCH 3/3] Speed up Printing permutations Replace old O(n^2) algorithm with O(n) one, because unlike the comment, we are no longer limited to 9600 baud and can produce some large permutations --- src/permutat.cc | 25 ++++++++++++++----------- tst/testinstall/perm.tst | 13 ++++++++++++- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/permutat.cc b/src/permutat.cc index 47cf2be266..920f28289e 100644 --- a/src/permutat.cc +++ b/src/permutat.cc @@ -163,10 +163,8 @@ static Obj InvPerm(Obj perm); ** uses the degree to print all points with same width, which looks nicer. ** Linebreaks are prefered most after cycles and next most after commas. ** -** It does not remember which points have already been printed. To avoid -** printing a cycle twice each is printed with the smallest element first. -** This may in the worst case, for (1,2,..,n), take n^2/2 steps, but is fast -** enough to keep a terminal at 9600 baud busy for all but the extrem cases. +** It remembers which points have already been printed, to avoid O(n^2) +** behaviour. */ template static void PrintPerm(Obj perm) @@ -187,29 +185,34 @@ static void PrintPerm(Obj perm) else if ( degPerm < 10000 ) { fmt1 = "%>(%>%4d%<"; fmt2 = ",%>%4d%<"; } else { fmt1 = "%>(%>%5d%<"; fmt2 = ",%>%5d%<"; } + UseTmpPerm(SIZE_OBJ(perm)); + T * ptSeen = ADDR_TMP_PERM(); + + // clear the buffer bag + for (p = 0; p < DEG_PERM(perm); p++) + ptSeen[p] = 0; + /* run through all points */ isId = 1; ptPerm = CONST_ADDR_PERM(perm); for ( p = 0; p < degPerm; p++ ) { - - /* find the smallest element in this cycle */ - q = ptPerm[p]; - while ( p < q ) q = ptPerm[q]; - /* if the smallest is the one we started with lets print the cycle */ - if ( p == q && ptPerm[p] != p ) { + if (!ptSeen[p] && ptPerm[p] != p) { + ptSeen[p] = 1; isId = 0; Pr(fmt1,(Int)(p+1),0L); ptPerm = CONST_ADDR_PERM(perm); for ( q = ptPerm[p]; q != p; q = ptPerm[q] ) { + ptSeen[q] = 1; Pr(fmt2,(Int)(q+1),0L); ptPerm = CONST_ADDR_PERM(perm); + ptSeen = ADDR_TMP_PERM(); } Pr("%<)",0L,0L); /* restore pointer, in case Pr caused a garbage collection */ ptPerm = CONST_ADDR_PERM(perm); + ptSeen = ADDR_TMP_PERM(); } - } /* special case for the identity */ diff --git a/tst/testinstall/perm.tst b/tst/testinstall/perm.tst index 734ab7ea06..28935ff656 100644 --- a/tst/testinstall/perm.tst +++ b/tst/testinstall/perm.tst @@ -1,4 +1,4 @@ -#@local checklens,n,permAll,permBig,permSml,x,y, moved +#@local checklens,n,permAll,permBig,permSml,x,y,moved,p gap> START_TEST("perm.tst"); # Permutations come in two flavors in GAP, with two TNUMs: T_PERM2 for @@ -87,6 +87,17 @@ gap> Print(permBig * (5,999999), "\n"); ( 1, 2, 3)( 5,999999), ( 1, 3, 2)( 5,999999), ( 1, 3)( 5,999999) ] +# Check String of large permutation +# Check length, beginning and end, as the string is too long to include in +# a test file +gap> p := String(PermList(Concatenation([2..2^20], [1])));; +gap> Length(p) = 7277505; +true +gap> p{[1..40]}; +"(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16," +gap> p{[Length(p)-40..Length(p)]}; +",1048572,1048573,1048574,1048575,1048576)" + # # EqPerm #