Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  tcsemi.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Götz Pfeiffer.
##
##  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
##
##  Installed in GAP4 by Andrew Solomon for Semigroups instead of Monoids.
##
##  This file contains implementations for Todd-Coxeter procedure for
##  fp semigroups. This uses the code written by Götz Pfeiffer
##  based on the thesis of T. Walker.
##


#############################################################################
##
#D  DeclareInfoClass("SemigroupToddCoxeterInfo");
##
##

DeclareInfoClass("SemigroupToddCoxeterInfo");

#############################################################################
##
#A  CosetTableOfFpSemigroup( cong )
##
##  A  monoid presentation is  essentially a list  of  pairs of words over an
##  alphabet.  In GAP this can be represented by a record |M| with components
##  |generators| (a list  of different |AbstractGenerator|s) for the alphabet
##  and a  component |relations| which  is a list of pairs  of words in these
##  generators meaning |r[1] =  r[2]| for each  pair  |r|.  For  example, the
##  commands
##
##      gap> a:= AbstractGenerator("a");;  b:= AbstractGenerator("b");;
##      gap> monoid:= rec( generators:= [a, b],
##      >   relations:= [[a^3, a], [b^7, b], [a*b^3*a*b^2, b^2*a]] );;
##
##  will represent the monoid with presentation $<a, b | a^3  = a, b^7 = b, a
##  b^3  a b^2 =  b^2 a>$.  The  function |CosetTableFpMonoid| enumerates the
##  elements   of a fp  monoid  if called with the  empty  list as its second
##  argument.
##
##      gap> CosetTableFpMonoid(monoid, []);;
##      #I  1005 cosets, 668 active, 337 killed.
##      #I  2010 cosets, 1223 active, 787 killed.
##      #I  2647 cosets defined, maximum 1240, 273 survive.
##
##  The enumerator  requires  an additional list  |cong| of   pairs of words,
##  which generate  a right congruence.   The classes  of this congruence are
##  called *cosets* in this context.
##
##      gap> CosetTableFpMonoid(monoid, [[a^2, a], [b^2, b]]);;
##      #I  355 cosets defined, maximum 196, 37 survive.
##
##  In  order to be able  to recycle cosets  which  have been identified with
##  other cosets  we organize them  in two lists:  the  active list of active
##  cosets and the free list of free cosets.
##
##  The *active list* is a doubly linked list.
##
##            1                 d               last          next
##            |                 |                 |             |
##            V                 V                 V             V
##          |---|---> ... --->|---|---> ... --->|---|-------->|---|---> ...
##          | 1 |             |   |             |   |         |   |
##    0 <---|---|<--- ... <---|---|<--- ... <---|---|         |---|
##
##  The   forward   references --->   are  stored  in  |forwd|,  the backward
##  references  <--- are stored in  |bckwd|.   Three pointers point into this
##  list, 1 to the initial  coset, (this  needn't  be done explicitly  since
##  coset 1 is always stored at  address 1 in the table),  |d| to the current
##  coset which is presently traced  through the relations, and |last| points
##  to the end of the list.   The cosets between  |d| and |last| are still to
##  be traced through the relations.  The last coset points to the free list.
##
##  The *free list* is a simply linked list.
##
##            last          next
##              |             |
##              V             V
##    ... --->|---|-------->|---|--->|---|---> ... --->|---|---> 0
##            |   |         |   |    |   |             |   |
##    ... <---|---|         |---|    |---|             |---|
##
##  Again, the references --->  are  stored in  |forwd|.  The pointer  |next|
##  points to its beginning, the last coset points at 0.  The free list might
##  be (and initially is) empty.  In that case |next| points at 0, too.
##
##  The images   of the cosets under the   generators are compiled in  a list
##  |table| such that  |table[i][s]| contains  the image  of  coset |s| under
##  generator |i|.   The preimages are  stored in a similar  way  in the list
##  |occur|.  Here |occur[i][s]|  contains the set  of  all cosets  which are
##  mapped to |s| under generator |i|.  There the empty set is represented by
##  0. The  list |occur| is needed  for the sole   purpose of identifying the
##  places in |table| where a coset |t|  occurs if this  needs to be replaced
##  by a coset |s|.
##
InstallMethod(CosetTableOfFpSemigroup,
"for a right congruence on an fp semigroup",
true,
[IsRightMagmaCongruence], 0,
function(cong)

   local i, r, d, la,             # loop variables,
         M,                     # the semigroup,
         gens, rels,            # generators |[1..n]| and relations,
         semirels,              # the rels of the semigroup plus x=x, x\in gens
         table, inver, occur,   # the coset table and its inverse,
         forwd, bckwd,          # for- and backward references,
         active,                # number of active cosets,
         next, lust,            # the next and the last address,
         lanext,                # the next lookahead point,
         oldkilled,
         eqnTrace,              # the trace/push,
         laTrace,               # Lookahead trace
         ideNtify,              # identification, please,
         newCoset,              # coset definition,
         repLaced,              # a translation function,
         word_to_list,          # aliased to repLaced
         defind, i1000,         # statistics and info,
         pos;                   # positions.

##  When  a new  coset is  defined the  following  steps are  taken.  Coset N
##  pointed at by |next|  is concatenated (doubly linked)  to coset L pointed
##  at by |last|.  Both  |last| and |next| move  one step forward so that now
##  |last| points to  coset N.

   # how to define a new coset: the image of t under a.
   newCoset:= function(t, a)

      # increase number of cosets.
      active:= active + 1;  defind:= defind + 1;  i1000:= i1000 + 1;

      # if the free list is empty create one of length 1 and link.
      if next = 0 then
         next:= active;  forwd[lust]:= next;  forwd[next]:= 0;
      fi;

      # make new coset active.
      bckwd[next]:= lust;  lust:= next;  next:= forwd[lust];
      for i in gens do
         table[i][lust]:= 0;
         inver[i][lust]:= 0;  #C inver[i][lust]:= [];
      od;
      table[a][t]:= lust;
      inver[a][lust]:= t;  occur[a][t]:= 0;  #C inver[a][lust]:= [t];

      # return new coset.
      pos[lust]:= defind;
#Error("Break Code\n");
      return lust;

   end;


   # how to trace the coset |d| through an equation |w|.
   eqnTrace:= function(w)
      local s, t, a, b, u, v, x;

      # tracing |d| through left of |w| gives |s|.
      s:= d;
      for a in [1..Length(w[1]) - 1] do
         if 0 < table[w[1][a]][s] then
            s:= table[w[1][a]][s];
         else
            s:= newCoset(s, w[1][a]);
         fi;
      od;

      # tracing |d| through right of |w| gives |t|.
      t:= d;
      for a in [1..Length(w[2]) - 1] do
         if 0 < table[w[2][a]][t] then
            t:= table[w[2][a]][t];
         else
            t:= newCoset(t, w[2][a]);
         fi;
      od;

      # print out statistics.
      if 999 < i1000  then
         i1000:= 0;
         Info(SemigroupToddCoxeterInfo, 2, "#I  ", defind, " cosets, ",
              active, " active, ", defind - active, " killed.\n");
      fi;

      a:= Last(w[1]);
      b:= Last(w[2]);
      u:= table[a][s];
      v:= table[b][t];

      if u = 0 and v = 0 then
        x:= newCoset(s, a);
        table[b][t]:= x;
        if a = b then
          occur[a][s]:= t;
          occur[a][t]:= 0;
        else
          inver[b][x]:= t;
          occur[b][t]:= 0;
        fi;
      fi;

      if u = 0 and v <> 0 then
        table[a][s]:= v;
        occur[a][s]:= inver[a][v];
        inver[a][v]:= s;
      fi;

      if u <> 0 and v = 0 then
        table[b][t]:= u;
        occur[b][t]:= inver[b][u];
        inver[b][u]:= t;
      fi;

      # if |s| differs from |t| start handling coincidences.
      if u <> 0 and v <> 0 then

        if pos[u] < pos[v] then
           ideNtify([v, u]);
        elif pos[v] < pos[u] then
           ideNtify([u, v]);
        fi;
      fi;

   end;

   laTrace:= function(w)
      local s, t, a, b, u, v;

      # tracing |la| through left of |w| gives |s|.
      s:= la;
      for a in [1..Length(w[1]) - 1] do
         if 0 < table[w[1][a]][s] then
            s:= table[w[1][a]][s];
         else
            return;
         fi;
      od;

      # tracing |la| through right of |w| gives |t|.
      t:= la;
      for a in [1..Length(w[2]) - 1] do
         if 0 < table[w[2][a]][t] then
            t:= table[w[2][a]][t];
         else
            return;
         fi;
      od;

      # print out statistics.
      if 999 < i1000  then
         i1000:= 0;
         Info(SemigroupToddCoxeterInfo, 2, "#I  ", defind, " cosets, ",
              active, " active, ", defind - active, " killed.\n");
      fi;

      a:= Last(w[1]);
      b:= Last(w[2]);
      u:= table[a][s];
      v:= table[b][t];

      if u = 0 and v = 0 then
        return;
      fi;

      if u = 0 and v <> 0 then
        table[a][s]:= v;
        occur[a][s]:= inver[a][v];
        inver[a][v]:= s;
      fi;

      if u <> 0 and v = 0 then
        table[b][t]:= u;
        occur[b][t]:= inver[b][u];
        inver[b][u]:= t;
      fi;

      # if |v| differs from |u| start handling coincidences.
      if u <> 0 and v <> 0 then

        if pos[u] < pos[v] then
           ideNtify([v, u]);
        elif pos[v] < pos[u] then
           ideNtify([u, v]);
        fi;
      fi;

   end;

##  When two cosets |s| and |t| are to be identified we work on an additional
##  *stack* of cosets which holds the list of yet to identify pairs of cosets
##  as consecutive entries.   After replacing |t|  by |s| in the coset table,
##  the list of  preimages and, if necessary, the  current coset, the rows of
##  |t| and |s| in  the coset table  are compared.  This produces new entries
##  in the  table and  new  coincidences  which  are written on   the  stack.
##  Afterwards the row of |t| can be  discarded in the  table.  The coset |t|
##  is taken out  of the active list  and linked to  the free  list.  It then
##  carries a (negative) backward reference to |s| in order to direct pending
##  coincidences to their proper place in the active list.

   # how to identify two cosets.
   ideNtify:= function(stack)
      local i, u, v, s, t, l;

      # initialize stack length.
      l:= 2;

      # loop over the stack.
      repeat

         # get current addresses of the top pair.
         s:= stack[l];  t:= stack[l-1];  l:= l-2;
         while bckwd[s] < 0 do
            s:= -bckwd[s];
         od;
         while bckwd[t] < 0 do
            t:= -bckwd[t];
         od;

         # if they still differ do the identification.
         if s <> t then

            # update counters and pointers.
            active:= active - 1;
            if t = d then
               d:= bckwd[d];  # replace current coset.
            fi;
            if t = la then
               la:= bckwd[la];
            fi;
            if t = lust then
               lust:= bckwd[lust];  # delete top of queue.
            else
               bckwd[forwd[t]]:= bckwd[t];  # drop |t| from queue.
               forwd[bckwd[t]]:= forwd[t];
               forwd[t]:= next;  # link |t| to free list.
               forwd[lust]:= t;
            fi;
            next:= t;
            bckwd[t]:= -s;  # leave forwarding address.

            # loop over the generators.
            for i in gens do

               # replace |t| by |s| in coset table ...
               #C for v in inver[i][t] do
               #C    table[i][v]:= s;
               #C    AddSet(inver[i][s], v);
               #C od;
#Error("Break Code");
               v:= inver[i][t];
               while 0 < v do
                  u:= occur[i][v];
                  table[i][v]:= s;
                  occur[i][v]:= inver[i][s];  inver[i][s]:= v;
                  v:= u;
               od;

               # ... and delete |t| from its inverse.
               v:= table[i][t];
               if 0 < v then

                  #C RemoveSet(inver[i][v], t);
                  u:= inver[i][v];
                  if u = t then
                     inver[i][v]:= occur[i][t];
                  else
                     while occur[i][u] <> t do
                        u:= occur[i][u];
                     od;
                     occur[i][u]:= occur[i][t];
                  fi;

                  # draw conclusions.
                  u:= table[i][s];
                  if u = 0 then
                     table[i][s]:= v;

                     #C AddSet(inver[i][v], s);
                     occur[i][s]:= inver[i][v];  inver[i][v]:= s;

                  # stack mismatches such that big is replaced by small.
                  elif pos[u] < pos[v] then
                     l:= l+2;  stack[l-1]:= v;  stack[l]:= u;
                  elif pos[v] < pos[u] then
                     l:= l+2;  stack[l-1]:= u;  stack[l]:= v;
                  fi;

               fi;
            od;

         fi;

      until l = 0;

   end;

   # how to switch to words over |[1..n]|.
   #repLaced:= w-> List(List(w), x-> Position(M.generators, x));
        #transforms a word into a list of integers
        word_to_list:=function(u)
          local i,k,n,l;

          n:=Length(ExtRepOfObj(u));
          l:=[];
          for i in [1..n/2] do
            for k in [1..ExtRepOfObj(u)[2*i]] do
              Add(l,ExtRepOfObj(u)[2*i-1]);
            od;
          od;
          return l;
        end;

   repLaced:= w-> word_to_list(w);

##  Initially there is  only one coset.  The  coset table and its inverse are
##  [[0], [0], ..., [0]] and the linked lists look as follows.
##
##           d last next
##           | |      |
##           V V      V
##          |---|---> 0
##          | 1 |
##    0 <---|---|
##
   # initialize.
         # get the semigroup on which <cong> is a congruence.
         M := Source(cong);
         # Make sure <M> is an fp semigroup
         if not IsFpSemigroup(M) then
             Error("right congruence of an fp-semigroup expected");
         fi;
   gens:= [1..Length(GeneratorsOfSemigroup(M))];
   # we add trivial relations to the semigroup relations to
   # make sure that if the semigroup has a free generator
   # then it does not stop
   semirels := Concatenation(RelationsOfFpSemigroup(M),
                             List(gens,i-> [FreeGeneratorsOfFpSemigroup(M)[i],
                             FreeGeneratorsOfFpSemigroup(M)[i]]));
   rels:= List(semirels, x-> List(x, repLaced));
   cong:= List(GeneratingPairsOfRightMagmaCongruence(cong),
                x-> List(x, y->repLaced(UnderlyingElement(y))));

   table:= [];  inver:= [];  occur:= [];
   for i in gens do
      table[i]:= [0];
      inver[i]:= [0];  occur[i]:= [];  #C inver[i]:= [[]];
   od;

   active:= 1;  defind:= 1;  i1000:= 1;
   lanext:= Int(SemigroupTCInitialTableSize/(3*Length(gens)));
   forwd:= [0];  bckwd:= [0];  pos:= [1];
   lust:= 1;  next:= 0;  la:= 0;
   d:= 1;

   # first close the congruence tables.
   for r in cong do
      eqnTrace(r);
   od;

   # loop over pending def'ns.
   repeat

      # loop over rel'ns.
      for r in rels do
         eqnTrace(r);
      od;

      if active > lanext then
                Info(SemigroupToddCoxeterInfo, 1, "Entering Lookahead");
                oldkilled:= defind - active;
        la:= d;
        repeat
          for r in rels do
            laTrace(r);
          od;
          la:= forwd[la];
        until la = next;
        Info(SemigroupToddCoxeterInfo, 1, "Lookahead done, ",
               (defind-active) - oldkilled," definitions saved");
         Info(SemigroupToddCoxeterInfo, 1, "#I  ", defind, " cosets, ",
                                                active, " active, ", defind - active, " killed.");
        if active > lanext then
          lanext:= lanext * 2;
        fi;
        la:= 0;
      fi;

      # proceed to next coset on active list.
      d:= forwd[d];

   until d = next;

   # print statistics.
   Info(SemigroupToddCoxeterInfo, 1, "#I  ", defind,
                " cosets defined, maximum ", Length(forwd), ", ", active, " survive.\n");

   # shrink coset table: trace coset 1 through |forwd|.
   occur:= 0;  pos:= [];  inver:= [];  i:= 0;  d:= 1;
   repeat
      i:= i+1;  pos[i]:= d;  inver[d]:= i;  d:= forwd[d];
   until d = next;

   # return final coset table.
   for i in gens do
      table[i]:= inver{table[i]{pos}};
   od;
   return table;

end);


