Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.9.2025 mit Größe 37 kB image not shown  

Quelle  kbsemi.gi   Sprache: unbekannt

 
#############################################################################
##
##  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)  ]