############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Isabel Araújo. ## ## 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 ## ##
############################################################################# ## #M OrderingsFamily(<F>) ##
InstallMethod( OrderingsFamily, "for a family", true, [IsFamily], 0, function( fam)
local ord_req, ord_imp;
###################################################################### ## #F CreateOrderingByLtFunction( <fam>, <fun>, <list> ) ## ## creates an orderings for the elements of the family fam ## with LessThan given by <fun> ## and with the properties list in <list> ##
BindGlobal("CreateOrderingByLtFunction", function( fam, fun, list)
local ord,prop;
if NumberArgumentsFunction(fun)<>2then
return Error("Function for orderings has to have two arguments"); fi;
ord := Objectify(
NewType( OrderingsFamily( fam ),
IsAttributeStoringRep),rec());
# now set the properties in list to true for prop in list do
Setter(prop)(ord,true);
od;
return ord; end);
###################################################################### ## #F CreateOrderingByLteqFunction( <fam>, <fun>, <list> ) ## ## creates an orderings for the elements of the family fam ## with LessThanOrequal given by <fun> ## and with the properties list in <list> ##
BindGlobal("CreateOrderingByLteqFunction", function( fam, fun, list)
local ord,prop;
if NumberArgumentsFunction(fun)<>2then
return Error("Function for orderings has to have two arguments"); fi;
ord := Objectify(
NewType( OrderingsFamily( fam ),
IsAttributeStoringRep),rec());
# now set the properties in list to true for prop in list do
Setter(prop)(ord,true);
od;
return ord; end);
###################################################################### ## #M OrderingByLessThanFunctionNC( <fam>, <fun> ) ##
InstallMethod( OrderingByLessThanFunctionNC, "for a family and a function", true,
[IsFamily, IsFunction], 0, function(fam, fun)
return CreateOrderingByLtFunction(fam,fun,[]); end);
InstallOtherMethod( OrderingByLessThanFunctionNC, "for a family, a function, and a list of properties", true,
[IsFamily,IsFunction,IsList], 0, function(fam,fun,list)
return CreateOrderingByLtFunction( fam,fun,list ); end);
###################################################################### ## #M OrderingByLessThanOrEqualFunctionNC( <fam>, <fun> ) ##
InstallMethod( OrderingByLessThanOrEqualFunctionNC, "for a family and a function", true,
[IsFamily, IsFunction], 0, function(fam, fun)
return CreateOrderingByLteqFunction(fam,fun,[]); end);
InstallOtherMethod( OrderingByLessThanOrEqualFunctionNC, "for a family, a function, and a list of properties", true,
[IsFamily,IsFunction,IsList], 0, function(fam,fun,list)
return CreateOrderingByLteqFunction( fam,fun,list ); end);
############################################################################# ## #A LessThanOrEqualFunction( <ord> ) ##
InstallMethod( LessThanOrEqualFunction, "for an ordering which has a LessThanFunction", true,
[IsOrdering and HasLessThanFunction], 0, function( ord)
local fun;
fun := function(x,y)
return x=y or LessThanFunction(ord)(x,y); end;
return fun; end);
############################################################################# ## #A LessThanFunction( <ord> ) ##
InstallMethod( LessThanFunction, "for an ordering which has a LessThanOrEqualFunction", true,
[IsOrdering and HasLessThanOrEqualFunction], 0, function( ord)
local fun;
fun := function(x,y)
return x<>y and LessThanOrEqualFunction(ord)(x,y); end;
if FamilyObj(obj1)<>FamilyObj(obj2) then
Error("Can only compare objects belonging to the same family"); fi; if FamilyObj(ord)<>OrderingsFamily(FamilyObj(obj1)) then
Error(ord," and ",obj1,obj2," do not have compatible families"); fi;
fun := LessThanFunction(ord);
return fun(obj1,obj2);
end);
############################################################################# ## #A IsLessThanOrEqualUnder( <ord>,<obj1>, <obj2> ) ##
InstallMethod( IsLessThanOrEqualUnder, "for an ordering and two objects ", true,
[IsOrdering,IsObject,IsObject], 0, function( ord, obj1, obj2 )
local fun;
fun := LessThanOrEqualFunction(ord);
return fun(obj1,obj2);
end);
############################################################################# ## #A IsIncomparableUnder( <ord>,<obj1>, <obj2> ) ## ## for an ordering <ord> on the elements of the family of <el1> and <el2>. ## Returns true if $el1\neq el2$i and `IsLessThanUnder'(<ord>,<el1>,<el2>), ## `IsLessThanUnder'(<ord>,<el2>,<el1>) are both false. ## Returns false otherwise. ## Notice that if obj1=obj2 then they are comparable ##
InstallMethod( IsIncomparableUnder, "for an ordering", true,
[IsOrdering,IsObject,IsObject], 0, function(ord,obj1,obj2)
local lteqfun;
if FamilyObj(obj1)<>FamilyObj(obj2) then
Error("`obj1' and `obj2' must belong to same family"); fi; if not (FamilyObj(ord)=OrderingsFamily(FamilyObj(obj1))) then
Error("`ord' is not an ordering in `OrderingsFamily(obj1)'"); fi;
# if we know that the ordering is total # then any pair of elements is comparable if HasIsTotalOrdering(ord) and IsTotalOrdering(ord) then
return false; fi;
lteqfun := LessThanOrEqualFunction( ord ); # now check that neither obj1 is less than or equal to obj2 # nor obj2 is less than or equal to obj1 # Note that if obj1=obj2 then they are comparable! if (not lteqfun(obj1,obj2)) and (not lteqfun(obj2,obj1)) then
return true; fi;
return false;
end);
###################################################################### ## ## Orderings on families of associative words ##
############################################################################# ## #M LexicographicOrdering( <fam> ) #M LexicographicOrdering( <fam>, <alphabet> ) #M LexicographicOrdering( <fam>, <gensord> ) #M LexicographicOrdering( <f> ) #M LexicographicOrdering( <f>, <alphabet> ) #M LexicographicOrdering( <f>, <gensord> ) #B LexicographicOrderingNC( <fam>, <alphabet> ) ## ## LexicographicOrderingNC is the function that actually does the work ##
BindGlobal("LexicographicOrderingNC", function(fam,alphabet)
local ltfun, # the less than function
ord; # the ordering
ltfun := function(w1,w2)
local i,x,y;
for i in [1..Minimum(Length(w1),Length(w2))] do
x := Subword(w1,i,i);
y := Subword(w2,i,i); if Position(alphabet,x)< Position(alphabet,y) then
return true; elif Position(alphabet,y)<Position(alphabet,x) then
return false; fi;
od; # at this time the shortest one is a prefix of the other one # or they are equal
return Length(w1)<Length(w2); end;
ord := OrderingByLessThanFunctionNC(fam,ltfun,[IsTotalOrdering,
IsOrderingOnFamilyOfAssocWords]);
SetIsTranslationInvariantOrdering(ord, false);
SetOrderingOnGenerators(ord,alphabet);
return ord; end);
InstallOtherMethod( LexicographicOrdering, "for a family of words of a free semigroup or free monoid",
true,
[IsFamily and IsAssocWordFamily], 0, function(fam)
local gens; # the generating set
# first find out if fam is a family of free semigroup or monoid # because we need to get a list of generators (in the default order) if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
return LexicographicOrderingNC(fam,gens);
end);
InstallMethod( LexicographicOrdering, "for a family of words of a free semigroup or free monoid and a list of generators",
true,
[IsFamily and IsAssocWordFamily,IsList and IsAssocWordCollection], 0, function(fam,alphabet)
local gens;
# first find out if fam is a family of free semigroup or monoid # because we need to get a list of generators (in the default order) if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# now check that the elements of alphabet lie in the right family if ElementsFamily(FamilyObj(alphabet))<>fam then
Error("Elements of `alphabet' should be in family `fam'"); fi;
# alphabet has to be a list of size Length(gens) # and all gens have to appear in the alphabet if Length(alphabet)<>Length(gens) or Set(alphabet)<>gens then
Error("The list `alphabet' does not contain all generators"); fi;
return LexicographicOrderingNC(fam,alphabet);
end);
InstallOtherMethod( LexicographicOrdering, "for a family of words of a free semigroup or free monoid and a list",
true,
[IsFamily and IsAssocWordFamily,IsList], 0, function(fam,orderofgens)
local gens, # list of generators
alphabet, # list of gens in the appropriate ordering
n; # the size of the generating set
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# we have to do some checking # orderofgens has to be a list of size Length(gens) # and all indexed of gens have to appear in the list
n := Length(gens); if Length(orderofgens)<>n or Set(orderofgens)<>[1..n] then
Error("`list' is not compatible with `fam'"); fi;
# we have to turn the list giving the order of gens # in a list of gens
alphabet := List([1..Length(gens)],i->gens[orderofgens[i]]);
InstallOtherMethod( LexicographicOrdering, "for a free semigroup and a list of generators",
IsElmsColls,
[IsFreeSemigroup,IsList and IsAssocWordCollection], 0, function(f,alphabet)
return LexicographicOrdering(ElementsFamily(FamilyObj(f)),alphabet); end);
InstallOtherMethod( LexicographicOrdering, "for a free monoid and a list of generators",
IsElmsColls,
[IsFreeMonoid,IsList and IsAssocWordCollection], 0, function(f,alphabet)
return LexicographicOrdering(ElementsFamily(FamilyObj(f)),alphabet); end);
InstallOtherMethod( LexicographicOrdering, "for a free semigroup and a list",
true,
[IsFreeSemigroup,IsList], 0, function(f,gensord)
return LexicographicOrdering(ElementsFamily(FamilyObj(f)),gensord); end);
InstallOtherMethod( LexicographicOrdering, "for a free monoid and a list",
true,
[IsFreeMonoid,IsList], 0, function(f,gensord)
return LexicographicOrdering(ElementsFamily(FamilyObj(f)),gensord); end);
############################################################################# ## #M ShortLexOrdering( <fam> ) #M ShortLexOrdering( <fam>, <alphabet> ) #M ShortLexOrdering( <fam>, <gensorder> ) #M ShortLexOrdering( <f> ) #M ShortLexOrdering( <f>, <alphabet> ) #M ShortLexOrdering( <f>, <gensorder> ) #B ShortLexOrderingNC ( <fam>, <alphabet> ) ## ## We implement these for families of elements of free smg and monoids ## In the first form returns the ShortLexOrdering for the elements of fam ## with the generators of the freeSmg (or freeMonoid) in the default order. ## In the second form returns the ShortLexOrdering for the elements of fam ## with the generators of the freeSmg (or freeMonoid) in the following order: ## gens[i]<gens[j] if and only if orderofgens[i]<orderofgens[j] ##
BindGlobal("ShortLexOrderingNC", function(fam,alphabet)
local ltfun, ord;
# the less than function
ltfun := function(w1,w2)
# if w1=w2 then w1 is certainly not less than w2 if w1=w2 then
return false; fi;
if Length(w1)<Length(w2) then
return true; elif Length(w1)=Length(w2) then
return IsLessThanUnder(LexicographicOrdering(fam,alphabet),w1,w2); fi;
return false; end;
ord := OrderingByLessThanFunctionNC(fam,ltfun,[IsTotalOrdering,
IsReductionOrdering, IsShortLexOrdering,
IsOrderingOnFamilyOfAssocWords]);
SetOrderingOnGenerators(ord,alphabet);
alphabet:=MakeImmutable(List(alphabet,i->GeneratorSyllable(i,1)));
ord!.alphnums:=alphabet; if IsSSortedList(alphabet) then
SetLetterRepWordsLessFunc(ord,function(a,b) if Length(a)<Length(b) then
return true; elif Length(a)>Length(b) then
return false; else
return a<b; fi; end); else
ord!.alphpos:=MakeImmutable(List([1..Maximum(alphabet)],i->Position(alphabet,i)));
SetLetterRepWordsLessFunc(ord,function(a,b) if Length(a)<Length(b) then
return true; elif Length(a)>Length(b) then
return false; else
return List(a,i->SignInt(i)*ord!.alphpos[AbsInt(i)])<
List(b,i->SignInt(i)*ord!.alphpos[AbsInt(i)]); fi; end); fi;
return ord;
end);
InstallOtherMethod( ShortLexOrdering, "for a family of words of a free semigroup or free monoid", true,
[IsFamily and IsAssocWordFamily], 0, function(fam)
local gens;
# first find out if fam is a family of free semigroup or monoid # because we need to get a list of generators (in the default order) if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
return ShortLexOrderingNC(fam,gens); end);
InstallMethod( ShortLexOrdering, "for a family of words of a free semigroup or free monoid and a list of generators",
true,
[IsFamily and IsAssocWordFamily,IsList and IsAssocWordCollection], 0, function(fam,alphabet)
local x, # loop variable
gens, # the generators of the semigroup or monoid
ltfun, # the less than function of the ordering being built,
ord; # the ordering
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# now check that the elements of alphabet lie in the right family if ElementsFamily(FamilyObj(alphabet))<>fam then
Error("Elements of `alphabet' should be in family `fam'"); fi;
# alphabet has to be a list of size Length(gens) # and all gens have to appear in the alphabet if Length(alphabet)<>Length(gens) or Set(alphabet)<>gens then
Error("`fam' and `alphabet' are not compatible"); fi;
# now build the ordering
return ShortLexOrderingNC(fam,alphabet);
end);
InstallOtherMethod( ShortLexOrdering, "for a family of free words of a free semigroup or free monoid and a list",
true, [IsFamily and IsAssocWordFamily,IsList], 0, function(fam,orderofgens)
local i, # loop variable
gens, # the generators of the semigroup or monoid
n, # the length of the generators list
alphabet; # the gens in the desired order
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# we have to do some checking # orderofgens has to be a list of size Length(gens) # and all gens have to appear in the list
n := Length(gens); if Length(orderofgens)<>n or Set(orderofgens)<>[1..n] then
Error("`fam' and `orderofgens' are not compatible"); fi;
# we have to turn the list giving the order of gens # in a list of gens
alphabet := List([1..Length(gens)],i->gens[orderofgens[i]]);
return ShortLexOrderingNC(fam,alphabet); end);
InstallOtherMethod( ShortLexOrdering, "for a free semigroup", true,
[IsFreeSemigroup], 0,
f -> ShortLexOrderingNC(ElementsFamily(FamilyObj(f)),
GeneratorsOfSemigroup(f)));
InstallOtherMethod( ShortLexOrdering, "for a free monoid", true,
[IsFreeMonoid], 0,
f -> ShortLexOrderingNC(ElementsFamily(FamilyObj(f)),GeneratorsOfMonoid(f)));
InstallOtherMethod( ShortLexOrdering, "for a free semigroup and a list of generators in the required order",
IsElmsColls,
[IsFreeSemigroup, IsList and IsAssocWordCollection], 0, function(f,alphabet)
return ShortLexOrdering( ElementsFamily(FamilyObj(f)),alphabet); end);
InstallOtherMethod( ShortLexOrdering, "for a free monoid and a list of generators in the required order ",
IsElmsColls,
[IsFreeMonoid,IsList and IsAssocWordCollection], 0, function(f,alphabet)
return ShortLexOrdering( ElementsFamily(FamilyObj(f)),alphabet); end);
InstallOtherMethod( ShortLexOrdering, "for a free semigroup and a list", true,
[IsFreeSemigroup, IsList], 0, function(f,gensorder)
return ShortLexOrdering( ElementsFamily(FamilyObj(f)),gensorder); end);
InstallOtherMethod( ShortLexOrdering, "for a free monoid and a list", true,
[IsFreeMonoid,IsList], 0, function(f,gensorder)
return ShortLexOrdering( ElementsFamily(FamilyObj(f)),gensorder); end);
############################################################################# ## #F IsShortLexLessThanOrEqual( <u>, <v> ) ## ## for two associative words <u> and <v>. ## It returns true if <u> is less than or equal to <v>, with ## respect to the shortlex ordering. ## (the shortlex ordering is the default one given by u<=v) ## (we have this function here to assure compatibility with gap4.2). ##
InstallGlobalFunction( IsShortLexLessThanOrEqual, function( u, v )
local fam,ord;
fam := FamilyObj(u);
ord := ShortLexOrdering(fam);
return IsLessThanOrEqualUnder(ord,u,v); end);
############################################################################# ## #M WeightLexOrdering( <fam>,<alphabet>,<wt>) #M WeightLexOrdering( <fam>,<gensord>,<wt>) #M WeightLexOrdering( <f>,<wt>,<alphabet>) #M WeightLexOrdering( <f>,<wt>,<gensord>) #B WeightLexOrderingNC( <fam>,<alphabet>,<wt>) ##
BindGlobal("WeightLexOrderingNC", function(fam,alphabet,wt)
local wordwt, # function that given a word returns its weight
ltfun, # the less than function
auxalph,
ord; # the ordering
######################################################### # this is a function that given a word returns its weight
wordwt := function(w)
local i, sum;
sum := 0; for i in [1..Length(alphabet)] do
sum := sum + ExponentSumWord(w,alphabet[i])*wt[i];
od;
return sum; end;
# the less than function
ltfun := function(w1,w2)
local w1wt,w2wt; # the weights of words w1 and w2, resp
# if w1=w2 then w1 is certainly not less than w2 if w1=w2 then
return false; fi;
# then if the sum of the weights of w1 is less than # the sum of the weight of w2 then returns true # so we calculate the weight of w1
w1wt := wordwt(w1);
w2wt := wordwt(w2); if w1wt<w2wt then
return true; elif w1wt=w2wt then
return IsLessThanUnder(LexicographicOrdering(fam,alphabet),w1,w2); fi;
return false; end;
ord := OrderingByLessThanFunctionNC(fam,ltfun,[IsTotalOrdering,
IsReductionOrdering, IsWeightLexOrdering,
IsOrderingOnFamilyOfAssocWords]);
SetOrderingOnGenerators(ord,alphabet);
SetWeightOfGenerators(ord,wt);
auxalph := ShallowCopy(alphabet);
auxalph := List(auxalph,i->GeneratorSyllable(i,1));
ord!.alphnums:=auxalph; if IsSSortedList(auxalph) then
SetLetterRepWordsLessFunc(ord,function(a,b)
local wa,wb;
wa:=Sum(a,i->wt[i]);
wb:=Sum(b,i->wt[i]); if wa<wb then
return true; elif wa>wb then
return false; else
return a<b; fi; end); else
ord!.alphpos:=List([1..Maximum(auxalph)],i->Position(auxalph,i));
SetLetterRepWordsLessFunc(ord,function(a,b)
local wa,wb;
wa:=Sum(a,i->wt[i]);
wb:=Sum(b,i->wt[i]); if wa<wb then
return true; elif wa>wb then
return false; else
return List(a,i->SignInt(i)*ord!.alphpos[AbsInt(i)])<
List(b,i->SignInt(i)*ord!.alphpos[AbsInt(i)]); fi; end); fi;
return ord;
end);
InstallMethod( WeightLexOrdering, "for a family of words of a free semigroup or free monoid, a list of generators and a list of weights",
true,
[IsFamily and IsAssocWordFamily,IsList and IsAssocWordCollection, IsList], 0, function(fam,alphabet,wt)
local x, # loop variable
gens, # the generators of the semigroup or monoid
ltfun, # the less than function of the ordering being built,
w1wt,w2wt, # the weights of w1 and w2, resp
ord; # the ordering
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# now check that the elements of alphabet lie in the right family if ElementsFamily(FamilyObj(alphabet))<>fam then
Error("Elements of `alphabet' should be in family `fam'"); fi;
# alphabet and wt both have to be lists of size Length(gens) # and all gens have to appear in the alphabet if Length(alphabet)<>Length(gens) or Length(wt)<>Length(gens)
or Set(alphabet)<> gens then
Error("`alphabet' and `wt' are not compatible with `fam'"); fi;
InstallOtherMethod( WeightLexOrdering, "for a family of words of a free semigroup or free monoid, and two lists",
true, [IsFamily and IsAssocWordFamily,IsList,IsList], 0, function(fam,orderofgens,wt)
local gens, # the generators of the semigroup or monoid
alphabet; # the gens in the desired order
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# alphabet and wt both have to be lists of size Length(gens) # and all gens have to appear in the alphabet if Length(orderofgens)<>Length(gens) or Length(wt)<>Length(gens)
or Set(orderofgens)<> [1..Length(gens)] then
Error("`orderofgens' and `wt' are not compatible with `fam'"); fi;
# we have to turn the list giving the order of gens # in a list of gens
alphabet := List([1..Length(gens)],i->gens[orderofgens[i]]);
InstallOtherMethod( WeightLexOrdering, "for a free semigroup, a list of generators and a list of weights",
true,
[IsFreeSemigroup,IsList and IsAssocWordCollection,IsList], 0, function(f,alphabet,wt)
return WeightLexOrdering( ElementsFamily(FamilyObj(f)),alphabet,wt); end);
InstallOtherMethod( WeightLexOrdering, "for a free monoid, a list of generators and a list of weights",
true,
[IsFreeMonoid,IsList and IsAssocWordCollection,IsList], 0, function(f,alphabet,wt)
return WeightLexOrdering( ElementsFamily(FamilyObj(f)),alphabet,wt); end);
InstallOtherMethod( WeightLexOrdering, "for a free semigroup, a list giving ordering on generators and a list of weights",
true,
[IsFreeSemigroup,IsList,IsList], 0, function(f,orderofgens,wt)
return WeightLexOrdering( ElementsFamily(FamilyObj(f)),orderofgens,wt); end);
InstallOtherMethod( WeightLexOrdering, "for a free monoid, a list giving ordering on generators and a list of weights",
true,
[IsFreeMonoid,IsList,IsList], 0, function(f,orderofgens,wt)
return WeightLexOrdering( ElementsFamily(FamilyObj(f)),orderofgens,wt); end);
############################################################################# ## #M BasicWreathProductOrdering( <fam> ) #M BasicWreathProductOrdering( <fam>, <alphabet>) #M BasicWreathProductOrdering( <fam>, <gensord>) #M BasicWreathProductOrdering( <f>) #M BasicWreathProductOrdering( <f>, <alphabet>) #M BasicWreathProductOrdering( <f>, <gensord>) #B BasicWreathProductOrderingNC( <fam>, <alphabet>) ## ## We implement these for families of elements of free smg and monoids ## In the first form returns the BasicWreathProductOrdering for the ## elements of fam with the generators of the freeSmg (or freeMonoid) ## in the default order. ## In the second form returns the BasicWreathProductOrdering for the ## elements of fam with the generators of the freeSmg (or freeMonoid) ## in the following order: ## gens[i]<gens[j] if and only if orderofgens[i]<orderofgens[j] ## ## So with the given order on the generators ## u<v if u'<v' where u=xu'y and v=xv'y ## So, if u and v have no common prefix, u is less than v wrt this ordering if ## (i) maxletter(v) > maxletter(u); or ## (ii) maxletter(u) = maxletter(v) and ## #maxletter(u) < #maxletter(v); or ## (iii) maxletter(u) = maxletter(v) =b and ## #maxletter(u) = #maxletter(v) and ## if u = u1 * b * u2 * b ... b * uk ## v = v1 * b * v2 * b ... b * vk ## then u1<v1 in the basic wreath product ordering. ##
BindGlobal("BasicWreathProductOrderingNC", function(fam,alphabet)
local ltfun, # the less than function
oltfun,
nltfun,
alphpos,
ord; # the ordering
nltfun := function(u,v)
local l,eu,ev,mp,np,me,ne;
eu:=ExtRepOfObj(u);
ev:=ExtRepOfObj(v); if eu=ev then
return false; fi; # find the longest common prefix
l:=1; while l<=Length(eu) and l<=Length(ev) and eu[l]=ev[l] do
l:=l+1;
od;
l:=l-1;
if l<>0 or (l=0 and (IsEmpty(eu) or IsEmpty(ev))) then if IsEvenInt(l) then # disagree on generator or ran out # if u is a proper prefix of v (ie l=|u|) then u<v if Length(eu)=l then
return true; # but if v is a proper prefix of u then u>v elif Length(ev)=l then
return false; fi;
eu:=eu{[l+1..Length(eu)]};
ev:=ev{[l+1..Length(ev)]}; elif SignInt(eu[l+1])=SignInt(ev[l+1]) then # disagree on exponent # if u is a proper prefix of v (ie l=|u|) then u<v if Length(eu)=l+1 and AbsInt(eu[l+1])<AbsInt(ev[l+1]) then
return true; # but if v is a proper prefix of u then u>v elif Length(ev)=l+1 and AbsInt(eu[l+1])>AbsInt(ev[l+1]) then
return false; fi; if AbsInt(eu[l+1])<AbsInt(ev[l+1]) then
ev:=ev{[l..Length(ev)]};
ev[2]:=ev[2]-eu[l+1];
eu:=eu{[l+2..Length(eu)]}; else
eu:=eu{[l..Length(eu)]};
eu[2]:=eu[2]-ev[l+1];
ev:=ev{[l+2..Length(ev)]}; fi; else
eu:=eu{[l..Length(eu)]};
ev:=ev{[l..Length(ev)]}; fi; fi; # now eu and ev don't have a common prefix.
#T the code now assumes that all exponents are positive. If we use free #T groups, this needs to be cleaned up
mp:=Length(eu)-1;
np:=Length(ev)-1;
me:=eu[mp+1];
ne:=ev[np+1]; while mp>0 and np>0do if ord!.alphpos[ev[np]]<ord!.alphpos[eu[mp]] then
ne:=ne-1; if ne=0then
np:=np-2; if np>0then
ne:=ev[np+1]; fi; fi; elif ord!.alphpos[eu[mp]]<ord!.alphpos[ev[np]] then
me:=me-1; if me=0then
mp:=mp-2; if mp>0then
me:=eu[mp+1]; fi; fi; else
ne:=ne-1; if ne=0then
np:=np-2; if np>0then
ne:=ev[np+1]; fi; fi;
me:=me-1; if me=0then
mp:=mp-2; if mp>0then
me:=eu[mp+1]; fi; fi; fi;
od;
return mp<=0 and np<>0; end;
######## # # this is obsolete but for tests
oltfun := function(u,v)
local l,m,n,ltgens;
# we start by building the function that gives the order on the alphabet
ltgens := function(x,y)
return Position(alphabet,x)< Position(alphabet,y); end;
if u=v then
return false; fi;
l := LengthOfLongestCommonPrefixOfTwoAssocWords( u, v); if l<>0then # if u is a proper prefix of v (ie l=|u|) then u<v # but if v is a proper prefix of u then u>v if l=Length(u) then
return true; elif l=Length(v) then
return false; fi;
# at this stage none of the words is a proper prefix of the other one # so remove the common prefix from both words
u := Subword( u, l+1, Length(u) );
v := Subword( v, l+1, Length(v) ); fi;
m := Length( u );
n := Length( v );
# so now u and v have no common prefixes # (in particular they are not equal)
while m>0 and n>0do if ltgens(Subword( v, n, n),Subword( u, m, m)) then
n := n - 1; elif ltgens(Subword( u, m, m),Subword( v, n, n)) then
m := m - 1; else
m := m - 1;
n := n - 1; fi;
od;
return m =0 and n<>0; end;
ltfun:=function(u,v)
local x,y;
x:=oltfun(u,v);
y:=nltfun(u,v); if x=y then
return x; else
Error("disagree"); fi; end;
if AssertionLevel()=0then
ltfun:=nltfun; fi;
ord := OrderingByLessThanFunctionNC(fam,ltfun,[IsTotalOrdering,
IsBasicWreathProductOrdering,
IsOrderingOnFamilyOfAssocWords, IsReductionOrdering]);
SetOrderingOnGenerators(ord,alphabet);
InstallOtherMethod(BasicWreathProductOrdering, "for a family of words of a free semigroup or free monoid and a list",
true, [IsAssocWordFamily and IsFamily], 0, function(fam)
local gens; # the generators list
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
InstallMethod(BasicWreathProductOrdering, "for a family of words of a free semigroup or free monoid and a list of generators",
true, [IsAssocWordFamily and IsFamily, IsList and IsAssocWordCollection], 0, function(fam,alphabet)
local gens; # the generators of the semigroup or monoid
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# we have to do some checking # alphabet has to be a list of size Length(gens) # all gens have to appear in the list if Length(alphabet)<>Length(gens) or Set(alphabet)<>gens then
Error("`alphabet' is not compatible with `fam'"); fi;
InstallMethod(BasicWreathProductOrdering, "for a family of words of a free semigroup or free monoid and a list",
true, [IsAssocWordFamily and IsFamily, IsList], 0, function(fam,orderofgens)
local gens, # the generators of the semigroup or monoid
n, # the length of the generators list
alphabet; # the generators in the appropriate order
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# we have to do some checking # orderofgens has to be a list of size Length(gens) # all gens have to appear in the list
n := Length(gens); if Length(orderofgens)<>n or Set(orderofgens)<>[1..n] then
Error("`orderofgens' is not compatible with `fam'"); fi;
# we have to turn the list giving the order of gens # in a list of gens
alphabet := List([1..Length(gens)],i->gens[orderofgens[i]]);
InstallOtherMethod(BasicWreathProductOrdering, "for a free semigroup and a list of generators", true,
[IsFreeSemigroup,IsList and IsAssocWordCollection], 0, function(f,alphabet)
return BasicWreathProductOrdering(ElementsFamily(FamilyObj(f)),alphabet); end);
InstallOtherMethod(BasicWreathProductOrdering, "for a free monoid and a list of generators", true,
[IsFreeMonoid,IsList and IsAssocWordCollection], 0, function(f,alphabet)
return BasicWreathProductOrdering(ElementsFamily(FamilyObj(f)),alphabet); end);
InstallOtherMethod(BasicWreathProductOrdering, "for a free semigroup and a list", true,
[IsFreeSemigroup,IsList], 0, function(f,gensorder)
return BasicWreathProductOrdering(ElementsFamily(FamilyObj(f)),gensorder); end);
InstallOtherMethod(BasicWreathProductOrdering, "for a free monoid and a list", true,
[IsFreeMonoid,IsList], 0, function(f,gensorder)
return BasicWreathProductOrdering(ElementsFamily(FamilyObj(f)),gensorder); end);
############################################################################# ## #F IsBasicWreathLessThanOrEqual( <u>, <v> ) ## ## for two associative words <u> and <v>. ## It returns true if <u> is less than or equal to <v>, with ## respect to the basic wreath product ordering. ## (we have this function here to assure compatibility with gap4.2). ##
InstallGlobalFunction( IsBasicWreathLessThanOrEqual, function( u, v )
local fam,ord;
fam := FamilyObj(u);
ord := BasicWreathProductOrdering(fam);
return IsLessThanOrEqualUnder(ord,u,v); end);
############################################################################# ## #M WreathProductOrdering( <fam>, <levels> ) #M WreathProductOrdering( <fam>, <gensord>, <levels>) #M WreathProductOrdering( <f>, <levels>) #M WreathProductOrdering( <f>, <gensord>, <levels>) ## ## We implement these for families of elements of free smg and monoids ## In the first form returns the WreathProductOrdering for the ## elements of fam with the generators of the freeSmg (or freeMonoid) ## in the default order. ## In the second form returns the WreathProductOrdering for the ## elements of fam with the generators of the freeSmg (or freeMonoid) ## in the following order: ## gens[i]<gens[j] if and only if orderofgens[i]<orderofgens[j] ## ## <levels> is a list of length equal to the number of generators, ## specifying the levels of the generators IN THEIR NEW ORDERING, ## That is, levels[i] is the level of the generator that comes i-th ## in the new ordering. ## ## So with the given order on the generators ## u<v if u'<v' where u=xu'y and v=xv'y ## So, if u and v have no common prefix, u is less than v wrt this ordering if ## (i) u_max < v_max in the shortlex ordering, where u_max, v_max are ## the words obtained from u, v by removing all letters that do not ## the highest level, or ## (ii) u_max = v_max and ## if u = u1 * u_m1 * u2 * u_m2 ... b * u_mk ## v = v1 * v_m1 * v2 * v_m2 ... b * v_mk ## where u_mi, v_mi are the maximal subwords of u, v containing ## only the letters of maximal weight ## (so u_max = u_m1 * u_m2 * ... * u_mk = v_m1 * v_m2 * ... * v_mk), ## then u1<v1 in the wreath product ordering. ##
InstallOtherMethod(WreathProductOrdering, "for a family of words of a free semigroup or free monoid and a list",
true, [IsAssocWordFamily and IsFamily,IsList], 0, function(fam, levels)
local gens;
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
InstallMethod(WreathProductOrdering, "for a family of words of a free semigroup or free monoid and a list",
true, [IsAssocWordFamily and IsFamily, IsList, IsList], 0, function(fam,orderofgens,levels)
local i, # loop variable
gens, # the generators of the semigroup or monoid
ltgens, # the function giving the order on the alphabet
ltfun, # the less than function
ord; # the ordering
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# we have to do some checking # orderofgens has to be a list of size Length(gens) if Length(orderofgens)<>Length(gens) then
TryNextMethod(); fi; # all gens have to appear in the list for i in [1..Length(orderofgens)] do if not i in orderofgens then
TryNextMethod(); fi;
od;
# now we build the less than function for the ordering
ltfun := function(u,v)
local l, #length of common prefix of u,v
m, #current position in scan of u (from right)
n, #current position in scan of v (from right)
ug, vg, #Current generators of u, v
ug_lev, vg_lev, #levels of urrent generators of u, v
sl_lev, #level at which one of the words u,v is #smaller in the shortlex ordering
sl, #sl=1 or 2 if u or v, resp., is #smaller in the shortlex ordering at level sl_lev. #note sl=0 <=> sl_lev=0.
levgens; #functions on generators
# we start by building the function that gives the order on # the alphabet # we construct it from the list <orderofgens>
ltgens := function(x,y)
return Position(orderofgens,Position(gens,x))<
Position(orderofgens,Position(gens,y)); end;
#and similarly for the level function on the alphabet
levgens := function(x)
return levels[Position(orderofgens,Position(gens,x))]; end;
if u=v then
return false; fi;
if Length(u)=0then
return true; fi; if Length(v)=0then
return false; fi;
l := LengthOfLongestCommonPrefixOfTwoAssocWords( u, v); if l<>0then # if u is a proper prefix of v (ie l=|u|) then u<v # but if v is a proper prefix of u then u>v if l=Length(u) then
return true; elif l=Length(v) then
return false; fi;
# at this stage none of the words is a proper prefix of the # other one so remove the common prefix from both words
u := Subword( u, l+1, Length(u) );
v := Subword( v, l+1, Length(v) ); fi;
# so now u and v have no common prefixes # (in particular they are not equal)
m := Length( u );
n := Length( v );
sl_lev := 0;
sl := 0;
#We now start scanning u,v from right to left. #sl_lev denotes the level of the block of generators #which is currently distinguishing between u,v. #sl = 1 or 2 if u or v is smaller, respectively, in this block. #Initially sl_lev=sl=0. This can also occur later if either # (i) we read two equal generators in u,v at a higher level # than sl_lev. Then everything to the right of these # equal generators becomes irrelevant. #(ii) we read a generator in u or v at a higher level than # sl_lev that is not matched by a generator at the same # level in the other word. We keep scanning backwards # along the other word until we find a generator of the # corresponding level or higher, but keep sl_lev=sl=0 # while we are doing this. while m>0 or n>0do #Print(m,n,sl,sl_lev,"\n"); if m<>0then
ug := Subword(u,m,m);
ug_lev := levgens(ug); fi; if n<>0then
vg := Subword(v,n,n);
vg_lev := levgens(vg); fi; if m = 0then #we have reached the beginning of u, but #u might be ahead in shortlex at sl_lev if sl <> 2 or vg_lev >= sl_lev then #u is certainly smaller
return true; fi; #u is ahead in shortlex at sl_lev, so keep #scanning v
n := n-1; elif n = 0then #we have reached the beginning of v, but #v might be ahead in shortlex at sl_lev if sl <> 1 or ug_lev >= sl_lev then #v is certainly smaller
return false; fi; #v is ahead in shortlex at sl_lev, so keep #scanning u.
m := m-1; elif vg_lev < ug_lev and sl_lev <= ug_lev then #u is now at a higher level than v
n := n - 1; if sl_lev < ug_lev then #we are in situation (ii) (see above)
sl_lev := 0;
sl := 0; fi; elif ug_lev < vg_lev and sl_lev <= vg_lev then #v is now at a higher level than u
m := m - 1; if sl_lev < vg_lev then #we are in situation (ii) (see above)
sl_lev := 0;
sl := 0; fi; elif ug_lev = vg_lev and sl_lev <= vg_lev then #u and v are at same level so use shortlex if ltgens(ug,vg) then
sl := 1;
sl_lev := ug_lev; elif ltgens(vg,ug) then
sl := 2;
sl_lev := ug_lev; elif sl_lev < ug_lev then #u and v are equal at this higher level. #everything to the right of u,v is now #irrelevant we are in situation (i) above.
sl := 0;
sl_lev := 0; fi;
m := m - 1;
n := n - 1; else #ug and vg are both at a lower level than sl_lev, #so can be ignored.
m := m-1;
n := n-1; fi;
od;
#We have reached the ends of both words, so sl tells us #which is the smaller. if sl = 1then
return true; elif sl = 2then
return false; else
Error("There is a bug in WreathProductOrdering!"); fi; end;
ord := OrderingByLessThanFunctionNC(fam,ltfun,[IsTotalOrdering,
IsWreathProductOrdering,
IsOrderingOnFamilyOfAssocWords, IsReductionOrdering]);
SetOrderingOnGenerators(ord,orderofgens);
SetLevelsOfGenerators(ord,List([1..Length(gens)],j->
levels[Position(orderofgens,j)]) );
return ord;
end);
InstallOtherMethod(WreathProductOrdering, "for a family of associative words, a list of generators and a list with the levels of the generators", true,
[IsAssocWordFamily,IsList and IsAssocWordCollection,IsList], 0, function(fam,alphabet,levels)
local gens,gensord,n;
# first find out if fam is a family of free semigroup or monoid if IsBound(fam!.freeSemigroup) then
gens := GeneratorsOfSemigroup(fam!.freeSemigroup); elif IsBound(fam!.freeMonoid) then
gens := GeneratorsOfMonoid(fam!.freeMonoid); else
TryNextMethod(); fi;
# we have to do some checking # alphabet has to be a list of size Length(gens) # all gens have to appear in the list
n := Length(gens); if Length(alphabet)<>n or Set(alphabet)<>gens then
Error("`alphabet' is not compatible with `fam'"); fi;
# we have to turn the `alphabet' to a list giving the order of gens
gensord := List([1..Length(gens)],i-> Position(gens,alphabet[i]));
InstallOtherMethod(WreathProductOrdering, "for a free monoid and a list", true,
[IsFreeMonoid,IsList,IsList], 0, function(f,gensorder,levels)
return WreathProductOrdering(ElementsFamily(FamilyObj(f)),gensorder,levels); end);
InstallOtherMethod(WreathProductOrdering, "for a free semigroup and a list", true,
[IsFreeSemigroup,IsList,IsList], 0, function(f,gensorder,levels)
return WreathProductOrdering(ElementsFamily(FamilyObj(f)),gensorder,levels); end);
InstallOtherMethod(WreathProductOrdering, "for a free monoid and a list", true,
[IsFreeMonoid,IsList,IsList], 0, function(f,gensorder,levels)
return WreathProductOrdering(ElementsFamily(FamilyObj(f)),gensorder,levels); end);
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.