############################################################################
##
#O  HomomorphismTransformationSemigroup(<S>,<r>)
#A  IsomorphismTransformationSemigroup(<S>)
##
##  As above the first case should become an attribute of <r>?
##

InstallMethod(IsomorphismTransformationSemigroup,
"<fp-semigroup>", true,
[IsFpSemigroup], 0,
function(S)
        return HomomorphismTransformationSemigroup(S,
                RightMagmaCongruenceByGeneratingPairs(S,[]));
end);


InstallMethod( HomomorphismTransformationSemigroup,
    "for an f.p. semigroup, and a right congruence",
    true,
    [ IsFpSemigroup, IsRightMagmaCongruence ],
    0,
function(S,r)
        local
        cotab,          # the coset table of the semigroup
        isofun,         # the function describing the isomorphism
        ts;             # the transformation semigroup

        if not S = Source(r) then
            TryNextMethod();
        fi;

        # make a transformation monoid on the congruence classes.
        cotab := CosetTableOfFpSemigroup(r);
        ts := Semigroup(List(cotab, Transformation));

        ########################################################
        # isofun:
        # The function which computes the isomorphism - take
        # the ith  generator of the fp semigroup to the
        # transformation whose image list is the ith row of the
        # multiplication table
        #
        isofun := function(x)
            local
                i,      # counter
                prod,   # accumulates the value of the image
                gensts, # generators of the transformation semigroup
                extr;   # ext rep of x

            extr := ExtRepOfObj(UnderlyingElement(x));
            gensts := GeneratorsOfSemigroup(ts);

            prod := One(Transformation(cotab[1]));
            for i in [1 .. Length(extr)/2] do
                prod  := prod * gensts[extr[2*i-1]]^extr[2*i];
            od;
            return prod;
        end;
        ########################################################
        # isofun end

        return MagmaHomomorphismByFunctionNC(S, ts, isofun);
end);

[ Dauer der Verarbeitung: 0.42 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge