From 397726308916f79f25cc1f59a735bf6664d38f99 Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Wed, 18 Jul 2018 14:05:35 +0100 Subject: [PATCH 1/4] Make Sortex use a stable sort --- lib/list.gd | 2 +- lib/list.gi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/list.gd b/lib/list.gd index 56862a3f83..0be88547ae 100644 --- a/lib/list.gd +++ b/lib/list.gd @@ -1661,7 +1661,7 @@ DeclareOperation( "StableSortBy", [IsList and IsMutable, IsFunction ] ); ## ## ## -## sorts the list list and returns a permutation +## stable sorts the list list and returns a permutation ## that can be applied to list to obtain the sorted list. ## The one argument form sorts via the operator <, ## the two argument form sorts w.r.t. the function func. diff --git a/lib/list.gi b/lib/list.gi index 67952d8de5..afa043f71d 100644 --- a/lib/list.gi +++ b/lib/list.gi @@ -2373,7 +2373,7 @@ InstallMethod( Sortex, n := Length(list); index := [1..n]; - SortParallel(list, index); + StableSortParallel(list, index); return PermList(index)^-1; end ); @@ -2391,7 +2391,7 @@ InstallMethod( Sortex, n := Length(list); index := [1..n]; - SortParallel(list, index, comp); + StableSortParallel(list, index, comp); return PermList(index)^-1; end ); From 20debaa5693087e099926375c059a60633b49a34 Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Wed, 18 Jul 2018 14:06:01 +0100 Subject: [PATCH 2/4] Make SortingPerm use SortEx --- lib/list.gi | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/lib/list.gi b/lib/list.gi index afa043f71d..36c77f7159 100644 --- a/lib/list.gi +++ b/lib/list.gi @@ -2434,37 +2434,12 @@ end ); InstallMethod( SortingPerm, [ IsDenseList ], function( list ) - local both, perm, i, l; + local copy; - # {\GAP} supports permutations only up to `MAX_SIZE_LIST_INTERNAL'. - if not IsSmallList( list ) then - Error( " must have length at most ", MAX_SIZE_LIST_INTERNAL ); - fi; - - # make a new list that contains the elements of and their indices - both := []; - l:= Length( list ); - for i in [ 1 .. l ] do - both[i] := [ list[i], i ]; - od; - - # Sort the new list according to the first item (stable). - # This needs more memory than a call of 'Sort' but is much faster. - # (The change was proposed by Frank Lübeck.) - both := Set( both ); - - # Remember the permutation. - perm := []; - perm{ [ 1 .. l ] }:= both{ [ 1 .. l ] }[2]; - - # return the permutation mapping onto the sorted list - return PermList( perm )^(-1); + copy := ShallowCopy(list); + return Sortex(copy); end ); -InstallMethod( SortingPerm, - "for a dense and sorted list", - [ IsDenseList and IsSortedList ], SUM_FLAGS, - list -> () ); ############################################################################# From 94af0f94194cb630d814c37d62ea85c7fd2b8ad2 Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Wed, 18 Jul 2018 14:06:22 +0100 Subject: [PATCH 3/4] Add tests for Sortex and SortingPerm --- tst/testbugfix/2018-07-18-sortex.tst | 3 +++ tst/testinstall/listgen.tst | 14 +++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2018-07-18-sortex.tst diff --git a/tst/testbugfix/2018-07-18-sortex.tst b/tst/testbugfix/2018-07-18-sortex.tst new file mode 100644 index 0000000000..1e7ef8d7bd --- /dev/null +++ b/tst/testbugfix/2018-07-18-sortex.tst @@ -0,0 +1,3 @@ +gap> ll:= [ 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1, 2 ];; +gap> Sortex( ll ); +(2,13,19,10,5,15,7,16,8,4)(3,14,20,22,23,24,12,6)(9,17)(11,18,21) diff --git a/tst/testinstall/listgen.tst b/tst/testinstall/listgen.tst index 5fcd9fedb2..8c1cf1dffb 100644 --- a/tst/testinstall/listgen.tst +++ b/tst/testinstall/listgen.tst @@ -74,8 +74,20 @@ gap> l := [ 2, 3, 4, 1, 5, 10, 9, 7, 8, 6 ];; gap> SortBy(l,AINV); gap> l; [ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ] -gap> perm:= Sortex( [ 2, 3, 4, 1, 5, 10, 9, 7, 8, 6 ] ); +gap> l2 := [ 2, 3, 4, 1, 5, 10, 9, 7, 8, 6 ];; +gap> lcpy := List(l2);; +gap> permsp := SortingPerm(l2); (1,2,3,4)(6,10)(7,9,8) +gap> l2 = lcpy; +true +gap> perm:= Sortex(l2); +(1,2,3,4)(6,10)(7,9,8) +gap> SortingPerm(l2); +() +gap> Sortex(l2); +() +gap> IsSet(l2); +true gap> Permuted( [ 2, 3, 4, 1, 5, 10, 9, 7, 8, 6 ], perm ); [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] gap> Product( [ 2, 3, 4, 1, 5, 10, 9, 7, 8, 6 ] ); From 87a0d0726cfb0951d82d2c1c9e74b3719d837da8 Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Fri, 20 Jul 2018 08:45:14 +0100 Subject: [PATCH 4/4] Improve sort documentation in lists.xml --- doc/ref/lists.xml | 13 +++++++++---- lib/list.gd | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/doc/ref/lists.xml b/doc/ref/lists.xml index e440b79392..83d0664413 100644 --- a/doc/ref/lists.xml +++ b/doc/ref/lists.xml @@ -1462,16 +1462,21 @@ copy using .
Sorting Lists +GAP implements three different families of sorting algorithms. The +default algorithm is pattern-defeating quicksort, a variant of quicksort +which performs better on partially sorted lists and has good worst-case +behaviour. The functions which begin Stable are stable (equal +elements keep the same relative order in the sorted list) and use +merge sort. Finally, the functions which begin Shell use the shell +sort which was GAP's default search algorithm before 4.9. + + and are also stable. <#Include Label="Sort"> <#Include Label="SortParallel"> <#Include Label="Sortex"> <#Include Label="SortingPerm"> -The default methods for all of these sorting operations currently -use Shell sort as it has a comparable performance to Quicksort for lists of -length at most a few thousands, and has better worst-case behaviour. -
diff --git a/lib/list.gd b/lib/list.gd index 0be88547ae..5d4209629a 100644 --- a/lib/list.gd +++ b/lib/list.gd @@ -1661,10 +1661,12 @@ DeclareOperation( "StableSortBy", [IsList and IsMutable, IsFunction ] ); ## ## ## -## stable sorts the list list and returns a permutation +## sorts the list list and returns a permutation ## that can be applied to list to obtain the sorted list. ## The one argument form sorts via the operator <, ## the two argument form sorts w.r.t. the function func. +## The permutation returned by will keep +## elements which compare equal in the same relative order. ## (If the list is not homogeneous it is the user's responsibility to ensure ## that < is defined for all element pairs, ## see )