############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Martin Schönert. ## ## Copyright of GAP belongs to its developers, whose names are too numerous ## to list here. Please refer to the COPYRIGHT file for details. ## ## SPDX-License-Identifier: GPL-2.0-or-later ## ## This file contains methods for lists in general. ##
############################################################################# ## #M methods for nesting depths for some quick cases ##
InstallMethod(NestingDepthA, [IsCyclotomicCollection and IsGeneralizedRowVector],
v->1);
InstallMethod(NestingDepthM, [IsCyclotomicCollection and IsMultiplicativeGeneralizedRowVector],
v->1);
InstallMethod(NestingDepthA, [IsFFECollection and IsGeneralizedRowVector],
v->1);
InstallMethod(NestingDepthM, [IsFFECollection and IsMultiplicativeGeneralizedRowVector],
v->1);
InstallMethod(NestingDepthA, [IsCyclotomicCollColl and
IsGeneralizedRowVector],
m->2);
InstallMethod(NestingDepthM, [IsCyclotomicCollColl and
IsOrdinaryMatrix and IsMultiplicativeGeneralizedRowVector], function( m )
local t;
t := TNUM_OBJ(m[1]); if FIRST_LIST_TNUM > t or LAST_LIST_TNUM < t then
TryNextMethod(); else
return 2; fi; end );
#T just a temporary (?) hack in order to exclude lists of class functions
InstallMethod(NestingDepthA, [IsFFECollColl and IsGeneralizedRowVector],
m->2);
InstallMethod(NestingDepthM, [IsFFECollColl and IsOrdinaryMatrix and IsMultiplicativeGeneralizedRowVector], function(m)
local t;
t := TNUM_OBJ(m[1]); if FIRST_LIST_TNUM > t or LAST_LIST_TNUM < t then
TryNextMethod(); else
return 2; fi; end);
############################################################################# ## #M methods for comparisons ## ## The default method `EQ_LIST_LIST_DEFAULT' is applicable only to small ## lists in the sense of `IsSmallList'. ## For finite lists that do not know to be small, first this property is ## checked, and if the lists are not small then the loop is done in {\GAP}. ##
InstallMethod( EQ, "for two small lists",
IsIdenticalObj,
[ IsList and IsSmallList, IsList and IsSmallList ],
EQ_LIST_LIST_DEFAULT );
InstallMethod( EQ, "for two finite lists (not necessarily small)",
IsIdenticalObj,
[ IsList and IsFinite, IsList and IsFinite ], function( list1, list2 )
local len, i;
# We ask for being small in order to catch the default methods # directly in the next call if possible. if IsSmallList( list1 ) then if IsSmallList( list2 ) then
return EQ_LIST_LIST_DEFAULT( list1, list2 ); else
return false; fi; elif IsSmallList( list2 ) then
return false; else
# None of the lists is small.
len:= Length( list1 ); if len <> Length( list2 ) then
return false; fi;
i:= 1; while i <= len do if IsBound( list1[i] ) then if IsBound( list2[i] ) then if list1[i] <> list2[i] then
return false; fi; else
return false; fi; elif IsBound( list2[i] ) then
return false; fi;
i:= i+1;
od;
return true;
fi; end );
InstallMethod( EQ, "for two lists, the first being empty",
[ IsList and IsEmpty, IsList ],
SUM_FLAGS, #can't do better function( empty, list )
return IsEmpty( list ); end );
InstallMethod( EQ, "for two lists, the second being empty",
[ IsList, IsList and IsEmpty ],
SUM_FLAGS, #can't do better function( list, empty )
return IsEmpty( list ); end );
############################################################################# ## #M \=( <list1>, <list2> ) . . .. . . . . . . . . . for two lists ##
InstallMethod( EQ, "for two lists with length - last resort",
IsIdenticalObj,
[ IsList and HasLength, IsList and HasLength ], function(list1, list2) if Length(list1) <> Length(list2) then
return false; fi;
# use the kernel method if small lists if IsSmallList(list1) and IsSmallList(list2) then
return EQ_LIST_LIST_DEFAULT(list1, list2); fi;
if IsInfinity(Length(list1)) then ## warning - trying to compare infinite lists
Info(InfoWarning, 1, "EQ: Attempting EQ on infinite lists"); fi;
TryNextMethod(); end);
InstallMethod( EQ, "for two lists - last resort",
IsIdenticalObj,
[ IsList, IsList], function(list1, list2)
local i;
# just compare elementwise
i := 1; while true do while IsBound(list1[i]) and IsBound(list2[i]) do if list1[i] <> list2[i] then
return false; fi;
i := i + 1;
od;
if IsBound(list1[i]) or IsBound(list2[i]) then
return false; fi;
# Now we've found an unbound spot on both lists # maybe we know enough to stop now # anyway at this stage we really must check the Lengths and hope # that they are computable now.
if Length(list1) <= i then
return Length(list2) <= i; elif Length(list2) <= i then
return false; fi;
i := i + 1;
od; end);
InstallMethod( LT, "for two small homogeneous lists",
IsIdenticalObj,
[ IsHomogeneousList and IsSmallList,
IsHomogeneousList and IsSmallList ],
LT_LIST_LIST_DEFAULT );
InstallMethod( LT, "for two finite homogeneous lists (not necessarily small)",
IsIdenticalObj,
[ IsHomogeneousList and IsFinite, IsHomogeneousList and IsFinite ],
LT_LIST_LIST_FINITE );
############################################################################# ## #M \in( <obj>, <list> ) ##
InstallMethod( IN, "for an object, and an empty list",
[ IsObject, IsList and IsEmpty ],
ReturnFalse );
InstallMethod( IN, "for wrong family relation",
IsNotElmsColls,
[ IsObject, IsCollection ],
SUM_FLAGS, # can't do better
ReturnFalse );
InstallMethod( IN, "for an object, and a small list",
[ IsObject, IsList and IsSmallList ],
IN_LIST_DEFAULT );
InstallMethod( IN, "for an object, and a list",
[ IsObject, IsList ], function( elm, list )
local len, i; if IsSmallList( list ) then
return IN_LIST_DEFAULT( elm, list ); elif IsFinite( list ) then
len:= Length( list );
i:= 1; while i <= len do if IsBound( list[i] ) and elm = list[i] then
return true; fi;
i:= i+1;
od;
return false; else
TryNextMethod(); fi; end );
############################################################################# ## #M <elm> \in <whole-family> ##
InstallMethod( IN, "for an object, and a collection that contains the whole family",
IsElmsColls,
[ IsObject, IsCollection and IsWholeFamily ],
SUM_FLAGS, # can't do better
ReturnTrue );
############################################################################# ## #M Display( <list> ) ##
InstallMethod( Display, "for a (finite) list",
[ IsList ], function( list )
Print( list, "\n" ); end );
############################################################################# ## #M String( <list> ) . . . . . . . . . . . . . . . . . . . . . . for a list #M String( <range> ) . . . . . . . . . . . . . . . . . . . . . . for a range ##
InstallMethod( String, "for a (finite) list",
[ IsList ], function ( list )
local str, i;
# Check that we are in the right method. if not IsFinite( list ) then
TryNextMethod(); fi;
# We cannot handle the case of an empty string in the method for strings # because the type of the empty string need not satisfy the requirement # `IsString'. if IsEmptyString( list ) then
return ""; fi;
str := "[ "; for i in [ 1 .. Length( list ) ] do if IsBound( list[ i ] ) then if IsStringRep( list[i] )
or ( IsString( list[i] ) and not IsEmpty( list[i] ) ) then
Append( str, "\"" );
Append( str, String( list[i] ) );
Append( str, "\"" ); else
Append( str, String( list[i] ) ); fi; fi; if i <> Length( list ) then
Append( str, ", " ); fi;
od;
Append( str, " ]" );
ConvertToStringRep( str );
return str; end );
InstallMethod( ViewString, "call ViewString and incorporate hints",
[ IsList and IsFinite], function ( list )
local str,ls, i;
# We have to handle empty string and empty list specially because # IsString( [ ] ) returns true
if Length(list) = 0then if IsEmptyString( list ) then
return "\"\""; else
return "[ ]"; fi; fi;
if IsString( list ) then
return VIEW_STRING_FOR_STRING(list); fi;
# make strings for objects in l
ls:=[]; for i in [1..Length(list)] do if IsBound(list[i]) then
str:=ViewString(list[i]); if str=DEFAULTVIEWSTRING then # there might not be a method
str:=String(list[i]); fi;
ls[i]:=str; else
ls[i]:=""; fi;
od;
# The line break hints are consistent with those # that appear in the kernel function 'PrintListDefault' # and in the 'ViewObj' method for finite lists.
str:= "\>\>[ \>\>"; for i in [ 1 .. Length( list ) ] do if ls[i] <> ""then if1 < i then
Append( str, "\<,\< \>\>" ); fi;
Append( str, ls[i] ); elif1 < i then
Append( str, "\<,\<\>\>" ); fi;
od;
Append( str, " \<\<\<\<]" );
ConvertToStringRep( str );
return str; end );
InstallMethod( DisplayString, "for a range",
[ IsRange ],
range -> Concatenation( String( range ), "\n" ) );
InstallMethod( ViewString, "for a range",
[ IsRange ], function( list )
local str;
str := "[ ";
Append( str, String( list[1] ) ); if Length( list ) > 1then if Length(list) = 2 or list[2] - list[1] <> 1then
Append( str, ", " );
Append( str, String( list[2] ) ); fi; if Length(list) > 2then
Append( str, " .. " );
Append( str, String( Last(list) ) ); fi; fi;
Append( str, " ]" );
Assert(0, IsStringRep(str));
ConvertToStringRep( str );
return str; end );
InstallOtherMethod( Size, "for a list that is a collection",
[ IsList and IsCollection ],
Length );
############################################################################# ## #M Representative( <list> ) ##
InstallOtherMethod( Representative, "for a list",
[ IsList ], function( list )
local elm; for elm in list do
return elm;
od;
Error( "<list> must be nonempty to have a representative" ); end );
############################################################################# ## #M RepresentativeSmallest( <list> ) ##
InstallOtherMethod( RepresentativeSmallest, "for an empty list",
[ IsList and IsEmpty ], function( list )
Error( "<C> must be nonempty to have a representative" ); end );
InstallOtherMethod( RepresentativeSmallest, "for a strictly sorted list",
[ IsSSortedList ], function( list )
return list[1]; end );
InstallOtherMethod(
RepresentativeSmallest, "for a list",
[ IsList ],
MinimumList );
############################################################################# ## #M Random( <list> ) . . . . . . . . . . . . . . . . for a dense small list ##
InstallMethod( Random, "for a dense small list",
[ IsList and IsDenseList and IsSmallList ],
RandomList );
InstallMethod( Random, "for a dense (small) list",
[ IsList and IsDenseList ], function( list ) if IsSmallList( list ) then
return RandomList( list ); else
TryNextMethod(); fi; end );
############################################################################# ## #M IsSmallList( <list> ) ##
InstallMethod( IsSmallList, "for a list",
[ IsList ],
list -> Length( list ) <= MAX_SIZE_LIST_INTERNAL );
############################################################################# ## #M IsSmallList( <non-list> ) ##
InstallOtherMethod( IsSmallList, "for a non-list",
[ IsObject ], function( nonlist ) if IsList( nonlist ) then
TryNextMethod(); else
return false; fi; end );
############################################################################# ## #M ConstantTimeAccessList( <list> ) #M ShallowCopy( <list> ) ## ## `ConstantTimeAccessList' and `ShallowCopy' have the same methods for ## lists: These methods return mutable lists, but since ## `ConstantTimeAccessList' is an attribute, its results are made immutable ## by the kernel. ## ## `ConstantTimeAccessList' has an additional ``almost immediate method'' ## constant time access lists: this method just returns the argument. (This ## cannot work for `ShallowCopy', because the argument could be immutable.) ##
Perform( [ ConstantTimeAccessList, ShallowCopy ], function(op)
InstallMethod( op, "for a list",
[ IsList ], function( list )
local new, i;
new:= [ ]; for i in [ 1 .. Length( list ) ] do if IsBound( list[ i ] ) then
new[ i ] := list[ i ]; fi;
od;
return new; end );
InstallMethod( op, "for a strictly sorted list",
[ IsList and IsSSortedList ], function( list )
local new, i;
new:= [ ]; for i in [ 1 .. Length( list ) ] do if IsBound( list[ i ] ) then
new[ i ] := list[ i ]; fi;
od;
SetIsSSortedList( new, true );
return new; end );
InstallMethod( op, "for a dense list",
[ IsList and IsDenseList ], function( list ) if IsSmallList( list ) then
return list{ [ 1 .. Length( list ) ] }; else
Error( "resulting list would be too large (length ",
Length( list ), ")" ); fi; end );
InstallMethod( op, "for a strictly sorted dense list",
[ IsList and IsDenseList and IsSSortedList ], function( list ) if IsSmallList( list ) then
list:= list{ [ 1 .. Length( list ) ] };
SetIsSSortedList( list, true );
return list; else
Error( "resulting list would be too large (length ",
Length( list ), ")" ); fi; end );
end);
InstallMethod( ConstantTimeAccessList, "for a constant time access list",
[ IsList and IsConstantTimeAccessList ],
SUM_FLAGS, # can't do better
Immutable );
############################################################################# ## #M AsList( <list> ) ##
InstallOtherMethod( AsList, "for a list",
[ IsList ],
list -> ConstantTimeAccessList( Enumerator( list ) ) );
InstallOtherMethod( AsList, "for a constant time access list",
[ IsList and IsConstantTimeAccessList ],
Immutable );
############################################################################# ## #M AsPlist( <list> ) ##
InstallOtherMethod( AsPlist, "for a plist",
[IsList and IsPlistRep],
x -> x );
InstallOtherMethod( AsPlist, "for a list",
[ IsList ], function(l)
l:=AsList(l); if not IsPlistRep(l) then
l:=PlainListCopy(l); # explicit copy for objects that claim to # be constant time access but not plists. fi;
return l; end );
############################################################################# ## #M AsSSortedList( <list> ) ## ## If <list> is a (not necessarily dense) list whose elements lie in the ## same family then 'AsSSortedList' is applicable. ##
InstallOtherMethod( AsSSortedList, "for a list",
[ IsList ],
list -> ConstantTimeAccessList( EnumeratorSorted( list ) ) );
InstallOtherMethod(AsSSortedList, "for a plist",
[IsList and IsPlistRep],
AsSSortedListList );
InstallOtherMethod(AsSSortedList, "for a list",
[ IsList ],
l -> AsSSortedListList( AsPlist( l ) ) );
############################################################################# ## #M EnumeratorSorted( <list> ) ##
InstallOtherMethod( EnumeratorSorted, "for a plist",
[IsList and IsPlistRep], function( l ) if IsSSortedList( l ) then
return l; fi;
return AsSSortedListList( l ); end );
InstallOtherMethod( EnumeratorSorted, "for a list", [ IsList ], function(l) if IsSSortedList(l) then
return l; fi;
return AsSSortedListList(AsPlist(l)); end);
############################################################################# ## #M SSortedList( <list> ) . . . . . . . . . . . set of the elements of a list ##
InstallMethod( SSortedList, "for a plist",
[ IsList and IsPlistRep ],
SSortedListList );
InstallMethod( SSortedList, "for a list",
[ IsList ],
l->SSortedListList(AsPlist(l)) );
############################################################################# ## #M SSortedList( <list>, <func> ) ##
InstallMethod( SSortedList, "for a list, and a function",
[ IsList, IsFunction ], function ( list, func )
local res, i, squashsize;
squashsize := 100;
res := []; for i in list do
Add( res, func( i ) ); if Length(res) > squashsize then
res := Set(res);
squashsize := Maximum(100, Size(res) * 2); fi;
od;
return Set(res); end );
############################################################################# ## #F IteratorList( <list> ) ## ## returns an iterator constructed from the list <list>, ## which stores the underlying list in the component `list' ## and the current position in the component `pos'. ## ## It may happen that the underlying list is a enumerator of a domain ## whose size cannot be computed easily. ## In such cases, the methods for `IsDoneIterator' and `NextIterator' ## shall avoid calling `Length' for the enumerator. ## Therefore a special representation exist for iterators of dense immutable ## lists. ## (Note that the `Length' call is unavoidable for iterators of non-dense ## lists.) ##
BindGlobal( "IsDoneIterator_List",
iter -> ( iter!.pos >= iter!.len ) );
BindGlobal( "NextIterator_List", function ( iter )
local p, l;
p := iter!.pos; if p = iter!.len then
Error("<iter> is exhausted"); fi;
l := iter!.list;
p := p + 1; while not IsBound( l[ p ] ) do
p := p + 1;
od;
iter!.pos := p;
return l[ p ]; end );
BindGlobal( "NextIterator_DenseList", function ( iter )
local p;
p := iter!.pos + 1;
iter!.pos := p; #if not IsBound( iter!.list[ iter!.pos ] ) then # Error("<iter> is exhausted"); #fi;
return iter!.list[ p ]; end );
BindGlobal( "ShallowCopy_List",
iter -> rec( list := iter!.list,
pos := iter!.pos,
len := iter!.len ) );
InstallGlobalFunction( IteratorList, function ( list )
local iter;
iter := rec(
list := list,
pos := 0,
len := Length(list),
IsDoneIterator := IsDoneIterator_List,
ShallowCopy := ShallowCopy_List );
if IsDenseList( list ) and not IsMutable( list ) then
iter.NextIterator := NextIterator_DenseList; else
iter.NextIterator := NextIterator_List; fi;
############################################################################# ## #M IteratorSorted( <list> ) ##
InstallOtherMethod( IteratorSorted, "for a list",
[ IsList ], function( list ) if IsSSortedList( list ) then
return IteratorList( list ); else
return IteratorList( SSortedListList( list ) ); #T allowed?? fi; end );
############################################################################# ## #M SumOp( <list> ) . . . . . . . . . . . . . . . . . . . . for a dense list ##
InstallOtherMethod( SumOp, "for a dense list",
[ IsDenseList ], 1, function ( list )
local sum, i; if IsEmpty(list) then
sum := 0; else
sum := list[1]; for i in [2..Length(list)] do
sum := sum + list[i];
od; fi;
return sum; end );
############################################################################# ## #M SumOp( <list>, <init> ) . . . . . . . . . . for a list, and initial value ##
InstallOtherMethod( SumOp, "for a list, and initial value",
[ IsList, IsAdditiveElement ], 1, function ( list, init )
local elm; for elm in list do
init := init + elm;
od;
return init; end );
############################################################################# ## #M SumOp( <list>, <func> ) . . . . . . . . for a dense list, and a function ##
InstallOtherMethod( SumOp, "for a dense list, and a function",
[ IsDenseList, IsFunction ], 1, function( list, func )
local sum, i; if IsEmpty(list) then
sum := 0; else
sum := func( list[1] ); for i in [2..Length(list)] do
sum := sum + func( list[i] );
od; fi;
return sum; end );
############################################################################# ## #M SumOp( <list>, <func>, <init> ) . . . for list, function, and init. value ##
InstallOtherMethod( SumOp, "for a list, a function, and initial value",
[ IsList, IsFunction, IsAdditiveElement ], 1, function ( list, func, init )
local elm; for elm in list do
init := init + func( elm );
od;
return init; end );
############################################################################# ## #M ProductOp( <list> ) . . . . . . . . . . . . . . . . . . for a dense list ##
InstallOtherMethod( ProductOp, "for a dense list",
[ IsDenseList ], 1, function ( list )
local prod, i; if IsEmpty(list) then
prod := 1; else
prod := list[1]; for i in [2..Length(list)] do
prod := prod * list[i];
od; fi;
return prod; end );
############################################################################# ## #M ProductOp( <list>, <init> ) . . . . . . . . for a list, and initial value ##
InstallOtherMethod( ProductOp, "for a list, and initial value",
[ IsList, IsMultiplicativeElement ], 1, function ( list, init )
local elm; for elm in list do
init := init * elm;
od;
return init; end );
############################################################################# ## #M ProductOp( <list>, <func> ) . . . . . . for a dense list, and a function ##
InstallOtherMethod( ProductOp, "for a dense list and a function",
[ IsDenseList, IsFunction ], 1, function( list, func )
local prod, i; if IsEmpty(list) then
prod := 1; else
prod := func( list[1] ); for i in [2..Length(list)] do
prod := prod * func( list[i] );
od; fi;
return prod; end );
############################################################################# ## #M ProductOp( <list>, <func>, <init> ) . for list, function, and init. value ##
InstallOtherMethod( ProductOp, "for a list, a function, and initial value",
[ IsList, IsFunction, IsMultiplicativeElement ], 1, function ( list, func, init )
local elm; for elm in list do
init := init * func( elm );
od;
return init; end );
############################################################################# ## #M <list>{<poss>} #M <list>{<poss>}:=<objs> ## ## `ELMS_LIST_DEFAULT' applies `LEN_LIST' to both of its arguments, ## so its use is restricted to small lists. ## ## `ASSS_LIST_DEFAULT' tries to change its first argument into a plain list, ## and applies `LEN_LIST' to the other two arguments, ## so also the usage of `ASSS_LIST_DEFAULT' is restricted to small lists. ##
InstallMethod( ELMS_LIST, "for a small list and a small dense list",
[ IsList and IsSmallList, IsDenseList and IsSmallList ],
ELMS_LIST_DEFAULT );
InstallMethod( ELMS_LIST, "for a list and a dense list",
[ IsList, IsDenseList ], function( list, poslist )
local choice, i; if IsSmallList( poslist ) then if IsSmallList( list ) then
return ELMS_LIST_DEFAULT( list, poslist ); else
choice:= []; for i in poslist do
Add( choice, list[i] );
od;
return choice; fi; else
TryNextMethod(); fi; end );
InstallMethod( ASSS_LIST, "for a small mutable list, a small dense list, and a small list",
[ IsList and IsSmallList and IsMutable, IsDenseList and IsSmallList,
IsList and IsSmallList ],
ASSS_LIST_DEFAULT );
InstallMethod( ASSS_LIST, "for a mutable list, a dense list, and a list",
[ IsList and IsMutable, IsDenseList, IsList ], function( list, poslist, vallist )
local i; if IsSmallList( poslist ) and IsSmallList( vallist ) then if IsSmallList( list ) then
ASSS_LIST_DEFAULT( list, poslist, vallist ); else for i in [ 1 .. Length( poslist ) ] do
list[ poslist[i] ]:= vallist[i];
od; fi; else
TryNextMethod(); fi; end );
InstallOtherMethod( ASS_LIST, "error message for immutable list",
[IsList, IsPosInt, IsObject], -100, function(list, pos, v) if not IsMutable( list ) then
Error("The list you are trying to assign to is immutable"); else
TryNextMethod(); fi; end );
############################################################################# ## #M IsSSortedList( <non-list> ) ##
InstallOtherMethod( IsSSortedList, "for non-lists",
[ IsObject ], function( nonlist ) if IsList( nonlist ) then
TryNextMethod(); else
return false; fi; end );
############################################################################# ## #M IsSSortedList(<list>) ##
InstallMethod( IsSSortedList, "for a small list",
[ IsSmallList ],
IS_SSORT_LIST_DEFAULT );
InstallMethod( IsSSortedList, "for a homogeneous list (not nec. finite)",
[ IsHomogeneousList ], function( list )
local i; if IsSmallList( list ) then
return IS_SSORT_LIST_DEFAULT( list ); else
i:= 1; while i+1 <= Length( list ) do if list[ i+1 ] <= list[i] then
return false; fi;
i:= i+1;
od; fi; end );
############################################################################# ## #M IsSortedList(<list>) ##
InstallMethod( IsSortedList, "for a finite list",
[ IsList and IsFinite ], function(l)
local i; # shortcut: strictly sorted is stored for internally represented lists if IsInternalRep( l ) and IsSSortedList( l ) then
return true; fi;
if not IsBound(l[1]) then
return false; fi; for i in [1..Length(l)-1] do if not IsBound(l[i+1]) or l[i+1] < l[i] then
return false; fi;
od;
return true; end);
InstallMethod( IsSortedList, "for a list (not nec. finite)",
[ IsList ], function( list )
local i;
i:= 1; if not IsBound(list[1]) then
return false; fi; while i+1 <= Length( list ) do if not IsBound(list[i+1]) or list[ i+1 ] < list[i] then
return false; fi;
i:= i+1;
od;
return true; end );
############################################################################# ## #M IsSortedList( <non-list> ) ##
InstallOtherMethod( IsSortedList, "for non-lists",
[ IsObject ], function( nonlist ) if IsList( nonlist ) then
TryNextMethod(); else
return false; fi; end );
############################################################################# ## #M IsDuplicateFree( <list> ) ##
InstallMethod( IsDuplicateFree, "for a finite list",
[ IsList ], function( list )
local i; if not IsDenseList( list ) then
return false; elif not IsFinite( list ) then
TryNextMethod(); fi; for i in [ 1 .. Length( list ) ] do if Position( list, list[i], 0 ) < i then
return false; fi;
od;
return true; end );
############################################################################# ## #M DifferenceLists . . . . . . . . list without the elements in another list ##
InstallMethod( DifferenceLists, "homogeneous lists",
[IsHomogeneousList, IsHomogeneousList], function( list1, list2 )
local diff, e;
list2 := Set( list2 );
diff := []; for e in list1 do if not e in list2 then
Add( diff, e ); fi;
od;
return diff; end );
############################################################################# ## #M IsPositionsList(<list>) ##
InstallMethod( IsPositionsList, "for a small homogeneous list",
[ IsHomogeneousList and IsSmallList ],
IS_POSS_LIST_DEFAULT );
InstallMethod( IsPositionsList, "for a homogeneous list",
[ IsHomogeneousList ], function( list ) if IsSmallList( list ) then
return IS_POSS_LIST_DEFAULT( list ); else
TryNextMethod(); fi; end );
############################################################################# ## #M IsPositionsList( <non-list> ) ##
InstallOtherMethod( IsPositionsList, "for non-lists",
[ IsObject ], function( nonlist ) if IsList( nonlist ) then
TryNextMethod(); else
return false; fi; end );
############################################################################# ## #M Position( <list>, <obj>, <from> ) ##
InstallMethod( Position, "for a small list, an object, and an integer",
[ IsList and IsSmallList, IsObject, IsInt ],
POS_LIST_DEFAULT );
InstallMethod( Position, "for a (small) list, an object, and an integer",
[ IsList, IsObject, IsInt ], function( list, obj, start ) if IsSmallList( list ) then
return POS_LIST_DEFAULT( list, obj, start ); else
TryNextMethod(); fi; end );
InstallMethod( Position, "for a homog. list, an object not in the elements family, and an int.", function( F1, F2, F3 )
return HasElementsFamily(F1)
and not IsIdenticalObj( ElementsFamily(F1), F2 ); end,
[ IsHomogeneousList,
IsObject,
IsInt ],
ReturnFail );
InstallMethod( Position, "for a small sorted list, an object, and an integer",
[ IsSSortedList and IsSmallList, IsObject, IsInt ], function ( list, obj, start )
local pos;
#N 1996/08/14 M.Schönert 'POSITION_SORTED_LIST' should take 3 arguments #T (This method is used only for ``external'' lists, the kernel methods #T `PosPlistSort', `PosPlistHomSort' support the argument `start'.) if start = 0then
pos := POSITION_SORTED_LIST( list, obj ); # `PositionSorted' will not return fail. Therefore we have to test # explicitly once it had been called. if pos > Length( list ) or list[pos] <> obj then
return fail; fi; else
pos := POS_LIST_DEFAULT( list, obj, start ); fi;
return pos; end );
InstallMethod( Position, "for a sorted list, an object, and an integer",
[ IsSSortedList, IsObject, IsInt ], function ( list, obj, start )
local pos; if IsSmallList( list ) then if start = 0then
pos := POSITION_SORTED_LIST( list, obj ); # `PositionSorted' will not return fail. Therefore we have to test # explicitly once it had been called. if pos > Length( list ) or list[pos] <> obj then
return fail; fi; else
pos := POS_LIST_DEFAULT( list, obj, start ); fi;
return pos; else
TryNextMethod(); fi; end );
############################################################################# ## #M Position(<list>,<obj>,<from>) ## ## The following method is installed for external lists since internal lists ## do not store whether they are duplicate free. ## For external lists such as special enumerators of domains, ## e.g.~`Integers', one needs only a special method for `Position' with ## third argument zero (installed with requirement `IsZeroCyc'), ## the case of a positive third argument is then handled by the following ## generic method. ##
InstallMethod( Position, "for duplicate free list, object, and positive integer",
[ IsDuplicateFreeList, IsObject, IsPosInt ], function( list, obj, start )
local pos;
pos:= Position( list, obj, 0 ); if pos <> fail and start < pos then
return pos; else
return fail; fi; end );
if IsPlistRep(list) then
res := [];
p := 0; while true do
p := Position(list,obj,p); if p <> fail then
Add(res,p); else
break; fi;
od; else
res:= PositionsOp(list,obj); fi;
SetIsSSortedList( res, true );
return res; end ); # generic method for non-plain lists
InstallMethod(PositionsOp, [IsList, IsObject], function(list, obj)
local res, p;
res := [];
p := Position(list, obj); while p <> fail do
Add(res, p);
p := Position(list, obj, p);
od;
return res; end);
############################################################################# ## #M PositionCanonical( <list>, <obj> ) . . for internally represented lists ##
InstallMethod( PositionCanonical, "for internally represented lists, fall back on `Position'",
[ IsList and IsInternalRep, IsObject ], function( list, obj )
return Position( list, obj, 0 ); end );
InstallMethod( PositionCanonical, "internal small sorted lists, use `POSITION_SORTED_LIST'",
[ IsList and IsInternalRep and IsSSortedList and IsSmallList, IsObject ], function(l,o)
local p;
p:=POSITION_SORTED_LIST(l,o); if p=0 or p>Length(l) or l[p]<>o then
return fail; else
return p; fi; end);
InstallMethod( PositionSortedOp, "for small list, and object",
[ IsList and IsSmallList, IsObject ],
POSITION_SORTED_LIST );
InstallMethod( PositionSortedOp,
[ IsList, IsObject ], function( list, elm ) if IsSmallList( list ) then
return POSITION_SORTED_LIST( list, elm ); else
TryNextMethod(); fi; end );
InstallMethod( PositionSortedOp, "for small list, object, and function",
[ IsList and IsSmallList, IsObject, IsFunction ],
POSITION_SORTED_LIST_COMP );
InstallMethod( PositionSortedOp, "for list, object, and function",
[ IsList, IsObject, IsFunction ], function( list, elm, func ) if IsSmallList( list ) then
return POSITION_SORTED_LIST_COMP( list, elm, func ); else
TryNextMethod(); fi; end );
InstallMethod( PositionSortedByOp, "for a dense plain list, an object and a function",
[ IsDenseList and IsPlistRep, IsObject, IsFunction ],
POSITION_SORTED_BY);
InstallMethod( PositionSortedByOp, "for a dense list, an object and a function",
[ IsDenseList, IsObject, IsFunction ], function ( list, val, func )
local l, h, m; # simple binary search. The entry is in the range [l..h]
l := 0;
h := Length(list) + 1; while l + 1 < h do# list[l] < val && val <= list[h]
m := QuoInt(l + h, 2); # l < m < h if func(list[m]) < val then
l := m; # it's not in [lo..m], so take the upper part. else
h := m; # So val<=list[m][1], so the new range is [1..m]. fi;
od;
return h; end );
############################################################################# ## #F PositionSet( <list>, <obj> ) #F PositionSet( <list>, <obj>, <func> ) ##
InstallGlobalFunction( PositionSet, function( arg )
local list, obj, pos; if Length( arg ) = 2 and IsList( arg[1] ) then
list := arg[1];
obj := arg[2];
pos := PositionSorted( list, obj ); elif Length( arg ) = 3 and IsList( arg[1] ) and IsFunction( arg[3] ) then
list := arg[1];
obj := arg[2];
pos := PositionSorted( list, obj, arg[3] ); else
Error( "usage: PositionSet( <list>, <elm>[, <func>] )" ); fi;
if ( not IsBound( list[ pos ] ) ) or list[ pos ] <> obj then
pos:= fail; fi;
return pos; end );
############################################################################# ## #M PositionProperty(<list>,<func>) . position of an element with a property #M PositionProperty( <list>, <func>, <from> ) ##
InstallMethod( PositionProperty, "for list and function",
[ IsList, IsFunction ], function ( list, func )
local i; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then if func( list[ i ] ) then
return i; fi; fi;
od;
return fail; end );
InstallMethod( PositionProperty, "for list, function, and integer",
[ IsList, IsFunction, IsInt ], function( list, func, from )
local i;
if from < 0then
from:= 0; fi; for i in [ from+1 .. Length( list ) ] do if IsBound( list[i] ) then if func( list[i] ) then
return i; fi; fi;
od;
return fail; end );
InstallMethod( PositionProperty, "for dense list and function",
[ IsDenseList, IsFunction ], function ( list, func )
local i; for i in [ 1 .. Length( list ) ] do if func( list[ i ] ) then
return i; fi;
od;
return fail; end );
InstallMethod( PositionProperty, "for dense list, function, and integer",
[ IsDenseList, IsFunction, IsInt ], function( list, func, from )
local i;
if from < 0then
from:= 0; fi; for i in [ from+1 .. Length( list ) ] do
if func( list[i] ) then
return i; fi;
od;
return fail; end );
############################################################################# ## #M PositionMaximum(<list>[, <func>]) . position of the largest element #M PositionMinimum(<list>[, <func>]) . position of the smallest element ##
InstallGlobalFunction( PositionMaximum, function ( args... )
local list, func, i, bestval, bestindex, ival;
if Length(args) < 1 or Length(args) > 2
or not(IsList(args[1]))
or (Length(args) = 2 and not(IsFunction(args[2]))) then
ErrorNoReturn("Usage: PositionMaximum(<list>, [<func>])"); fi;
list := args[1]; if Length(args) = 2then
func := args[2]; else
func := IdFunc; fi;
bestindex := fail; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
ival := func ( list[ i ] );
if not( IsBound(bestval) ) or ival > bestval then
bestval := ival;
bestindex := i; fi; fi;
od;
return bestindex; end );
InstallGlobalFunction( PositionMinimum, function ( args... )
local list, func, i, bestval, bestindex, ival;
if Length(args) < 1 or Length(args) > 2
or not(IsList(args[1]))
or (Length(args) = 2 and not(IsFunction(args[2]))) then
ErrorNoReturn("Usage: PositionMinimum(<list>, [<func>])"); fi;
list := args[1]; if Length(args) = 2then
func := args[2]; else
func := IdFunc; fi;
bestindex := fail; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
ival := func ( list[ i ] );
if not( IsBound(bestval) ) or ival < bestval then
bestval := ival;
bestindex := i; fi; fi;
od;
return bestindex; end );
############################################################################# ## #M PositionsProperty(<list>,<func>) . positions of elements with a property ##
InstallMethod( PositionsProperty, "for list and function",
[ IsList, IsFunction ], function( list, func )
local result, i;
result:= []; for i in [ 1 .. Length( list ) ] do if IsBound( list[ i ] ) and func( list[i] ) then
Add( result, i ); fi;
od;
SetIsSSortedList( result, true );
return result; end );
InstallMethod( PositionsProperty, "for dense list and function",
[ IsDenseList, IsFunction ], function( list, func )
local result, i;
result:= []; for i in [ 1 .. Length( list ) ] do if func( list[i] ) then
Add( result, i ); fi;
od;
SetIsSSortedList( result, true );
return result; end );
############################################################################# ## #M PositionBound( <list> ) . . . . . . . . . . position of first bound entry ##
InstallMethod( PositionBound, "for a list",
[ IsList ], function( list )
local i; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
return i; fi;
od;
return fail; end );
############################################################################# ## #M PositionsBound( <list> ) . . . . . . . . . positions of all bound entries ##
InstallGlobalFunction( PositionsBound, function( list )
local i, bound;
if IsDenseList( list ) then
return [ 1 .. Length( list ) ]; fi;
bound := []; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
Add( bound, i ); fi;
od;
SetIsSSortedList( bound, true );
return bound; end );
############################################################################# ## #M PositionSublist( <list>,<sub>[,<ind>] ) ##
InstallMethod( PositionSublist, "list,sub,pos",
[IsList,IsList,IS_INT], function( list,sub,start )
local n, m, next, j, max, i;
# trivial case if m = 1 or start = fail then
return start; fi;
# string-match algorithm, cf. Manber, section 6.7
# compute the next entries
next:=[-1,0]; for i in [3..m] do
j:=next[i-1]+1; while j>0 and sub[i-1]<>sub[j] do
j:=next[j]+1;
od;
next[i]:=j;
od;
if Maximum(next) * 3 < m then # in this case reduce overhead and use naive loop
i := start;
max := n - m + 1; while i<>fail and i <= max do for j in [2..m] do if list[i+j-1] <> sub[j] then
j := 0;
break; fi;
od; if j <> 0then
return i; fi;
i:=Position(list, sub[1], i);
od;
return fail;
fi;
# otherwise repeat with Manber
i:=start;
j:=1; while i<=n do if sub[j]=list[i] then
i:=i+1;
j:=j+1; else
j:=next[j]+1; if j=0then
j:=1;
i:=i+1; fi; fi; if j=m+1then
return i-m; fi;
od;
return fail; end);
# no installation restrictions to avoid extra installations for empty list #T but the first two arguments should be in `IsList', shouldn't they?
InstallOtherMethod( PositionSublist, "list, sub",
[IsObject,IsObject], function( list,sub )
return PositionSublist(list,sub,0); end);
last:=first+Length(sub)-1;
return Length(list) >= last and list{[first..last]} = sub; end);
# no installation restrictions to avoid extra installations for empty list
InstallOtherMethod( IsMatchingSublist, "list, sub",
[IsObject,IsObject], function( list,sub )
return IsMatchingSublist(list,sub,1); end);
############################################################################# ## #M Add( <list>, <obj> ) ##
InstallMethod( Add, "for mutable list and list",
[ IsList and IsMutable, IsObject ],
ADD_LIST_DEFAULT );
InstallMethod( Add, "three arguments fast version",
[ IsPlistRep and IsList and IsMutable, IsObject, IsPosInt], function(l, o, p)
local len;
len := Length(l); if p <= len then
CopyListEntries(l,p,1,l,p+1,1,len-p+1); fi;
l[p] := o;
return; end);
InstallMethod( Add, "three arguments fast version sorted",
[ IsPlistRep and IsSSortedList and IsMutable, IsObject, IsPosInt], function(l, o, p)
local len;
len := Length(l); if p <= len then
CopyListEntries(l,p,1,l,p+1,1,len-p+1); fi;
l[p] := o; if IS_DENSE_LIST(l) and (p = 1 or l[p-1] < o) and (p = len+1 or o < l[p+1]) then
SET_IS_SSORTED_PLIST(l); fi;
return; end);
InstallMethod( Add, "three arguments general version",
[IsList and IsMutable, IsObject, IsPosInt], function(l, o, p)
local len;
len := Length(l); if p <= len then
l{[len+1,len..p+1]} := l{[len,len-1..p]}; fi;
l[p] := o;
return; end);
InstallMethod(Remove, "one argument", [IsList and IsMutable], function(l)
local x,len;
len := Length(l); if len = 0then
Error("Remove: list <l> must not be empty.\n"); fi;
x := l[len];
Unbind(l[len]);
return x; end);
InstallEarlyMethod(Remove, function(l,p)
local ret,x,len; if not (IsPlistRep(l) and IsMutable(l) and IsPosInt(p)) then
TryNextMethod(); fi;
len := Length(l);
ret := IsBound(l[p]); if ret then
x := l[p]; fi; if p <= len then
CopyListEntries(l,p+1,1,l,p,1,len-p);
Unbind(l[len]); fi; if ret then
return x; fi; end);
InstallMethod(Remove, "two arguments, general", [IsList and IsMutable, IsPosInt], function(l,p)
local ret,x,len;
len := Length(l);
ret := IsBound(l[p]); if ret then
x := l[p]; fi; if p <= len then
l{[p..len-1]} := l{[p+1..len]};
Unbind(l[len]); fi; if ret then
return x; fi; end);
############################################################################# ## #M Append(<list1>,<list2>) ##
BindGlobal( "APPEND_LIST_DEFAULT", function ( list1, list2 )
local len1, len2, i;
len1 := Length(list1);
len2 := Length(list2); if len1 = infinity then
Error("Append: can't append to an infinite list"); fi; if len2 = infinity then
Error("Append: Default method can't append an infinite list"); fi; for i in [1..len2] do if IsBound(list2[i]) then
list1[len1+i] := list2[i]; fi;
od; end );
InstallMethod( Append, "for mutable list and list",
[ IsList and IsMutable , IsList ],
APPEND_LIST_DEFAULT );
InstallMethod( Append, "for mutable list in plist representation, and small list",
[ IsList and IsPlistRep and IsMutable, IsList and IsSmallList ],
APPEND_LIST_INTR );
############################################################################# ## #F Apply( <list>, <func> ) . . . . . . . . apply a function to list entries ##
InstallGlobalFunction( Apply, function( list, func )
local i; for i in [1..Length( list )] do if IsBound(list[i]) then
list[i] := func( list[i] ); fi;
od; end );
############################################################################# ## #F Concatenation( <list1>, <list2>, ... ) #F Concatenation( <list> ) ##
InstallGlobalFunction( Concatenation, function ( arg )
local res, i; if Length( arg ) = 1 and IsList( arg[1] ) then
arg := arg[1]; fi; if Length( arg ) = 0then
return [ ]; fi; if not IsList( arg[1] ) then
Error( "Concatenation: arguments must be lists" ); fi;
res := ShallowCopy( arg[1] ); for i in [ 2 .. Length( arg ) ] do if not IsList( arg[i] ) then
Error( "Concatenation: arguments must be lists" ); fi;
Append( res, arg[i] );
od;
return res; end );
############################################################################# ## #M Compacted( <list> ) . . . . . . . . . . . . . . remove holes from a list ##
InstallMethod( Compacted, "for a list",
[ IsList ], function ( list )
local res, # compacted of <list>, result
elm; # element of <list> if IsDenseList(list) then
return ShallowCopy(list); fi;
res := []; for elm in list do
Add( res, elm );
od;
return res; end );
############################################################################# ## #M Collected( <list> ) . . . . . ##
InstallMethod( Collected, "for a list",
[ IsList ], function ( list )
local res, # collected, result
col, # one element of collected list
sorted, # list in sorted order
elm; # one element of list
# special case for empty list if IsEmpty( list ) then
return []; fi;
# sort a shallow copy of the list
sorted := ShallowCopy( list );
Sort( sorted );
# now collect
res := [];
col := [ sorted[1], 0 ]; for elm in sorted do if elm <> col[1] then
Add( res, col );
col := [ elm, 0 ]; fi;
col[2] := col[2] + 1;
od;
Add( res, col );
# return the collected list
return res; end );
############################################################################# ## #M DuplicateFreeList( <list> ) . . . . duplicate free list of list elements ##
InstallMethod( DuplicateFreeList, "for a list",
[ IsList ], function ( list )
local l,i;
l:= []; for i in list do if not i in l then
Add(l,i); fi;
od;
return l; end );
############################################################################# ## #M AsDuplicateFreeList( <list> ) . . . duplicate free list of list elements ##
InstallMethod( AsDuplicateFreeList, "for a list",
[ IsList ],
DuplicateFreeList );
############################################################################# ## #M Flat( <list> ) . . . . . . . list of elements of a nested list structure ##
InstallMethod( Flat, "for a list",
[ IsList ], function ( list )
local res, # list <list> flattened, result
elm; # one element of <list>
res := []; for elm in list do if not IsList(elm) then
Add( res, elm ); else
Append( res, Flat(elm) ); fi;
od;
return res; end );
############################################################################# ## #F Reversed( <list> ) . . . . . . . . . . . reverse the elements in a list ## ## Note that the special case that <list> is a range is dealt with by the ## `{}' implementation, we need not introduce a special treatment for this. ##
InstallGlobalFunction( Reversed, function( list )
local tnum, len;
tnum:= TNUM_OBJ( list ); if FIRST_LIST_TNUM <= tnum and tnum <= LAST_LIST_TNUM then
len:= Length( list );
return list{ [ len, len-1 .. 1 ] }; else
return ReversedOp( list ); fi; end );
############################################################################# ## #M ReversedOp( <list> ) . . . . . . . . . . reverse the elements in a list ## ## We install just two generic methods; ## they deal with (non-internal) finite lists only. ##
InstallMethod( ReversedOp, "for a dense list",
[ IsDenseList ], function( list )
local len; if not IsFinite( list ) then
TryNextMethod(); fi;
len:= Length( list );
return list{ [ len, len-1 .. 1 ] }; end );
InstallMethod( ReversedOp, "for a range",
[ IsRange ], function ( list )
local len;
len := Length( list ); if len = 0then
return []; elif len = 1then
return [ list[1] ]; else
return [ list[len], list[len-1] .. list[1] ]; fi; end );
############################################################################# ## #M Shuffle( <list> ) . . . . . . . . . . . . . . . . permute entries randomly
InstallMethod(Shuffle, [IsDenseList and IsMutable], function(l)
local len, j, tmp, i;
len := Length(l); for i in [1..len-1] do
j := Random(i, len); if i <> j then
tmp := l[i];
l[i] := l[j];
l[j] := tmp; fi;
od;
return l; end);
############################################################################# ## #M Sort( <list>[, <func>] ) ##
InstallMethod( Sort, "for a mutable small list",
[ IsList and IsMutable and IsSmallList ],
SORT_LIST );
InstallMethod( StableSort, "for a mutable small list",
[ IsList and IsMutable and IsSmallList ],
STABLE_SORT_LIST );
InstallMethod( Sort, "for a mutable list",
[ IsList and IsMutable ], function( list ) if IsSmallList( list ) then
SORT_LIST( list ); else
TryNextMethod(); fi; end );
InstallMethod( StableSort, "for a mutable list",
[ IsList and IsMutable ], function( list ) if IsSmallList( list ) then
STABLE_SORT_LIST( list ); else
TryNextMethod(); fi; end );
InstallMethod( Sort, "for a mutable set",
[ IsList and IsMutable and IsSortedList ], SUM_FLAGS,
Ignore );
InstallMethod( StableSort, "for a mutable set",
[ IsList and IsMutable and IsSortedList ], SUM_FLAGS,
Ignore );
InstallMethod( Sort, "for a mutable small list and a function",
[ IsList and IsMutable and IsSmallList, IsFunction ],
SORT_LIST_COMP );
InstallMethod( StableSort, "for a mutable small list and a function",
[ IsList and IsMutable and IsSmallList, IsFunction ],
STABLE_SORT_LIST_COMP );
InstallMethod( Sort, "for a mutable list and a function",
[ IsList and IsMutable, IsFunction ], function( list, func ) if IsSmallList( list ) then
SORT_LIST_COMP( list, func ); else
TryNextMethod(); fi; end );
InstallMethod( StableSort, "for a mutable list and a function",
[ IsList and IsMutable, IsFunction ], function( list, func ) if IsSmallList( list ) then
STABLE_SORT_LIST_COMP( list, func ); else
TryNextMethod(); fi; end );
InstallMethod( SortBy, "for a mutable list and a function",
[IsList and IsMutable, IsFunction ], function(list, func)
local images;
images := List(list, func);
SortParallel(images, list);
return; end);
InstallMethod( StableSortBy, "for a mutable list and a function",
[IsList and IsMutable, IsFunction ], function(list, func)
local images;
images := List(list, func);
StableSortParallel(images, list);
return; end);
############################################################################# ## #F SORT_MUTABILITY_ERROR_HANDLER( <list> ) #F SORT_MUTABILITY_ERROR_HANDLER( <list>, <func> ) #F SORT_MUTABILITY_ERROR_HANDLER( <list1>, <list2> ) #F SORT_MUTABILITY_ERROR_HANDLER( <list1>, <list2>, <func> ) ## ## This function will be installed as method for `Sort', `Sortex' and ## `SortParallel', for the sake of a more gentle error message. ##
BindGlobal( "SORT_MUTABILITY_ERROR_HANDLER", function( arg ) if ( Length( arg ) = 1 and IsMutable( arg[1] ) )
or ( Length( arg ) = 2 and IsMutable( arg[1] )
and ( IsFunction( arg[2] ) or IsMutable( arg[2] ) ) )
or ( Length( arg ) = 3 and IsMutable( arg[1] )
and IsMutable( arg[2] ) ) then
TryNextMethod(); fi;
Error( "immutable lists cannot be sorted" ); end );
InstallOtherMethod( Sort, "for an immutable list and a function",
[ IsList, IsFunction ],
SORT_MUTABILITY_ERROR_HANDLER );
InstallOtherMethod( StableSort, "for an immutable list and a function",
[ IsList, IsFunction ],
SORT_MUTABILITY_ERROR_HANDLER );
############################################################################# ## #M Sortex( <list> ) . . sort a list (stable), return the applied permutation ##
InstallMethod( Sortex, "for a mutable list",
[ IsList and IsMutable ], function ( list )
local n, index;
# {\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;
n := Length(list);
index := [1..n];
StableSortParallel(list, index);
return PermList(index)^-1;
end );
InstallMethod( Sortex, "for a mutable list and a function",
[ IsList and IsMutable, IsFunction ], function ( list, comp )
local n, index;
# {\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;
n := Length(list);
index := [1..n];
StableSortParallel(list, index, comp);
return PermList(index)^-1;
end );
InstallMethod( Sortex, "for a mutable sorted list",
[ IsDenseList and IsSortedList and IsMutable ], SUM_FLAGS,
list -> () );
############################################################################# ## #F PermListList( <list1>, <list2> ) what permutation of <list1> is <list2> ##
InstallGlobalFunction( PermListList, function( list1, list2 )
local perm;
# to not destroy list1 and list2
list1:= ShallowCopy(list1);
list2:= ShallowCopy(list2);
perm:= Sortex( list2 ) / Sortex( list1 ); if list1 <> list2 then
return fail; else
return perm; fi; end );
############################################################################# ## #M SortingPerm( <list> ) ##
InstallMethod( SortingPerm,
[ IsDenseList ], function( list )
local copy;
copy := ShallowCopy(list);
return Sortex(copy); end );
InstallMethod( SortingPerm, "for a dense and sorted list",
[ IsDenseList and IsSortedList ], SUM_FLAGS,
list -> () );
############################################################################# ## #M SortParallel( <list>, <list2> ) . . . . . . . sort two lists in parallel ##
InstallMethod( SortParallel, "for two mutable lists",
[ IsList and IsMutable,
IsList and IsMutable ],
SORT_PARA_LIST );
InstallMethod( StableSortParallel, "for two mutable lists",
[ IsList and IsMutable,
IsList and IsMutable ],
STABLE_SORT_PARA_LIST );
############################################################################# ## #M SortParallel( <sorted>, <list> ) ##
InstallMethod( SortParallel, "for a mutable set and a dense mutable list",
[ IsDenseList and IsSortedList and IsMutable,
IsDenseList and IsMutable ],
SUM_FLAGS,
Ignore );
InstallMethod( StableSortParallel, "for a mutable set and a dense mutable list",
[ IsDenseList and IsSortedList and IsMutable,
IsDenseList and IsMutable ],
SUM_FLAGS,
Ignore );
############################################################################# ## #M SortParallel( <list>, <list2>, <func> ) ##
InstallMethod( SortParallel, "for mutable lists, and function",
[ IsList and IsMutable,
IsList and IsMutable,
IsFunction ],
SORT_PARA_LIST_COMP );
InstallMethod( StableSortParallel, "for two mutable lists, and function",
[ IsList and IsMutable,
IsList and IsMutable,
IsFunction ],
STABLE_SORT_PARA_LIST_COMP );
InstallOtherMethod( SortParallel, "for two immutable lists",
[IsList,IsList],
SORT_MUTABILITY_ERROR_HANDLER);
InstallOtherMethod( StableSortParallel, "for two immutable lists",
[IsList,IsList],
SORT_MUTABILITY_ERROR_HANDLER);
InstallOtherMethod( SortParallel, "for two immutable lists and function",
[IsList,IsList,IsFunction],
SORT_MUTABILITY_ERROR_HANDLER);
InstallOtherMethod( StableSortParallel, "for two immutable lists and function",
[IsList,IsList,IsFunction],
SORT_MUTABILITY_ERROR_HANDLER);
############################################################################# ## #M MaximumList( <list> ) ##
InstallMethod( MaximumList, "for a list",
[ IsList ], function ( list )
local max, elm; if Length( list ) = 0then
Error( "MaximumList: <list> must contain at least one element" ); fi;
max := Last(list); for elm in list do if max < elm then
max := elm; fi;
od;
return max; end );
InstallMethod( MaximumList, "for a list and a seed",
[ IsList, IsObject ], function ( list, max )
local elm; for elm in list do if max < elm then
max := elm; fi;
od;
return max; end );
InstallMethod( MaximumList, "for a range",
[ IsRange ], function ( range )
local max; if Length( range ) = 0then
Error( "MaximumList: <range> must contain at least one element" ); fi;
max := Last(range); if max < range[1] then
return range[1]; fi;
return max; end );
InstallMethod( MaximumList, "for a range and a seed",
[ IsRange, IsObject ], function ( range, max )
local len;
len := Length(range); if max < range[1] then
max := range[1]; fi; if len > 0 and max < range[len] then
max := range[len]; fi;
return max; end );
InstallMethod( MaximumList, "for a sorted list",
[ IsSSortedList ], function ( list )
local len;
len := Length(list); if len = 0then
Error( "MaximumList: <list> must contain at least one element" ); fi;
return list[len]; end );
InstallMethod( MaximumList, "for a sorted list and a seed",
[ IsSSortedList, IsObject ], function ( list, max )
local len;
len := Length(list); if len > 0 and list[len] > max then
return list[len]; fi;
return max; end );
############################################################################# ## #M MinimumList( <list> ) ##
InstallMethod( MinimumList, "for a list",
[ IsList ], function ( list )
local min, elm; if Length( list ) = 0then
Error( "MinimumList: <list> must contain at least one element" ); fi;
min := Last(list); for elm in list do if elm < min then
min := elm; fi;
od;
return min; end );
InstallMethod( MinimumList, "for a list",
[ IsList, IsObject ], function ( list, min )
local elm; for elm in list do if elm < min then
min := elm; fi;
od;
return min; end );
InstallMethod( MinimumList, "for a range",
[ IsRange ], function ( range )
local min, len;
len := Length(range); if len = 0then
Error( "MinimumList: <range> must contain at least one element" ); fi;
min := range[ len ]; if range[1] < min then
return range[1]; fi;
return min; end );
InstallMethod( MinimumList, "for a range and a seed",
[ IsRange, IsObject ], function ( range, min )
local len;
len := Length(range); if min > range[1] then
min := range[1]; fi; if len > 0 and min > range[len] then
min := range[len]; fi;
return min; end );
InstallMethod( MinimumList, "for a sorted list",
[ IsSSortedList ], function ( list ) if Length(list) = 0then
Error( "MinimumList: <list> must contain at least one element" ); fi;
return list[1]; end );
InstallMethod( MinimumList, "for a sorted list and a seed",
[ IsSSortedList, IsObject ], function ( list, min ) if Length(list) > 0 and list[1] < min then
return list[1]; fi;
return min; end );
############################################################################# ## #F Cartesian( <list1>, <list2>, ... ) #F Cartesian( <list> ) ##
DeclareGlobalName( "Cartesian2" );
BindGlobal( "Cartesian2", function ( list, n, tup, i )
local tups, l; if i = n+1then
tup := ShallowCopy(tup);
tups := [ tup ]; else
tups := []; for l in list[i] do
tup[i] := l;
Append( tups, Cartesian2( list, n, tup, i+1 ) );
od; fi;
return tups; end );
InstallGlobalFunction( Cartesian, function ( arg ) if Length(arg) = 1then
return Cartesian2( arg[1], Length(arg[1]), [], 1 ); else
return Cartesian2( arg, Length(arg), [], 1 ); fi; end );
############################################################################# ## #M Permuted( <list>, <perm> ) . . . apply permutation <perm> to list <list> ##
InstallMethod( Permuted, "for a dense list and a permutation",
[ IsDenseList, IS_PERM ], function( list, perm ) # this was proposed by Jean Michel
return list{ OnTuples( [ 1 .. Length( list ) ], perm^-1 ) }; end );
InstallMethod( Permuted, "for a (non-dense) list and a permutation",
[ IsList, IS_PERM ], function( list, perm )
local result, i;
result := []; for i in [1 .. Length(list)] do if IsBound(list[i]) then
result[i ^ perm] := list[i]; fi;
od;
return result; end );
############################################################################# ## #F First( <C>, <func> ) . . . find first element in a list with a property ##
InstallEarlyMethod( First, function ( C )
local tnum, elm;
tnum:= TNUM_OBJ( C ); if FIRST_LIST_TNUM <= tnum and tnum <= LAST_LIST_TNUM then for elm in C do
return elm;
od;
return fail; fi;
TryNextMethod(); end );
InstallEarlyMethod( First, function ( C, func )
local tnum, elm;
tnum:= TNUM_OBJ( C ); if FIRST_LIST_TNUM <= tnum and tnum <= LAST_LIST_TNUM then for elm in C do if func( elm ) then
return elm; fi;
od;
return fail; fi;
TryNextMethod(); end );
############################################################################# ## #M First( <C>, <func> ) . . . . find first element in a list with a property ##
InstallMethod( First, "for a list or collection and a function",
[ IsListOrCollection, IsFunction ], function ( C, func )
local elm; for elm in C do if func( elm ) then
return elm; fi;
od;
return fail; end );
InstallMethod( First, "for a list or collection",
[ IsListOrCollection ], function ( C )
local elm; for elm in C do
return elm;
od;
return fail; end );
############################################################################# ## #F Last( <C>, <func> ) . . . . find last element in a list with a property ##
InstallGlobalFunction( Last, function ( C, func... )
local tnum, i; if Length( func ) > 1then
Error( "too many arguments" ); fi;
tnum:= TNUM_OBJ( C ); if FIRST_LIST_TNUM <= tnum and tnum <= LAST_LIST_TNUM then if Length( func ) = 0then
func := ReturnTrue; else
func := func[1]; fi; for i in [Length(C),Length(C)-1..1] do if IsBound(C[i]) and func(C[i]) then
return C[i]; fi;
od;
return fail; elif Length( func ) = 0then
return LastOp( C ); else
return LastOp( C, func[1] ); fi; end );
############################################################################# ## #M LastOp( <C>, <func> ) . . . find last element in a list with a property ##
InstallMethod( LastOp, "for a list and a function",
[ IsList and IsFinite, IsFunction ], function ( list, func )
local i; for i in [Length(list),Length(list)-1..1] do if IsBound(list[i]) and func(list[i]) then
return list[i]; fi;
od;
return fail; end );
InstallMethod( LastOp, "for a list",
[ IsList and IsFinite ], function ( list )
return LastOp(list, ReturnTrue); end );
############################################################################# ## #M Iterated( <list>, <func> ) . . . . . . . iterate a function over a list ##
InstallMethod( Iterated, "for a list and a function",
[ IsList, IsFunction ], function ( list, func )
local res, i; if IsEmpty( list ) then
Error( "Iterated: <list> must contain at least one element" ); fi;
res:= list[1]; for i in [ 2 .. Length( list ) ] do
res:= func( res, list[i] );
od;
return res; end );
num := Length(arg) -1;
func := arg[num+1];
Unbind( arg[num+1] );
len := Length(arg[1]);
if not IsFunction(func) then
Error("Last argument must be a function"); elif ForAny( arg, a -> not IsList(a) or Length(a) <> len ) then
Error("<arg1>, ..., <argn> must be lists of the same length"); fi;
return List( [1..len],
i -> CallFuncList( func, List( [1..num],
j -> arg[j][i] ) ) ); end );
############################################################################# ## #M IsBound( list[i] ) . . . . . . . . . . . . . . . IsBound for dense lists ##
InstallMethod( IsBound\[\], "for a dense list and positive integer",
[ IsDenseList, IsPosInt ], function( list, index )
return index <= Length( list ); end );
############################################################################# ## #M IsBound( list[i] ) . . . . . IsBound for small lists with large arguments ##
InstallMethod( IsBound\[\], "for a small list and large positive integer",
[ IsSmallList, IsPosInt ], function( list, index ) if IsSmallIntRep(index) then
TryNextMethod(); else
return false; fi; end );
############################################################################# ## ## Arithmetic behaviour of lists ##
############################################################################# ## #M ZeroOp( <list> ) . . . . . . . . . . . for small list in `IsListDefault' #M ZeroSameMutability( <list> ) . . . . . for small list in `IsListDefault' ## ## Default methods are installed only for small lists in `IsListDefault'. ## For those lists, `Zero' is defined pointwise. ## (If the lists are inhomogeneous then strange things may happen, ## for example `Zero( <l1> + <l2> )' is in general different from ## `Zero( <l1> ) + Zero( <l2> )'.) ##
InstallOtherMethod( ZeroMutable,
[ IsListDefault and IsSmallList ],
ZERO_MUT_LIST_DEFAULT );
InstallOtherMethod( ZeroSameMutability,
[ IsListDefault and IsSmallList ],
ZERO_LIST_DEFAULT );
############################################################################# ## #M AdditiveInverseOp( <list> ) . . . . . for small list in `IsListDefault' #M AdditiveInverseSameMutability( <list> ) for small list in `IsListDefault' ## ## Default methods are installed only for small lists in `IsListDefault'. ## For those lists, `AdditiveInverse' is defined pointwise. ##
InstallOtherMethod( AdditiveInverseMutable,
[ IsListDefault and IsSmallList ],
AINV_MUT_LIST_DEFAULT );
InstallOtherMethod( AdditiveInverseSameMutability,
[ IsListDefault and IsSmallList ],
AINV_LIST_DEFAULT );
############################################################################# ## #M <grv> + <nonlist> . . . . . . . . . . for small list in `IsListDefault' #M <nonlist> + <grv> . . . . . . . . . . for small list in `IsListDefault' ## ## Default methods are installed only for small lists in `IsListDefault'. ## For those lists, the sum with an object that is neither a list nor a ## domain is defined pointwise. ##
InstallOtherMethod( \+,
[ IsListDefault and IsSmallList, IsObject ], function( list, nonlist ) if IsList( nonlist ) or IsDomain( nonlist ) then
TryNextMethod(); else
return SUM_LIST_SCL_DEFAULT( list, nonlist ); fi; end );
InstallOtherMethod( \+,
[ IsObject, IsListDefault and IsSmallList ], function( nonlist, list ) if IsList( nonlist ) or IsDomain( nonlist ) then
TryNextMethod(); else
return SUM_SCL_LIST_DEFAULT( nonlist, list ); fi; end );
InstallGlobalFunction( LIST_WITH_HOMOGENEOUS_MUTABILITY_LEVEL, function( list, level )
local i;
if not IsCopyable( list ) then
return list; elif level <= 0then
return Immutable( list ); fi;
list:= ShallowCopy( list ); for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
list[i]:= LIST_WITH_HOMOGENEOUS_MUTABILITY_LEVEL( list[i], level - 1 ); fi;
od;
return list; end );
InstallGlobalFunction( IMMUTABILITY_LEVEL2, function( list ) if not IsGeneralizedRowVector( list ) or IsEmpty( list ) then
return 0; elif IsMutable( list ) then
return IMMUTABILITY_LEVEL2( list[ PositionBound( list ) ] ); else
return 1 + IMMUTABILITY_LEVEL2( list[ PositionBound( list ) ] ); fi; end );
BindGlobal( "IMMUTABILITY_LEVEL", function( list ) if IsMutable( list ) then
return IMMUTABILITY_LEVEL2( list ); else
return infinity; fi; end );
############################################################################# ## #F SUM_LISTS_SPECIAL( <left>, <right>, <depthleft>, <depthright> ) ## ## This is a generic addition function for two small lists <left>, <right> ## in `IsListDefault' which have additive nesting depths <depthleft> and ## <depthright>, respectively. ## ## If at least one of <left>, <right> is non-dense or has additive nesting ## depth at least $3$, `SUM_LISTS_SPECIAL' is called by the generic `\+' ## method for two small lists in `IsListDefault'. ##
BindGlobal( "SUM_LISTS_SPECIAL", function( left, right, depthleft, depthright )
local result, len1, len2, i, depth, depth2;
result:= [];
len1:= Length( left );
len2:= Length( right );
# Compute the sum. if depthleft = depthright then if len1 < len2 then
len1:= len2; fi; for i in [ 1 .. len1 ] do if IsBound( left[i] ) then if IsBound( right[i] ) then
result[i]:= left[i] + right[i]; else
result[i]:= ShallowCopy( left[i]); fi; elif IsBound( right[i] ) then
result[i]:= ShallowCopy(right[i]); fi;
od; elif depthleft < depthright then for i in [ 1 .. len2 ] do if IsBound( right[i] ) then
result[i]:= left + right[i]; fi;
od; else for i in [ 1 .. len1 ] do if IsBound( left[i] ) then
result[i]:= left[i] + right; fi;
od; fi;
# Adjust the mutability status.
depth:= IMMUTABILITY_LEVEL( left );
depth2:= IMMUTABILITY_LEVEL( right ); if depth2 < depth then
depth:= depth2; fi; if depth = infinity then
result:= Immutable( result ); else
result:= LIST_WITH_HOMOGENEOUS_MUTABILITY_LEVEL( result,
NestingDepthA( result ) - depth ); fi;
# Return the result.
return result; end );
############################################################################# ## #M <list1> + <list2> . . . . . . . . for two small lists in `IsListDefault' ## ## A default method is installed only for two small lists in ## `IsListDefault'. ## For those lists, the sum is computed depending on the additive nesting ## depth. ##
InstallOtherMethod( \+,
[ IsListDefault and IsSmallList, IsListDefault and IsSmallList ], function( left, right )
local depth1, depth2;
depth1:= NestingDepthA( left );
depth2:= NestingDepthA( right ); if (2 < depth1 and not IsDenseList( left ))
or (2 < depth2 and not IsDenseList( right )) then
return SUM_LISTS_SPECIAL( left, right, depth1, depth2 ); elif depth1 = depth2 then
return SUM_LIST_LIST_DEFAULT( left, right ); elif depth1 < depth2 then
return SUM_SCL_LIST_DEFAULT( left, right ); else
return SUM_LIST_SCL_DEFAULT( left, right ); fi; end );
############################################################################# ## #M <obj1> - <obj2> ## ## For two {\GAP} objects $x$ and $y$ of which one is in ## `IsGeneralizedRowVector' and the other is either not a list or is ## also in `IsGeneralizedRowVector', ## $x - y$ is defined as $x + (-y)$. ## For this case, we install a default method that relies on `\+'. ## ## A (better?) default method is installed only for two small lists in ## `IsListDefault'. ##
InstallOtherMethod( \-,
[ IsGeneralizedRowVector, IsGeneralizedRowVector ], function( grv1, grv2 )
return grv1 + (-grv2); end );
InstallOtherMethod( \-,
[ IsGeneralizedRowVector, IsObject ], function( grv, nonlist ) if IsList( nonlist ) then
TryNextMethod(); fi;
return grv + (-nonlist); end );
InstallOtherMethod( \-,
[ IsObject, IsGeneralizedRowVector ], function( nonlist, grv ) if IsList( nonlist ) then
TryNextMethod(); fi;
return nonlist + (-grv); end );
InstallOtherMethod( \-,
[ IsListDefault and IsSmallList, IsListDefault and IsSmallList ], function( left, right )
local depth1, depth2;
depth1:= NestingDepthA( left );
depth2:= NestingDepthA( right ); if (2 < depth1 and not IsDenseList( left ))
or (2 < depth2 and not IsDenseList( right )) then
return SUM_LISTS_SPECIAL( left, - right, depth1, depth2 ); elif depth1 = depth2 then
return DIFF_LIST_LIST_DEFAULT( left, right ); elif depth1 < depth2 then
return DIFF_SCL_LIST_DEFAULT( left, right ); else
return DIFF_LIST_SCL_DEFAULT( left, right ); fi; end );
############################################################################# ## #M OneOp( <matrix> ) . . . . . . . . . . . . . for matrix in `IsListDefault' #M OneSameMutability( <matrix> ) . . . . . . . for matrix in `IsListDefault' ##
InstallOtherMethod( OneOp,
[ IsListDefault ], function( mat ) if IsSmallList( mat ) and NestingDepthM( mat ) mod 2 = 0then
return ONE_MATRIX_MUTABLE( mat ); else
TryNextMethod(); fi; end );
InstallOtherMethod( OneSameMutability,
[ IsListDefault ], function( mat ) if IsSmallList( mat ) and NestingDepthM( mat ) mod 2 = 0then
return ONE_MATRIX_SAME_MUTABILITY( mat ); else
TryNextMethod(); fi; end );
############################################################################# ## #M InverseOp( <matrix> ) . . . . . . . . . . . for matrix in `IsListDefault' #M InverseSameMutability( <matrix> ) . . . . . for matrix in `IsListDefault' ## ## The `INV_MAT_DEFAULT' methods are faster for lists of FFEs because they ## use `AddRowVector', etc. ##
InstallOtherMethod( InverseOp, "for default list whose rows are vectors of FFEs",
[ IsListDefault and IsRingElementTable and IsFFECollColl ], function( mat ) if NestingDepthM( mat ) mod 2 = 0 and IsSmallList( mat ) then if IsRectangularTable( mat ) then
return INV_MAT_DEFAULT_MUTABLE( mat ); else
return fail; fi; else
TryNextMethod(); fi; end );
InstallOtherMethod( InverseOp, "for default list over a ring without zero divisors",
[ IsListDefault and IsZDFRECollColl ], function( mat ) if NestingDepthM( mat ) mod 2 = 0 and IsSmallList( mat ) then if IsRectangularTable( mat ) then
return INV_MATRIX_MUTABLE( mat ); else
return fail; fi; else
TryNextMethod(); fi; end );
InstallOtherMethod( InverseSameMutability, "for default list whose rows are vectors of FFEs",
[ IsListDefault and IsRingElementTable and IsFFECollColl ], function( mat ) if NestingDepthM( mat ) mod 2 = 0 and IsSmallList( mat ) then if IsRectangularTable( mat ) then
return INV_MAT_DEFAULT_SAME_MUTABILITY( mat ); else
return fail; fi; else
TryNextMethod(); fi; end );
InstallOtherMethod( InverseSameMutability, "for default list over a ring without zero divisors",
[ IsListDefault and IsZDFRECollColl ], function( mat ) if NestingDepthM( mat ) mod 2 = 0 and IsSmallList( mat ) then if IsRectangularTable( mat ) then
return INV_MATRIX_SAME_MUTABILITY( mat ); else
return fail; fi; else
TryNextMethod(); fi; end );
############################################################################# ## #M <vector> ^ <matrix> ##
InstallOtherMethod( \^, "using `PROD' for ring element list and ring element table",
IsElmsColls,
[ IsRingElementList, IsRingElementTable ],
PROD );
############################################################################# ## #M <mgrv> * <nonlist> . . . . . . . . . . for small list in `IsListDefault' #M <nonlist> * <mgrv> . . . . . . . . . . for small list in `IsListDefault' ## ## Default methods are installed only for small lists in `IsListDefault'. ## For those lists, the product with an object that is neither a list nor a ## domain is defined pointwise. ##
InstallOtherMethod( \*,
[ IsListDefault and IsSmallList, IsObject ], function( list, nonlist ) if IsList( nonlist ) or IsDomain( nonlist ) then
TryNextMethod(); else
return PROD_LIST_SCL_DEFAULT( list, nonlist ); fi; end );
InstallOtherMethod( \*,
[ IsObject, IsListDefault and IsSmallList ], function( nonlist, list ) if IsList( nonlist ) or IsDomain( nonlist ) then
TryNextMethod(); else
return PROD_SCL_LIST_DEFAULT( nonlist, list ); fi; end );
result:= []; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
result[i]:= func( list[i] ); fi;
od;
return result; end ); #T Note that the two-argument version of `List' is defined only for dense #T lists -- I think this restriction could be removed now!
############################################################################# ## #F PROD_LISTS_SPECIAL( <left>, <right>, <depthleft>, <depthright> ) ## ## This is a generic multiplication function for two small lists <left>, ## <right> in `IsListDefault' which have multiplicative nesting depths ## <depthleft> and <depthright>, respectively. ## ## If at least one of <left>, <right> is non-dense or has multiplicative ## nesting depth at least $3$, `PROD_LISTS_SPECIAL' is called by the generic ## `\*' method for two small lists in `IsListDefault'. ##
BindGlobal( "PROD_LISTS_SPECIAL", function( left, right, depthleft, depthright )
local len1, len2, prods, i, result, depth, depth2;
# Compute the product. if IsOddInt( depthleft ) then if IsOddInt( depthright ) or depthleft < depthright then # vector product
len1:= Length( left );
len2:= Length( right ); if len2 < len1 then
len1:= len2; fi;
prods:= []; for i in [ 1 .. len1 ] do if IsBound( left[i] ) and IsBound( right[i] ) then
Add( prods, left[i] * right[i] ); fi;
od; if IsEmpty( prods ) then
Error( "no summands to add up in mult. of <left> and <right>" ); fi;
result:= prods[1]; for i in [ 2 .. Length( prods ) ] do
result:= result + prods[i];
od; else # <vec> * <scl>
result:= LIST_WITH_HOLES( left, x -> x * right ); fi; elif IsOddInt( depthright ) then if depthleft < depthright then # <scl> * <vec>
result:= LIST_WITH_HOLES( right, x -> left * x ); else # <mat> * <vec>
result:= LIST_WITH_HOLES( left, x -> x * right ); fi; elif depthleft = depthright then # <mat> * <mat>
result:= LIST_WITH_HOLES( left, x -> x * right ); elif depthleft < depthright then # <scl> * <mat>
result:= LIST_WITH_HOLES( right, x -> left * x ); else # <mat> * <scl>
result:= LIST_WITH_HOLES( left, x -> x * right ); fi;
# Adjust the mutability status.
depth:= IMMUTABILITY_LEVEL( left );
depth2:= IMMUTABILITY_LEVEL( right ); if depth2 < depth then
depth:= depth2; fi; if depth = infinity then
result:= Immutable( result ); else
result:= LIST_WITH_HOMOGENEOUS_MUTABILITY_LEVEL( result,
NestingDepthA( result ) - depth ); fi;
# Return the result.
return result; end );
############################################################################# ## #M <list1> * <list2> . . . . . . . . for two small lists in `IsListDefault' ## ## A default method is installed only for two small lists in ## `IsListDefault'. ## For those lists, the product is defined depending on the multiplicative ## nesting depths of the arguments. ##
InstallOtherMethod( \*,
[ IsListDefault and IsSmallList, IsListDefault and IsSmallList ], function( left, right )
local depth1, depth2, depthDiff, prod;
depth1:= NestingDepthM( left );
depth2:= NestingDepthM( right ); if (2 < depth1 and not IsDenseList( left ))
or (2 < depth2 and not IsDenseList( right ))
or 3 < depth1 or 3 < depth2 then
return PROD_LISTS_SPECIAL( left, right, depth1, depth2 ); elif IsOddInt( depth1 ) then if IsOddInt( depth2 ) or depth1 < depth2 then # <vec> * <vec> or <vec> * <mat>
depthDiff := depth1 - depth2; if depthDiff < -1 or depthDiff > 1then
return PROD_LISTS_SPECIAL(left, right, depth1, depth2 ); else
return PROD_LIST_LIST_DEFAULT( left, right, depthDiff ); fi; else # <vec> * <scl>
return PROD_LIST_SCL_DEFAULT( left, right ); fi; elif depth1 < depth2 then # <scl> * <vec> or <scl> * <mat>
return PROD_SCL_LIST_DEFAULT( left, right ); elif IsEvenInt(depth1) and IsOddInt(depth2) and depth1 > depth2 then # <mat>*<vec> may need to adjust mutability
prod := PROD_LIST_SCL_DEFAULT( left, right ); if IsMutable(prod) and not IsMutable(right) and
not IsMutable(left[PositionBound(left)]) then
MakeImmutable(prod); fi;
return prod; else # <mat> * <scl> or <mat> * <mat>
return PROD_LIST_SCL_DEFAULT( left, right ); fi; end );
InstallMethod( \*, "More efficient non-recursive kernel method for vector*matrix of cyclotomics",
[ IsListDefault and IsSmallList and IsCyclotomicCollection and
IsPlistRep,
IsListDefault and IsSmallList and IsCyclotomicCollColl and
IsPlistRep and IsRectangularTable], function(v, mat)
local prod; if ForAny(mat, r-> not IsPlistRep(r)) then
TryNextMethod(); fi;
prod := PROD_VECTOR_MATRIX(v, mat); if not IsMutable(v) and not IsMutable(mat) then
MakeImmutable(prod); fi;
return prod; end);
InstallMethod( \*, "More efficient non-recursive method for matrix*matrix of cyclotomics",
[ IsListDefault and IsSmallList and IsCyclotomicCollColl,
IsListDefault and IsSmallList and IsCyclotomicCollColl and
IsPlistRep and IsRectangularTable], function(m1,m2)
local prod, row; if ForAny(m2, r-> not IsPlistRep(r)) or
ForAny(m1, r-> not IsPlistRep(r)) then
TryNextMethod(); fi;
prod := List(m1, row-> PROD_VECTOR_MATRIX(row, m2)); if not IsMutable(m1) and not IsMutable(m2) then
MakeImmutable(prod); fi;
return prod; end);
result:= []; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
result[i]:= list[i] mod scalar; fi;
od; if not IsMutable( list ) and not IsMutable( scalar ) then
result:= Immutable( result ); fi;
return result; end );
BindGlobal( "MOD_SCL_LIST_DEFAULT", function( scalar, list )
local result, i;
result:= []; for i in [ 1 .. Length( list ) ] do if IsBound( list[i] ) then
result[i]:= scalar mod list[i]; fi;
od; if not IsMutable( list ) and not IsMutable( scalar ) then
result:= Immutable( result ); fi;
return result; end );
BindGlobal( "MOD_LIST_LIST_DEFAULT", function( left, right )
local result, i;
result:= []; for i in [ 1 .. Maximum( Length( left ), Length( right ) ) ] do if IsBound( left[i] ) then if IsBound( right[i] ) then
result[i]:= left[i] mod right[i]; elif IsCopyable( left[i] ) then
result[i]:= ShallowCopy( left[i] ); else
result[i]:= left[i]; fi; elif IsBound( right[i] ) then if IsCopyable( right[i] ) then
result[i]:= ShallowCopy( right[i] ); else
result[i]:= right[i]; fi; fi;
od; if not IsMutable( left ) and not IsMutable( right ) then
result:= Immutable( result ); fi;
return result; end );
############################################################################# ## #M <grv> mod <nonlist> . . . . . . . . . for small list in `IsListDefault' #M <nonlist> mod <grv> . . . . . . . . . for small list in `IsListDefault' ## ## Default methods are installed only for small lists in `IsListDefault'. ## For those lists, ## the result of `mod' with a non-list is defined pointwise. ##
InstallOtherMethod( \mod,
[ IsListDefault and IsSmallList, IsObject ], function( list, nonlist ) if IsList( nonlist ) then
TryNextMethod(); else
return MOD_LIST_SCL_DEFAULT( list, nonlist ); fi; end );
InstallOtherMethod( \mod,
[ IsObject, IsListDefault and IsSmallList ], function( nonlist, list ) if IsList( nonlist ) then
TryNextMethod(); else
return MOD_SCL_LIST_DEFAULT( nonlist, list ); fi; end );
############################################################################# ## #M <list1> mod <list2> . . . . . . . for two small lists in `IsListDefault' ## ## A default method is installed only for two small lists in ## `IsListDefault'. ## For those lists, `mod' is defined depending on the multiplicative nesting ## depth. ##
InstallOtherMethod( \mod,
[ IsListDefault and IsSmallList, IsListDefault and IsSmallList ], function( left, right )
local depth1, depth2;
depth1:= NestingDepthM( left );
depth2:= NestingDepthM( right ); if depth1 = depth2 then
return MOD_LIST_LIST_DEFAULT( left, right ); elif depth1 < depth2 then
return MOD_SCL_LIST_DEFAULT( left, right ); else
return MOD_LIST_SCL_DEFAULT( left, right ); fi; end );
############################################################################# ## #M LeftQuotient( <obj1>, <obj2> ) ## ## For two {\GAP} objects $x$ and $y$ of which one is in ## `IsMultiplicativeGeneralizedRowVector' and the other is either not a list ## or is also in `IsMultiplicativeGeneralizedRowVector', ## $`LeftQuotient'( x, y )$ is defined as $x^{-1} y$. ## For this case, we install a default method that relies on `Inverse' and ## `\*'. ##
InstallOtherMethod( LeftQuotient,
[ IsMultiplicativeGeneralizedRowVector,
IsMultiplicativeGeneralizedRowVector ], function( grv1, grv2 )
return grv1^(-1) * grv2; end );
InstallOtherMethod( LeftQuotient,
[ IsMultiplicativeGeneralizedRowVector, IsObject ], function( grv, nonlist ) if IsList( nonlist ) then
TryNextMethod(); fi;
return grv^(-1) * nonlist; end );
InstallOtherMethod( LeftQuotient,
[ IsObject, IsMultiplicativeGeneralizedRowVector ], function( nonlist, grv ) if IsList( nonlist ) then
TryNextMethod(); fi;
return nonlist^(-1) * grv; end );
############################################################################# ## ## (end of the list arithmetic stuff) ##
############################################################################# ## #F DifferenceBlist ( <blist1>, <blist2> ) ##
InstallGlobalFunction( DifferenceBlist, function( a, b )
a:= ShallowCopy( a );
SubtractBlist( a, b );
return a; end );
############################################################################# ## #F UnionBlist( <blists> ) . . . . . . . . . . . . . . . . . union of blists ##
InstallGlobalFunction( UnionBlist, function( arg )
local union, blist,blists; if Length(arg)=1 and not IsBlist(arg[1]) then
blists:=arg[1]; else
blists:=arg; fi;
union := BlistList( [ 1 .. Length( blists[ 1 ] ) ], [ ] ); for blist in blists do
UniteBlist( union, blist );
od;
return union; end );
############################################################################# ## #F IntersectionBlist( <blists> ) . . . . . . . . . . intersection of blists ##
InstallGlobalFunction( IntersectionBlist, function( arg )
local intersection, blist,blists; if Length(arg)=1 and not IsBlist(arg[1]) then
blists:=arg[1]; else
blists:=arg; fi;
# make a list with all bits set.
intersection:=BlistList([1..Length(blists[1])],[1..Length(blists[1])]); for blist in blists do
IntersectBlist( intersection, blist );
od;
return intersection; end );
############################################################################# ## #M ViewObj( <list> ) . . . . . . . . . . . . . . . . . view the sub-objects ## ## This is a very naive method which will view the sub-objects. A better ## method is needed eventually looking out for long list or homogeneous list ## or dense list, etc. ## ## The line break hints are consistent with those ## that appear in the kernel function 'PrintListDefault' ## and in the 'ViewString' method for finite lists. ##
InstallMethod( ViewObj, "for a finite list",
[ IsList and IsFinite ],
{} -> RankFilter(IsList) + 1 - RankFilter(IsList and IsFinite), function( list )
local i;
if0 = Length(list) and IsInternalRep(list) then
PrintObj( list ); elif0 < Length(list) and IsString(list) then
View(list); # there is a special method for strings else
Print( "\>\>[ \>\>" ); for i in [ 1 .. Length(list) ] do if IsBound(list[i]) then if1 < i then Print( "\<,\< \>\>" ); fi;
# This is needed to handle recursive objects nicely
SET_PRINT_OBJ_INDEX(i);
ViewObj(list[i]); elif1 < i then Print( "\<,\<\>\>" ); fi;
od;
Print( " \<\<\<\<]" ); fi; end );
InstallMethod( ViewObj, "for a range",
[ IsList and IsFinite and IsRange ], function( list )
Print( "[ " ); if Length( list ) = 1then
Print( list[1] ); elif Length( list ) = 2then
Print( list[1], ", ", list[2] ); elif2 < Length( list ) then if list[2] - list[1] <> 1then
Print( list[1], ", ", list[2], " .. ", Last(list) ); else
Print( list[1], " .. ", Last(list) ); fi; fi;
Print( " ]" ); end );
InstallTrueMethod(CanEasilySortElements, IsHomogeneousList and IsEmpty);
############################################################################# ## #M Elements( <coll> ) ## ## for gap3 compatibility. Because `InfoWarning' is not available ## immediately this is not in coll.gi, but in the later read list.gi ##
InstallGlobalFunction(Elements,function(coll)
Info(InfoPerformance,2, "`Elements' is an outdated synonym for `AsSSortedList'");
Info(InfoPerformance,2, "If sortedness is not required, `AsList' might be much faster!");
return AsSSortedList(coll); end);
############################################################################# ## #M IsRectangularTable( <obj> ) ##
InstallMethod( IsRectangularTable, "kernel method for a plain list",
[IsTable and IsPlistRep],
IsRectangularTablePlist);
InstallMethod( IsRectangularTable, "generic",
[ IsList ], function(l)
local len, i, lenl; if not IsTable( l ) then
return false; fi;
lenl := Length(l); if lenl = 1then
return true; fi;
len := Length(l[1]); for i in [2..lenl] do if Length(l[i]) <> len then
return false; fi;
od;
return true; end);
# # Stuff for better storage of blists (trans grp. library) #
BindGlobal( "DECODE_BITS_TO_HEX", function(b,i)
local v;
v:=0; if b[i+0] then v:=v+8; fi; if b[i+1] then v:=v+4; fi; if b[i+2] then v:=v+2; fi; if b[i+3] then v:=v+1; fi;
return HEXNIBBLES[v+1]; end );
InstallGlobalFunction(HexStringBlist,function(b)
local i,n,s;
n:=Length(b);
i:=1;
s:=""; while i+3<=n do
Add(s,DECODE_BITS_TO_HEX(b,i));
i:=i+4;
od; if i <= n then
b:=b{[i..n]}; while Length(b)<4do
Add(b,false);
od;
Add(s,DECODE_BITS_TO_HEX(b,1)); fi; if IsOddInt(Length(s)) then Add(s,'0'); fi;
return s; end);
InstallGlobalFunction(HexStringBlistEncode,function(b)
local i,n,s,t,u,zero;
zero:="00";
n:=Length(b);
i:=1;
s:="";
u:=0; while i+7<=n do
t:="";
Add(t,DECODE_BITS_TO_HEX(b,i));
Add(t,DECODE_BITS_TO_HEX(b,i+4)); if t<>zero then if u>0then if u=1then
Append(s,zero); else
Add(s,'s');
Append(s,HexStringInt(256+u){[2,3]}); fi;
u:=0; fi;
Append(s,t); else
u:=u+1; if u=255then
Add(s,'s');
Append(s,HexStringInt(256+u){[2,3]});
u:=0; fi; fi;
i:=i+8;
od;
b:=b{[i..n]}; while Length(b)<8do
Add(b,false);
od;
t:="";
Add(t,DECODE_BITS_TO_HEX(b,1));
Add(t,DECODE_BITS_TO_HEX(b,5)); if t<>zero then if u>0then if u=1then
Append(s,zero); else
Add(s,'s');
Append(s,HexStringInt(256+u){[2,3]}); fi;
u:=0; fi;
Append(s,t); fi;
return s; end);
InstallGlobalFunction(BlistStringDecode,function(arg)
local s,b,i,j,l;
s:=arg[1];
b:=[];
i:=1; while i<=Length(s) do if s[i]='s'then for j in [1..IntHexString(s{[i+1,i+2]})] do
Append(b,BLISTZERO);
od;
i:=i+3; else
l:=IntHexString(s{[i]});
Append(b,BLISTNIBBLES[16-l]);
l:=IntHexString(s{[i+1]});
Append(b,BLISTNIBBLES[16-l]);
i:=i+2; fi;
od; if Length(arg)>1then
l:=arg[2]; while Length(b)<l do
Append(b,BLISTZERO);
od; if Length(b)>l then
b:=b{[1..l]}; fi; fi;
IsBlist(b);
return b; end);
InstallMethod(IntersectSet, "for two ranges",
[IsRange and IsRangeRep and IsMutable,
IsRange and IsRangeRep ],
INTER_RANGE);
InstallGlobalFunction(Variance, function(l)
local avg;
avg := Average(l);
return Average(List(l, x -> (x-avg)^2)); end);
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.156Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-13)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.