|
#############################################################################
##
## This file is part of GAP, a system for computational discrete algebra.
## This file's authors include Isabel Araújo and Andrew Solomon.
##
## 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 code for the Knuth-Bendix rewriting system for semigroups
## and monoids.
##
InstallGlobalFunction(EmptyKBDAG,function(genids)
local offset,deadend;
if Length(genids)=0 then
offset:=0;
deadend:=[];
else
offset:=Minimum(genids);
deadend:=ListWithIdenticalEntries(Maximum(genids)-offset+1,fail);
fi;
# index shifting so we always start at 1
if offset>0 then offset:=offset-1;
else offset:=1-offset;fi;
return rec(IsKBDAG:=true,
genids:=genids,
offset:=offset,
deadend:=deadend,
backpoint:=[],
dag:=ShallowCopy(deadend));
end);
InstallGlobalFunction(AddRuleKBDAG,function(d,left,idx)
local offset,node,j,a;
offset:=d.offset;
node:=d.dag;
for j in [1..Length(left)] do
a:=left[j]+offset;
if node[a]=fail then
if j=Length(left) then
# store index position
d.backpoint[idx]:=[node,a];
node[a]:=idx;
return true;
else
node[a]:=ShallowCopy(d.deadend); # at least one symbol more
node:=node[a];
fi;
elif IsList(node[a]) then
if j<Length(left) then
node:=node[a]; # go to next letter
else
# rule would reduce existing LHS
return fail;
fi;
else
#LHS could have been reduced with existing rules
return false;
fi;
od;
return true;
end);
InstallGlobalFunction(DeleteRuleKBDAG, function(d,left,idx)
local backpoint,i,a,node,offset;
backpoint:=d.backpoint;
backpoint[idx][1][backpoint[idx][2]]:=fail; # #rule indicator is gone
for i in [idx+1..Length(backpoint)] do
a:=backpoint[i][2];
#if backpoint[i][1][a]<>i then Error("poss");fi;
backpoint[i][1][a]:=backpoint[i][1][a]-1; # decrease index numbers
backpoint[i-1]:=backpoint[i]; # and correct back pointers
od;
Remove(backpoint);
# now trace through the word and kill nodes that are all fail
offset:=d.offset;
a:=Length(left)-2;
while a>-1 do
node:=d.dag;
for i in [1..a] do
node:=node[left[i]+offset];
od;
# where are we at length a+1?
if node[left[a+1]+offset]=d.deadend then
node[left[a+1]+offset]:=fail;
else
a:=0;
fi;
a:=a-1;
od;
end);
InstallGlobalFunction(RuleAtPosKBDAG,function(d,w,p)
local node,q;
node:=d.dag;
q:=p;
while IsList(node) and q<=Length(w) do
node:=node[w[q]+d.offset];
q:=q+1;
od;
if IsInt(node) then
return node; # the rule number to apply
else
# fail or list -- no rule applies
return fail;
fi;
end);
# Function to test validity of DAG structure
# BindGlobal("VerifyKBDAG",function(d,tzrules)
# local offset,node,j,a,idx,left,recurse;
# if Length(d!.backpoint)<>Length(tzrules) then Error("len");fi;
# offset:=d.offset;
# for idx in [1..Length(tzrules)] do
# left:=tzrules[idx][1];
#
# node:=d.dag;
# for j in [1..Length(left)] do
# a:=left[j]+offset;
# if node[a]=fail then
# Error("not stored");
# elif j=Length(left) then
# # end -- check
# if d.backpoint[idx]<>[node,a] or node[a]<>idx then Error("data!"); fi;
# else
# if not IsList(node[a]) then Error("too short");fi;
# node:=node[a]; # go to next letter
# fi;
# od;
# od;
#
# recurse:=function(n)
# local i,flag;
# if not IsList(n) then
# return;
# else
# flag:=true;
# for i in n do
# if IsList(i) then
# recurse(i);
# flag:=false;
# elif IsInt(i) then
# flag:=false;
# fi;
# od;
# if flag and n<>d.dag then Error("stored fail list");fi;
# fi;
# end;
#
# recurse(d.dag);
#end);
############################################################################
##
#R IsKnuthBendixRewritingSystemRep(<obj>)
##
## reduced - is the system known to be reduced
## fam - the family of elements of the fp smg/monoid
##
DeclareRepresentation("IsKnuthBendixRewritingSystemRep",
IsComponentObjectRep,
["family", "tzrules","pairs2check", "reduced", "ordering"]);
#############################################################################
##
#F CreateKnuthBendixRewritingSystem(<fam>, <wordord>)
##
## <wordord> is a reduction ordering
## (compatible with left and right multiplication).
##
## A Knuth Bendix rewriting system consists of a list of relations,
## which we call rules, and a list of pairs of numbers
## or more generalized form for saving memory (pairs2check).
## Each lhs of a rule has to be greater than its rhs
## (so when we apply a rule to a word, we are effectively reducing it -
## according to the ordering considered)
## Each number in a pair of the list pairs2check
## refers to one of the rules. A pair corresponds to a pair
## of rules where confluence was not yet checked (according to
## the Knuth Bendix algorithm).
## Pairs might also be given in the form of a 3-entry list
## ['A',x,l] to denote all pairs of the form [x,y] for y in l,
## respectively ['B',l,y] for pairs [x,y] with x in l.
##
## Note that at this stage the kb rws obtained might not be reduced
## (the same relation might even appear several times).
##
InstallGlobalFunction(CreateKnuthBendixRewritingSystem,
function(fam, wordord)
local r,kbrws,rwsfam,relations_with_correct_order,CantorList,relwco,
w,freefam,gens;
#changes the set of relations so that lhs is greater then rhs
# and removes trivial rules (like u=u)
relations_with_correct_order:=function(r,wordord)
local i,q;
q:=ShallowCopy(r);
for i in [1..Length(q)] do
if q[i][1]=q[i][2] then
Unbind(q[i]);
elif IsLessThanUnder(wordord,q[i][1],q[i][2]) then
q[i]:=[q[i][2],q[i][1]];
fi;
od;
return Unique(q);
end;
# generates the list of all pairs (x,y)
# where x,y are distinct elements of the set [1..n]
# encoded in compact form
CantorList:=function(n)
local i,l;
l:=[];
for i in [2..n] do
Add(l,['A',i,[1..i-1]]);
Add(l,['B',[1..i-1],i]);
od;
return(l);
end;
if ValueOption("isconfluent")=true then
CantorList:=n->[];
fi;
# check that fam is a family of elements of an fp smg or monoid
if not (IsElementOfFpMonoidFamily(fam) or IsElementOfFpSemigroupFamily(fam))
then
Error(
"Can only create a KB rewriting system for an fp semigroup or monoid");
fi;
# check the second argument is a reduction ordering
if not (IsOrdering(wordord) and IsReductionOrdering(wordord)) then
Error("Second argument must be a reduction ordering");
fi;
if IsElementOfFpMonoidFamily(fam) then
w:=CollectionsFamily(fam)!.wholeMonoid;
r:=RelationsOfFpMonoid(w);
freefam:=ElementsFamily(FamilyObj(FreeMonoidOfFpMonoid(w)));
gens:=GeneratorsOfMonoid(FreeMonoidOfFpMonoid(w));
else
w:=CollectionsFamily(fam)!.wholeSemigroup;
r:=RelationsOfFpSemigroup(w);
freefam:=ElementsFamily(FamilyObj(FreeSemigroupOfFpSemigroup(w)));
gens:=GeneratorsOfSemigroup(FreeSemigroupOfFpSemigroup(w));
fi;
rwsfam := NewFamily("Family of Knuth-Bendix Rewriting systems",
IsKnuthBendixRewritingSystem);
relwco:=relations_with_correct_order(r,wordord);
kbrws := Objectify(NewType(rwsfam,
IsMutable and IsKnuthBendixRewritingSystem and
IsKnuthBendixRewritingSystemRep),
rec(family:= fam,
reduced:=false,
tzrules:=List(relwco,i->
[LetterRepAssocWord(i[1]),LetterRepAssocWord(i[2])]),
pairs2check:=CantorList(Length(r)),
ordering:=wordord,
freefam:=freefam,
generators:=gens));
kbrws!.kbdag:=EmptyKBDAG(Concatenation(List(gens,LetterRepAssocWord)));
if ValueOption("isconfluent")=true then
kbrws!.createdconfluent:=true;
fi;
if HasLetterRepWordsLessFunc(wordord) then
kbrws!.tzordering:=LetterRepWordsLessFunc(wordord);
else
kbrws!.tzordering:=false;
fi;
if IsElementOfFpMonoidFamily(fam) then
SetIsBuiltFromMonoid(kbrws,true);
else
SetIsBuiltFromSemigroup(kbrws,true);
fi;
return kbrws;
end);
#############################################################################
##
#A ReduceRules(<RWS>)
##
## Reduces the set of rules of a Knuth Bendix Rewriting System
##
InstallMethod(ReduceRules,
"for a Knuth Bendix rewriting system", true,
[ IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep and IsMutable ], 0,
function(rws)
local
r, # local copy of the rules
ptc, # do we need to check pairs
v; # a rule
ptc:=not (IsBound(rws!.createdconfluent) and rws!.createdconfluent);
r := ShallowCopy(rws!.tzrules);
rws!.tzrules:=[];
if ptc then
rws!.pairs2check:=[];
else
Unbind(rws!.pairs2check);
fi;
rws!.reduced := true;
if IsBound(rws!.kbdag) then
rws!.kbdag.stepback:=11;
fi;
for v in r do
AddRuleReduced(rws, v);
od;
if not ptc then
rws!.pairs2check:=[];
fi;
end);
# use bit lists to reduce the numbers of rules to test
# this should ultimately become part of the kernel routine
BindGlobal("ReduceLetterRepWordsRewSysNew",function(tzrules,w,dag)
local has,n,p,back;
if not IsRecord(dag) then
return ReduceLetterRepWordsRewSys(tzrules,w);
fi;
w:=ShallowCopy(w); # so we can replace
if IsBound(dag.stepback) then back:=dag.stepback;
else back:=11;fi;
repeat
has:=false;
p:=1;
while p<=Length(w) do
# find the rule applying at the position in the dag
n:=RuleAtPosKBDAG(dag,w,p);
if n<>fail then
# now apply rule
if Length(tzrules[n][1])=Length(tzrules[n][2]) then
w{[p..p+Length(tzrules[n][1])-1]}:=tzrules[n][2];
else
w:=Concatenation(w{[1..p-1]},tzrules[n][2],
w{[p+Length(tzrules[n][1])..Length(w)]});
fi;
has:=true;
# step a bit back. It doesn't really matter, as we only terminate if
# we have once run through the whole list without doing any change.
p:=Maximum(0,p-back);
fi;
p:=p+1;
od;
until has=false;
return w;
end);
InstallOtherMethod(AddRule,
"Fallback Method, call AddRuleReduced", true,
[ IsKnuthBendixRewritingSystem and IsMutable
and IsKnuthBendixRewritingSystemRep, IsList ], -1,
function(kbrws,v)
Info(InfoWarning,1,"Fallback method -- calling `AddRuleReduced` instead");
AddRuleReduced(kbrws,v);
end);
#############################################################################
##
#O AddRuleReduced(<RWS>, <tzrule>)
##
## Add a rule to a rewriting system and, if the system is already
## reduced it will remain reduced. Note, this also changes the pairs
## of rules to check.
##
## given a pair v of words that have to be equal it checks whether that
## happens or not and adjoin new rules if necessary. Then checks that we
## still have something reduced and keep removing and adding rules, until
## we have a reduced system where the given equality holds and everything
## that was equal before is still equal. It returns the resulting rws
##
## See Sims: "Computation with finitely presented groups".
##
InstallOtherMethod(AddRuleReduced,
"for a Knuth Bendix rewriting system and a rule", true,
[ IsKnuthBendixRewritingSystem and IsMutable
and IsKnuthBendixRewritingSystemRep, IsList ], 0,
function(kbrws,v)
local u,a,b,c,k,n,s,add_rule,fam,ptc,kbdag,abi,rem,
remove_rules;
# did anyone fiddle with the rules that there are invalid pairs?
# This happens e.g. in the fr package.
if IsBound(kbrws!.pairs2check)
# only do this if its within the fr package to not slow down other uses
and not IsBound(kbrws!.kbdag) then
b:=kbrws!.pairs2check;
k:=false;
a:=Length(kbrws!.tzrules);
for n in [1..Length(b)] do
s:=b[n];
if (Length(s)=2 and s[1]>a or s[2]>a)
or (s[1]='A' and s[2]>a) or (s[1]='B' and s[3]>a) then
b[n]:=fail; k:=true;
elif s[1]='A' and ForAny(s[3],x->x>a) then
s[3]:=Filtered(s[3],x->x<=a);
elif s[1]='B' and ForAny(s[2],x->x>a) then
s[2]:=Filtered(s[2],x->x<=a);
fi;
od;
if k then kbrws!.pairs2check:=Filtered(b,x->x<>fail);fi;
fi;
# the fr package assigns initial tzrules on its own, this messes up
# the dag structure. Delete ...
if IsBound(kbrws!.kbdag) and
Length(kbrws!.kbdag.backpoint)<>Length(kbrws!.tzrules) then
Info(InfoPerformance,2,
"Cannot use dag for lookup since rules were assigned directly");
#a:=EmptyKBDAG(kbrws!.kbdag.genids);
#kbrws!.kbdag:=a;
#for b in [1..Length(kbrws!.tzrules)] do
# AddRuleKBDAG(a,kbrws!.tzrules[b][1],b);
#od;
Unbind(kbrws!.kbdag);
fi;
# allow to give rule also as words in free monoid
if ForAll(v,IsAssocWord) and
IsIdenticalObj(kbrws!.freefam,FamilyObj(v[1])) then
v:=List(v,LetterRepAssocWord);
fi;
ptc:=IsBound(kbrws!.pairs2check);
if IsBound(kbrws!.kbdag) then
kbdag:=kbrws!.kbdag;
else
kbdag:=fail;
fi;
# older, less efficient version for just single rule
# #given a Knuth Bendix Rewriting System, kbrws,
# #removes rule i of the set of rules of kbrws and
# #modifies the list pairs2check in such a way that the previous indexes
# #are modified so they correspond to same pairs as before
# remove_rule:=function(i)
# local j,q,l,kk;
#
# if kbdag<>fail then
# # update lookup structure
# DeleteRuleKBDAG(kbdag,kbrws!.tzrules[i][1],i);
# fi;
#
# #remove rule from the set of rules
# #q:=kbrws!.tzrules{[1..i-1]};
# #Append(q,kbrws!.tzrules{[i+1..Length(kbrws!.tzrules)]});
# #kbrws!.tzrules:=q;
# q:=kbrws!.tzrules;
# Remove(q,i);
#
# if ptc then
# #delete pairs of indexes that include i
# #and change occurrences of indexes k greater than i in the
# #list of pairs and change them to k-1
#
# kk:=kbrws!.pairs2check;
#
# #So we'll construct a new list with the right pairs
# l:=[];
# for j in [1..Length(kk)] do
# if Length(kk[j])=2 then
# if kk[j][1]<i then
# if kk[j][2]<i then
# Add(l,kk[j]);
# elif kk[j][2]>i then
# # reindex
# Add(l,[kk[j][1],kk[j][2]-1]);
# fi;
# elif kk[j][1]>i then
# if kk[j][2]<i then
# # reindex
# Add(l,[kk[j][1]-1,kk[j][2]]);
# elif kk[j][2]>i then
# # reindex
# Add(l,[kk[j][1]-1,kk[j][2]-1]);
# fi;
# # else rule gets deleted
# fi;
# elif kk[j][1]='A' then
# if kk[j][2]<i then
# Add(l,kk[j]); # all smaller, no delete
# elif kk[j][2]>i then
# Add(l,['A',kk[j][2]-1,Concatenation(
# Filtered(kk[j][3],x->x<i),Filtered(kk[j][3],x->x>i)-1)]);
# # else pairs deleted since rule deleted
# fi;
# else # 'B' case
# if kk[j][3]<i then
# Add(l,kk[j]); # all smaller, no delete
# elif kk[j][3]>i then
# Add(l,['B',Concatenation(Filtered(kk[j][2],x->x<i),
# Filtered(kk[j][2],x->x>i)-1),kk[j][3]-1]);
# # else pairs deleted since rule deleted
# fi;
# fi;
#
# od;
# kbrws!.pairs2check:=l;
# fi;
#
# end;
#given a Knuth Bendix Rewriting System, kbrws,
#removes the rules indexed by weg from the set of rules of kbrws and
#modifies the list pairs2check in such a way that the previous indexes
#are modified so they correspond to same pairs as before
remove_rules:=function(weg)
local j,q,a,l,kk,i,neu,x,y;
if kbdag<>fail then
for i in weg do
# update lookup structure
DeleteRuleKBDAG(kbdag,kbrws!.tzrules[i][1],i);
od;
fi;
#remove rule from the set of rules
q:=kbrws!.tzrules;
kk:=Minimum(weg);
neu:=[1..kk-1];
for i in [kk..Length(q)] do
if i in weg then
neu[i]:=fail;
else
q[kk]:=q[i];
neu[i]:=kk;
kk:=kk+1;
fi;
od;
for i in [Length(q),Length(q)-1..Length(q)-Length(weg)+1] do
Unbind(q[i]);
od;
if ptc then
#delete pairs of indexes that include i
#and change occurrences of indexes k greater than i in the
#list of pairs and change them to k-1
kk:=kbrws!.pairs2check;
#So we'll construct a new list with the right pairs
l:=[];
for j in [1..Length(kk)] do
if Length(kk[j])=2 then
if not(kk[j][1] in weg or kk[j][2] in weg) then
Add(l,neu{kk[j]});
# otherwise, one is killed
fi;
elif kk[j][1]='A' and not kk[j][2] in weg then
#a:=Difference(neu{kk[j][3]},[fail]);
a:=kk[j][3];
x:=neu[a[1]];y:=neu[Last(a)];
if IsRange(a) and x<>fail and y<>fail then
a:=[x..y];
else
a:=Set(neu{kk[j][3]});
if Last(a)=fail then Remove(a);fi;
fi;
if Length(a)>0 then
Add(l,['A',neu[kk[j][2]],a]);
fi;
elif kk[j][1]='B' and not kk[j][3] in weg then
#a:=Difference(neu{kk[j][2]},[fail]);
a:=kk[j][2];
x:=neu[a[1]];y:=neu[Last(a)];
if IsRange(a) and x<>fail and y<>fail then
a:=[x..y];
else
a:=Set(neu{kk[j][2]});
if Last(a)=fail then Remove(a);fi;
fi;
if Length(a)>0 then
Add(l,['B',a,neu[kk[j][3]]]);
fi;
fi;
od;
kbrws!.pairs2check:=l;
fi;
end;
#given a Knuth Bendix Rewriting System this function returns it
#with the given extra rule adjoined to the set of rules
#and the necessary pairs adjoined to pairs2check
#(the pairs that we have to put in pairs2check correspond to the
#new rule together with all the ones that were in the set of rules
#previously)
add_rule:=function(u,kbrws)
local l,i,j,n,p,any;
#insert rule
Add(kbrws!.tzrules,u);
if kbdag<>fail then
l:=AddRuleKBDAG(kbdag,u[1],Length(kbrws!.tzrules));
if l<>true then Error("rulesubset"); fi;
fi;
#VerifyKBDAG(kbdag,kbrws!.tzrules);
if ptc then
#insert new pairs
l:=kbrws!.pairs2check;
n:=Length(kbrws!.tzrules);
Add(l,[n,n]);
#for i in [1..n-1] do
# Append(l,[[i,n],[n,i]]);
#od;
if n>1 then
Add(l,['A',n,[1..n-1]]);
Add(l,['B',[1..n-1],n]);
fi;
kbrws!.pairs2check:=l;
fi;
if IsBound(kbrws!.invmap) then
# free cancel part
u:=List(u,ShallowCopy);
i:=1;
while i<=Length(u[1]) and i<=Length(u[2]) and u[1][i]=u[2][i] do
i:=i+1;
od;
any:=false;
for j in [i..Length(u[2])] do
p:=Concatenation(kbrws!.invmap{u[1]{[j,j-1..i]}},
u[2]{[i..j]});
l:=ReduceLetterRepWordsRewSysNew(kbrws!.tzrules,p,kbdag);
#Print("fellow ",List(u,Length),Length(p)," ",Length(l),"\n");
if not l in kbrws!.fellowTravel then
Add(kbrws!.fellowTravel,l);
any:=true;
if Length(kbrws!.fellowTravel) mod 200=0 then
kbrws!.fellowTravel:=List(kbrws!.fellowTravel,
x->ReduceLetterRepWordsRewSysNew(kbrws!.tzrules,x,kbdag));
kbrws!.fellowTravel:=Unique(kbrws!.fellowTravel);
fi;
fi;
od;
if any then
kbrws!.flaute:=0;
else
kbrws!.flaute:=kbrws!.flaute+1;
fi;
fi;
end;
#the stack is a list of pairs of words such that if two words form a pair
#they have to be equivalent, that is, they have to reduce to same word
#TODO
fam:=kbrws!.freefam;
#we put the pair v in the stack
s:=[v];
#while the stack is non empty
while not(IsEmpty(s)) do
#VerifyKBDAG(kbdag,kbrws!.tzrules);
#pop the first rule from the stack
#use rules available to reduce both sides of rule
u:=s[1];
s:=s{[2..Length(s)]};
a:=ReduceLetterRepWordsRewSysNew(kbrws!.tzrules,u[1],kbdag);
b:=ReduceLetterRepWordsRewSysNew(kbrws!.tzrules,u[2],kbdag);
#if both sides reduce to different words
#have to adjoin a new rule to the set of rules
if not(a=b) then
#TODO
if kbrws!.tzordering=false then
c:=IsLessThanUnder(kbrws!.ordering,
AssocWordByLetterRep(fam,a),AssocWordByLetterRep(fam,b));
else
c:=kbrws!.tzordering(a,b);
fi;
if c then
c:=a; a:=b; b:=c;
fi;
#Now we have to check if by adjoining this rule
#any of the other active ones become redundant
n:=Length(kbrws!.tzrules);
# go descending to avoid having to reindex
rem:=[];
for k in [n,n-1..1] do
#if lhs of rule k contains lhs of new rule
#as a subword then we delete rule k
#but add it to the stack, since it has to still hold
if PositionSublist(kbrws!.tzrules[k][1],a,0)<>fail then
Add(s,kbrws!.tzrules[k]);
Add(rem,k);
n:=Length(kbrws!.tzrules)-1;
fi;
od;
if Length(rem)>0 then
remove_rules(rem);
fi;
#VerifyKBDAG(kbdag,kbrws!.tzrules);
# and store new rule
add_rule([a,b],kbrws);
kbrws!.reduced := false;
n:=Length(kbrws!.tzrules);
for k in [n,n-1..1] do
#else if rhs of rule k contains the new rule
#as a subword then we use the new rule
#to reduce that rhs
if PositionSublist(kbrws!.tzrules[k][2],a,0)<>fail then
kbrws!.tzrules[k][2]:=
ReduceLetterRepWordsRewSysNew(kbrws!.tzrules,
kbrws!.tzrules[k][2],kbdag);
fi;
od;
fi;
od;
kbrws!.reduced := true;
end);
#############################################################################
##
#M MakeKnuthBendixRewritingSystemConfluent (<KBRWS>)
##
## RWS is a Knuth Bendix Rewriting System
## This function takes a Knuth Bendix Rws (ie a set of rules
## and a set of pairs which indicate the rules that
## still have to be checked for confluence) and
## applies the Knuth Bendix algorithm for strigs to it to get a reduced
## confluent rewriting system.
##
## Confluence means the following: if w is a word which can be reduced
## using two different rules, say w->u and w->v, then the irreducible forms
## of u and v are the same word.
##
## To construct a rws from a set of rules consists of adjoining new
## rules if necessary to be sure the confluence property holds
##
## This implementation of Knuth-bendix also guarantees that we will
## obtain a reduced rws, meaning that there are not redundant rules
##
## Note (see Sims, `Computation with finitely presented groups', 1994)
## a reduced confluent rewriting system for a semigroup with a given set of
## generators is unique, under a given ordering.
InstallGlobalFunction( MakeKnuthBendixRewritingSystemConfluent,
function ( rws )
Info( InfoKnuthBendix, 1, "MakeKnuthBendixRewritingSystemConfluent called" );
# call the KB plugin
KB_REW.MakeKnuthBendixRewritingSystemConfluent(rws);
Info( InfoKnuthBendix, 1, "KB terminates with ",Length(rws!.tzrules),
" rules" );
end);
# We store compressed data -- expand, (and also delete old stuff)
BindGlobal("KBRWSUnpackPairsAt",function(kbrws,p)
local i,a;
i:=kbrws!.pairs2check[p];
if IsChar(i[1]) then
# We store compressed data -- expand, (and also delete old stuff)
if i[1]='A' then
a:=List(i[3],x->[i[2],x]);
elif i[1]='B' then
a:=List(i[2],x->[x,i[3]]);
else Error("kind"); fi;
kbrws!.pairs2check:=Concatenation(a,kbrws!.pairs2check{[p+1..Length(kbrws!.pairs2check)]});
p:=1;
fi;
return p;
end);
#u and v are pairs of rules, kbrws is a kb RWS
#look for proper overlaps of lhs (lhs of u ends as lhs of v starts)
#Check confluence does not fail here, adjoining extra rules if necessary
BindGlobal("KBOverlaps",function(ui,vi,kbrws,p)
local u,v,m,k,a,c,lsu,lsv,lu,eq,i,j;
# work around copied code in kan package
if IsChar(ui) then # must unpack
p:=KBRWSUnpackPairsAt(kbrws,p);
vi:=kbrws!.pairs2check[p];
ui:=vi[1];vi:=vi[2];
fi;
u:=kbrws!.tzrules[ui]; v:=kbrws!.tzrules[vi];
lsu:=u[1];
lu:=Length(lsu);
lsv:=v[1];
#we are only going to consider proper overlaps
#m:=Minimum(lu,Length(lsv))-1;
m:=Length(lsv)-1;
if lu<=m then
m:=lu-1;
fi;
#any overlap will have length less than m
k:=1;
while k<=m do
#if the last k letters of u[1] are the same as the 1st k letters of v[1]
#they overlap
#if Subword(u[1],Length(u[1])-k+1,Length(u[1]))=Subword(v[1],1,k) then
eq:=true;
i:=lu-k+1;
j:=1;
while eq and j<=k do
eq:=lsu[i]=lsv[j];
i:=i+1;
j:=j+1;
od;
if eq then
#a:=Subword(u[1],1,Length(u[1])-k)*v[2];
#c:=u[2]*Subword(v[1],k+1,Length(v[1]));
# we can't have cancellation
a:=Concatenation(lsu{[1..lu-k]},v[2]);
c:=Concatenation(u[2],lsv{[j..Length(lsv)]});
#for guarantee confluence a=c has to hold
#we change rws, if necessary, so a=c is verified
if a <> c then
# `AddRuleReduced' might affect the pairs. So first throw away the
# already used pairs
kbrws!.pairs2check:=
kbrws!.pairs2check{[p+1..Length(kbrws!.pairs2check)]};
p:=0; # no remaining pair was looked at
AddRuleReduced(kbrws,[a,c]);
fi;
fi;
k:=k+1;
od;
return p;
end);
############################################################
#
# Function proper
#
###########################################################
BindGlobal("GKB_MakeKnuthBendixRewritingSystemConfluent",
function(kbrws)
local pn,lp,rl,p,i;
if IsBound(kbrws!.invmap) then
kbrws!.fellowTravel:=[];
fi;
kbrws!.flaute:=0; # how often no new fellow traveler?
# kbrws!.reduced is true than it means that the system know it is
# reduced. If it is false it might be reduced or not.
if not kbrws!.reduced then
ReduceRules(kbrws);
fi;
# we check all pairs of relations for overlaps. In most cases there will
# be no overlaps. Therefore cally an inde xp in the pairs list and reduce
# this list, only if `AddRules' gets called. This avoids creating a lot of
# garbage lists.
p:=1;
rl:=49;
pn:=Length(kbrws!.pairs2check);
lp:=Length(kbrws!.pairs2check);
while lp>=p do
i:=kbrws!.pairs2check[p];
if IsChar(i[1]) then
# We store compressed data -- expand, (and also delete old stuff)
p:=KBRWSUnpackPairsAt(kbrws,p);
fi;
p:=KBOverlaps(i[1],i[2],kbrws,p)+1;
lp:=Length(kbrws!.pairs2check);
if Length(kbrws!.tzrules)>rl
or AbsInt(lp-pn)>10000 then
Info(InfoKnuthBendix,1,Length(kbrws!.tzrules)," rules, ",
lp," pairs, ",kbrws!.flaute," no new fellow");
rl:=Length(kbrws!.tzrules)+49;
pn:=lp;
fi;
od;
kbrws!.pairs2check:=[];
end);
GAPKB_REW.MakeKnuthBendixRewritingSystemConfluent :=
GKB_MakeKnuthBendixRewritingSystemConfluent;
if IsHPCGAP then
MakeReadOnlyObj( GAPKB_REW );
fi;
#############################################################################
##
#M MakeConfluent (<KB RWS>)
##
InstallMethod(MakeConfluent,
"for Knuth Bendix Rewriting System",
true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep and IsMutable
and IsBuiltFromSemigroup],0,
function(kbrws)
local rws;
MakeKnuthBendixRewritingSystemConfluent(kbrws);
# if the semigroup of the kbrws does not have a
# ReducedConfluentRws build one from kbrws and then store it in
# the semigroup
if not HasReducedConfluentRewritingSystem(
SemigroupOfRewritingSystem(kbrws)) then
rws := ReducedConfluentRwsFromKbrwsNC(kbrws);
SetReducedConfluentRewritingSystem(SemigroupOfRewritingSystem(kbrws),
rws);
fi;
end);
InstallMethod(MakeConfluent,
"for Knuth Bendix Rewriting System",
true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep and IsMutable
and IsBuiltFromMonoid],0,
function(kbrws)
local rws;
MakeKnuthBendixRewritingSystemConfluent(kbrws);
# if the monoid of the kbrws does not have a
# ReducedConfluentRws build one from kbrws and then store it in
# the monoid
if not HasReducedConfluentRewritingSystem(
MonoidOfRewritingSystem(kbrws)) then
rws := ReducedConfluentRwsFromKbrwsNC(kbrws);
SetReducedConfluentRewritingSystem(MonoidOfRewritingSystem(kbrws),
rws);
fi;
end);
#############################################################################
##
#P IsReduced( <rws> )
##
## True iff the rws is reduced
## A rws is reduced if for each (u,v) in rws both u and v are
## irreducible with respect to rws-{(u,v)}
##
InstallMethod(IsReduced,
"for a Knuth Bendix rewriting system", true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep and IsMutable], 0,
function(kbrws)
local i, copy_of_kbrws, u, tzr;
# if the rws already knows it is reduced return true
if kbrws!.reduced then return true; fi;
tzr := TzRules(kbrws);
for i in [1..Length(tzr)] do
u := tzr[i];
copy_of_kbrws := ShallowCopy(kbrws);
copy_of_kbrws!.tzrules := [];
Append(copy_of_kbrws!.tzrules,kbrws!.tzrules{[1..i-1]});
Append(copy_of_kbrws!.tzrules,kbrws!.tzrules
{[i+1..Length(kbrws!.tzrules)]});
if ReduceLetterRepWordsRewSys(copy_of_kbrws!.tzrules,u[1])<>u[1] or
ReduceLetterRepWordsRewSys(copy_of_kbrws!.tzrules,u[2])<>u[2] then
return false;
fi;
od;
return true;
end);
#############################################################################
##
#M KnuthBendixRewritingSystem(<fam>)
#M KnuthBendixRewritingSystem(<fam>,<wordord>)
#M KnuthBendixRewritingSystem(<m>)
#M KnuthBendixRewritingSystem(<m>,<wordord>)
#M KnuthBendixRewritingSystem(<s>)
#M KnuthBendixRewritingSystem(<s>,<wordord>)
##
## creates the Knuth Bendix rewriting system for a family of
## word of an fp monoid or semigroup
## using a supplied reduction ordering.
##
## We also allow using a function giving the ordering
## to assure compatibility with gap4.2
## In that case the function <lteq> should be the less than or equal
## function of a reduction ordering (no checking is performed)
##
InstallMethod(KnuthBendixRewritingSystem,
"for a family of words of an fp semigroup and on ordering on that family", true,
[IsElementOfFpSemigroupFamily, IsOrdering], 0,
function(fam,wordord)
local freefam,kbrws;
freefam := ElementsFamily(FamilyObj(fam!.freeSemigroup));
# the ordering has to be an ordering on the family freefam
if not freefam=FamilyForOrdering(wordord) then
Error("family <fam> and ordering <wordord> are not compatible");
fi;
kbrws := CreateKnuthBendixRewritingSystem(fam,wordord);
return kbrws;
end);
InstallMethod(KnuthBendixRewritingSystem,
"for a family of words of an fp monoid and on ordering on that family", true,
[IsElementOfFpMonoidFamily, IsOrdering], 0,
function(fam,wordord)
local freefam,kbrws;
freefam := ElementsFamily(FamilyObj(fam!.freeMonoid));
# the ordering has to be an ordering on the family fam
if not freefam=FamilyForOrdering(wordord) then
Error("family <fam> and ordering <wordord> are not compatible");
fi;
kbrws := CreateKnuthBendixRewritingSystem(fam,wordord);
return kbrws;
end);
InstallOtherMethod(KnuthBendixRewritingSystem,
"for an fp semigroup and an order on the family of words of the underlying free semigroup", true,
[IsFpSemigroup, IsOrdering], 0,
function(s,wordord)
local fam;
fam := ElementsFamily(FamilyObj(s));
return KnuthBendixRewritingSystem(fam,wordord);
end);
InstallOtherMethod(KnuthBendixRewritingSystem,
"for an fp monoid and an order on the family of words of the underlying free monoid", true,
[IsFpMonoid, IsOrdering], 0,
function(m,wordord)
local fam;
fam := ElementsFamily(FamilyObj(m));
return KnuthBendixRewritingSystem(fam,wordord);
end);
InstallOtherMethod(KnuthBendixRewritingSystem,
"for an fp semigroup and a function", true,
[IsFpSemigroup, IsFunction], 0,
function(s,lt)
local wordord,fam;
wordord := OrderingByLessThanOrEqualFunctionNC(ElementsFamily
(FamilyObj(FreeSemigroupOfFpSemigroup(s))),lt,[IsReductionOrdering]);
fam := ElementsFamily(FamilyObj(s));
return KnuthBendixRewritingSystem(fam,wordord);
end);
InstallOtherMethod(KnuthBendixRewritingSystem,
"for an fp monoid and a function", true,
[IsFpMonoid, IsFunction], 0,
function(m,lt)
local wordord,fam;
wordord := OrderingByLessThanOrEqualFunctionNC(ElementsFamily
(FamilyObj(FreeMonoidOfFpMonoid(m))),lt,[IsReductionOrdering]);
fam := ElementsFamily(FamilyObj(m));
return KnuthBendixRewritingSystem(fam,wordord);
end);
#############################################################################
##
#M KnuthBendixRewritingSystem(<m>)
##
## Create the a KB rewriting system for the fp monoid <m> using the
## shortlex order.
##
InstallOtherMethod(KnuthBendixRewritingSystem,
"for an fp monoid", true,
[IsFpMonoid], 0,
function(m)
return KnuthBendixRewritingSystem(m,
ShortLexOrdering(ElementsFamily(FamilyObj(
FreeMonoidOfFpMonoid(m)))));
end);
InstallOtherMethod(KnuthBendixRewritingSystem,
"for an fp semigroup", true,
[IsFpSemigroup], 0,
function(s)
return KnuthBendixRewritingSystem(s,
ShortLexOrdering(ElementsFamily(FamilyObj(
FreeSemigroupOfFpSemigroup(s)))));
end);
#############################################################################
##
#M MonoidOfRewritingSystem(<KB RWS>)
##
## for a Knuth Bendix Rewriting System
## returns the monoid of the rewriting system
##
InstallMethod(MonoidOfRewritingSystem,
"for a Knuth Bendix rewriting system", true,
[IsRewritingSystem and IsBuiltFromMonoid], 0,
function(kbrws)
local fam;
fam := FamilyForRewritingSystem(kbrws);
return CollectionsFamily(fam)!.wholeMonoid;
end);
#############################################################################
##
#M SemigroupOfRewritingSystem(<KB RWS>)
##
## for a Knuth Bendix Rewriting System
## returns the semigroup of the rewriting system
##
InstallMethod(SemigroupOfRewritingSystem,
"for a Knuth Bendix rewriting system", true,
[IsRewritingSystem and IsBuiltFromSemigroup], 0,
function(kbrws)
local fam;
fam := FamilyForRewritingSystem(kbrws);
return CollectionsFamily(fam)!.wholeSemigroup;
end);
#############################################################################
##
#M Rules(<KB RWS>)
##
## for a Knuth Bendix Rewriting System
## returns the set of rules of the rewriting system
##
InstallMethod(Rules,
"for a Knuth Bendix rewriting system", true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep], 0,
function(kbrws)
local fam;
fam:=kbrws!.freefam;
return List(kbrws!.tzrules,
i->[AssocWordByLetterRep(fam,i[1]),AssocWordByLetterRep(fam,i[2])]);
end);
#############################################################################
##
#M TzRules(<KB RWS>)
##
## for a Knuth Bendix Rewriting System
## returns the set of rules of the rewriting system in compact form
##
InstallMethod(TzRules,"for a Knuth Bendix rewriting system", true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep], 0,
function(kbrws)
return List(kbrws!.tzrules,i->[ShallowCopy(i[1]),ShallowCopy(i[2])]);
end);
#############################################################################
##
#A OrderingOfRewritingSystem(<rws>)
##
## for a rewriting system rws
## returns the order used by the rewriting system
##
InstallMethod(OrderingOfRewritingSystem,
"for a Knuth Bendix rewriting system", true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep], 0,
function(kbrws)
return kbrws!.ordering;
end);
#############################################################################
##
#A FamilyForRewritingSystem(<rws>)
##
## for a rewriting system rws
##
InstallMethod(FamilyForRewritingSystem,
"for a Knuth Bendix rewriting system", true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep], 0,
function(kbrws)
return kbrws!.family;
end);
############################################################################
##
#A ViewObj(<KB RWS>)
##
##
InstallMethod(ViewObj, "for a Knuth Bendix rewriting system", true,
[IsKnuthBendixRewritingSystem and IsBuiltFromMonoid], 0,
function(kbrws)
Print("Knuth Bendix Rewriting System for ");
Print(MonoidOfRewritingSystem(kbrws));
Print(" with rules \n");
Print(Rules(kbrws));
end);
InstallMethod(ViewObj, "for a Knuth Bendix rewriting system", true,
[IsKnuthBendixRewritingSystem and IsBuiltFromSemigroup], 0,
function(kbrws)
Print("Knuth Bendix Rewriting System for ");
Print(SemigroupOfRewritingSystem(kbrws));
Print(" with rules \n");
Print(Rules(kbrws));
end);
###############################################################################
##
#M ShallowCopy
##
InstallMethod( ShallowCopy,
"for a Knuth Bendix rewriting system",
true,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep], 0,
function(kbrws)
local new;
new:=Objectify( Subtype( TypeObj(kbrws), IsMutable ),
rec(
generators:=StructuralCopy(kbrws!.generators),
family := kbrws!.family,
reduced := false,
tzrules:= StructuralCopy(kbrws!.tzrules),
pairs2check:= [],
ordering :=kbrws!.ordering,
freefam := kbrws!.freefam,
tzordering := kbrws!.tzordering));
if IsBound(kbrws!.kbdag) then
new!.kbdag:=StructuralCopy(kbrws!.kbdag);
fi;
return new;
end);
###############################################################################
##
#M \=
##
InstallMethod( \=,
"for two Knuth-Bendix rewriting systems",
IsIdenticalObj,
[IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep,
IsKnuthBendixRewritingSystem and IsKnuthBendixRewritingSystemRep],0,
function(rws1,rws2)
return
rws1!.family=rws2!.family
and
IsSubset(rws1!.tzrules,rws2!.tzrules)
and
IsSubset(rws2!.tzrules,rws1!.tzrules)
and
rws1!.ordering=rws2!.ordering;
end);
[ Dauer der Verarbeitung: 0.44 Sekunden
(vorverarbeitet)
]
|