diff --git a/lib/permutat.g b/lib/permutat.g index 797a8ad129..cfea2b9cb7 100644 --- a/lib/permutat.g +++ b/lib/permutat.g @@ -735,31 +735,33 @@ 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 - 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; + 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 ) ); + 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; 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 #