Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions doc/ref/lists.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1462,16 +1462,21 @@ copy using <Ref Func="Immutable"/>.
<Section Label="Sorting Lists">
<Heading>Sorting Lists</Heading>

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 <C>Stable</C> are stable (equal
elements keep the same relative order in the sorted list) and use
merge sort. Finally, the functions which begin <C>Shell</C> use the shell
sort which was GAP's default search algorithm before 4.9.

<Ref Oper="Sortex"/> and <Ref Attr="SortingPerm"/> are also stable.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move the paragraph to the beginning of the manual section on Sorting Lists.
In particular for someone reading the manual (and not the source),
it is not clear that this paragraph belongs to all subsections and not just to the last one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now done. Also mentioned better in the documentation for sortex that it is stable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great.
Thanks for this improvement.


<#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.

</Section>


Expand Down
2 changes: 2 additions & 0 deletions lib/list.gd
Original file line number Diff line number Diff line change
Expand Up @@ -1665,6 +1665,8 @@ DeclareOperation( "StableSortBy", [IsList and IsMutable, IsFunction ] );
## that can be applied to <A>list</A> to obtain the sorted list.
## The one argument form sorts via the operator <C>&lt;</C>,
## the two argument form sorts w.r.t. the function <A>func</A>.
## The permutation returned by <Ref Func="Sortex"/> 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 <C>&lt;</C> is defined for all element pairs,
## see&nbsp;<Ref Sect="Comparison Operations for Elements"/>)
Expand Down
35 changes: 5 additions & 30 deletions lib/list.gi
Original file line number Diff line number Diff line change
Expand Up @@ -2373,7 +2373,7 @@ InstallMethod( Sortex,

n := Length(list);
index := [1..n];
SortParallel(list, index);
StableSortParallel(list, index);
return PermList(index)^-1;

end );
Expand All @@ -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 );
Expand Down Expand Up @@ -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( "<list> must have length at most ", MAX_SIZE_LIST_INTERNAL );
fi;

# make a new list that contains the elements of <list> 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 <list> 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 -> () );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChrisJefferson any particular reason this method was removed? I see no mention of this change in the PR description nor the commit message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was part of making SortingPerm be exactly the same as SortEx.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why that requires removing this optimization, though? Now if the input is sorted, we make a copy, sort that, and compute the identity permutation from that...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could probably have been left in, I wouldn't have a problem with it being re-added but I wasn't sure it was worth it, for a fairly unusual case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this method as an illustration of the idea to avoid working by using known information.
If the presence of such methods for fairly unusual cases does not slow down
the computations in the usual cases
then these methods are beneficial.
If this is not the case then it might be interesting to discuss the situation in detail,
perhaps in some tutorial.



#############################################################################
Expand Down
3 changes: 3 additions & 0 deletions tst/testbugfix/2018-07-18-sortex.tst
Original file line number Diff line number Diff line change
@@ -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)
14 changes: 13 additions & 1 deletion tst/testinstall/listgen.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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 ] );
Expand Down