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


Quelle  cp.gi   Sprache: unbekannt

 
#############################################################################
##
#W cp.gi                                                       Thorsten Groth
##
#Y Copyright (C) 2014, Thorsten Groth
##
#############################################################################
##
##  This file implements the conjugacy problem for branch groups
##
#############################################################################

#---------------------------------------------------------------
#------              Dep-Cartesian          --------------------
#--  Calculates a cartesian product of ordered lists with    ---
#-- respect to dependencies which entries belong together    ---
#-- Example: L=[[A,B,X],[C,D],[c,d]], dep=[[1],[2,3]] results --
#--   in [[A,C,c],[A,D,d],[B,C,c],[B,D,d],[X,C,c],[X,D,d]    ---
#--     The Lists, which are joined by the dependencies      ---
#--            have to be of the same length                --- 
#---------------------------------------------------------------
BindGlobal("DEP_CARTESIAN@", function(L,dep)
 local res_list, temp_cart, container, al, d, i ,j,a;
 res_list := [];
 temp_cart := [];
 for d in dep do
  container := [];
  for j in [1..Size(L[d[1]])] do
   al := [];
   for i in [1..Size(d)] do
    if IsBound(L[d[i]][j]) then
     al[i]:=L[d[i]][j];
    fi;
   od;
   if al <> [] then container[j]:=al; fi;
  od; 
  Add(temp_cart,container);
 od; 
 temp_cart := Cartesian(temp_cart);
 for i in temp_cart do
  container := [];
  for d in i do
   Append(container,d);
  od;
  Add(res_list,container);
 od;
 return res_list;
end);

#--------------------------------------------------------------
#------             LEVEL_PERM_CONJ                     -------
#------  Takes two FRElements and computes a list of    -------
#------  conjugators of the action on the first level.  -------
#--------------------------------------------------------------
BindGlobal("LEVEL_PERM_CONJ@", function(arg)
 local G, pi_x, pi_y, c;
 if Length(arg) < 3 then
  G:=SymmetricGroup(AlphabetOfFRObject(arg[1]));
 else 
  if not IsFRObject(arg[1]) or not IsFRObject(arg[2]) or not IsPermGroup(arg[3]) then
   Error("Usage: FRelm, FRelm, [PermGroup]");
  fi;
  G:=arg[3];
 fi;
 pi_x := PermList(DecompositionOfFRElement(arg[1])[2]);
  pi_y := PermList(DecompositionOfFRElement(arg[2])[2]);
  c := RepresentativeAction(G,pi_x,pi_y);
  if c= fail then
   return [];
  fi;
  return c*List(Centralizer(G,pi_y));
end);
##################################################################
#````````````````````````````````````````````````````````````````#
#```````````````````    OrbitSignalizer   ```````````````````````#
#````````````````                            ````````````````````#
#````````````````    Guaranteed to stop on    ```````````````````#
#```````````````` BoundedFRElements as input ````````````````````#
#``````  Computes {a^m@v|v∊X*} with m = |Orb_a(v)|   ````````````#
#````````````````````````````````````````````````````````````````#
##################################################################
InstallMethod(OrbitSignalizer,
 "Returns the finite Orbit Signalizer",
 [IsFRElement],
function(a)
 local OS_list,i,OS_unvisited,OS_new,elm,x,new,suc;
 suc := function(state,x)
  return  State(state^Size(ForwardOrbit(state,[x])),[x]);
 end;
 OS_list := [];
 OS_unvisited := [a];
 while Length(OS_unvisited) > 0 do
  OS_new := [];
  for elm in OS_unvisited do
   for x in AlphabetOfFRObject(a) do
    new := suc(elm,x);
    if (not new in OS_list) and (not new in OS_unvisited) and (not new in OS_new) then
     Add(OS_new,new);
    fi;
   od;
   
  od; 
  Append(OS_list,OS_unvisited);
  OS_unvisited := OS_new;
 od;
 return OS_list;
end
);
##################################################################
#````````````````````````````````````````````````````````````````#
#`````````````````````                  `````````````````````````#
#`````````````````````  ConjugatorGraph `````````````````````````#
#`````````````````````     DrawGraph    `````````````````````````#
#`````````````````````                  `````````````````````````#
#````````````````````````````````````````````````````````````````#
##################################################################
BindGlobal("CONJUGATOR_GRAPH@", function(a,b)
 local Alph, Vertices, Edges, c, d, p, v_id, e_id, v, orbits, orb_repr, i, new_con_pair, new_v, w, change, found, e, all_found;
 
 Alph := AlphabetOfFRObject(a);
 Vertices := [];
 Edges := [];
 #--------------------- Save some work, in easy cases--------
 if Size(LEVEL_PERM_CONJ@(a,b))=0 then
  return [[],[]];
 fi;
 #--------------------- Generate the Vertex list ------------
 v_id := 1;
 for c in OrbitSignalizer(a) do
  for d in OrbitSignalizer(b) do
   for p in LEVEL_PERM_CONJ@(c,d) do
    Add(Vertices,rec( id:= v_id,
             conj_pair := [c,d],
             action := p));
    v_id := v_id+1;
   od;
  od;
 od;
 #Print("Vertexlist generated\n");
 
 #--------------------- Find the Edges  -------------------
 e_id := 1;
 for v in Vertices do
  c := v.conj_pair[1];
  d := v.conj_pair[2];
  orbits := Orbits(Group(c),Alph);
  orb_repr := List(orbits,Minimum);
  for i in [1..Length(orbits)] do
   new_con_pair := [State(c^Length(orbits[i]),orb_repr[i]),State(d^Length(orbits[i]),orb_repr[i]^v.action)];
   for p in LEVEL_PERM_CONJ@(new_con_pair[1],new_con_pair[2]) do
    new_v := 0;
    for w in Vertices do
     if w.conj_pair = new_con_pair and w.action = p then;
      new_v := w;
      break;
     fi;
    od;
    if new_v <> 0 then
     #Print("Add Edge from ",v.id," to ",new_v.id," along ",orb_repr[i],"\n");
     Add(Edges,rec( from:=v.id,
             to := new_v.id,
             read := orb_repr[i],
             write := orb_repr[i]^v.action,
             id := e_id));
     e_id := e_id +1; 
    else #This case should never happen...
     Error("Error the element is not in the vertex set!\n");
    fi;
   od;
  od;
 od;
 #Print(Size(Edges)," Edges generated\n");
 
 #--------------------- Delete dead Vertices  -------------------
 change:=true;
 while change do
  change := false;
  for v in Vertices do
   orbits := Orbits(Group(v.conj_pair[1]),Alph);
   orb_repr := List(orbits,Minimum);
   found := [];
   for e in Edges do
    if e.from = v.id then
     Add(found,e.read);
    fi;
   od;
   #Are all outgoing edges there?
   all_found := true;
   for i in orb_repr do
    if not i in found then
     all_found := false;
     #Print("At Vertex ",v.id," no Edge ",i," was found. So remove it.\n");
     break;
    fi;
   od;
   if not all_found then
    Unbind(Vertices[v.id]);
    #Delete all Edges from or to the removed vertex
    for e in Edges do
     if e.from = v.id or e.to = v.id then
      Unbind(Edges[e.id]);
     fi;
    od;
    change:=true;
   fi;
  od;
 od;
 #Print("Dead Vertices removed\n");
 return [Vertices,Edges];
end);

BindGlobal("DRAW_GRAPH@",function(Vertices,Edges)
 local v,S,e;
 for v in Vertices do
  Print("ID: ",v.id," Name: (",v.conj_pair[1]![2],",",v.conj_pair[2]![2],")\n");
 od;
 #Draw Conjugacy Graph
 S := "digraph finite_state_machine {\n";
 for e in Edges do
  #Print(Vertices[e.from].conj_pair[1]![2]);
  Append(S,"\"");
  Append(S,String(Vertices[e.from].id));
  Append(S,": (");
  Append(S,String(Vertices[e.from].conj_pair[1]![2]));
  Append(S,",");
  Append(S,String(Vertices[e.from].conj_pair[2]![2]));
  Append(S,")");
  Append(S,String(Vertices[e.from].action));
  Append(S,"\"");
  Append(S," -> ");
  Append(S,"\"");
  Append(S,String(Vertices[e.to].id));
  Append(S,": (");
  Append(S,String(Vertices[e.to].conj_pair[1]![2]));
  Append(S,",");
  Append(S,String(Vertices[e.to].conj_pair[2]![2]));
  Append(S,")");
  Append(S,String(Vertices[e.to].action));
  Append(S,"\"");
  Append(S," [label=\"");
  Append(S,String(e.read));
  Append(S,"|");
  Append(S,String(e.write));
  Append(S,"\"];\n");
 od;
 Append(S,"}");
 Print(S);
 DOT2DISPLAY@(S,"dot");
end);
##################################################################
#````````````````````````````````````````````````````````````````#
#```````````````````  MEALY_FROM_STATES@  ```````````````````````#
#````````````````                            ````````````````````#
#`````````````````  Computes a mealy machine ````````````````````#
#````````````````     with Statesset L and   ````````````````````#
#````````````````        activity act        ````````````````````#
#````````````````````````````````````````````````````````````````#
##################################################################
#Computes a mealy machine with stateset L and given activity act.
BindGlobal("MEALY_FROM_STATES@", function(L,act)
  local m,tran,out,i,j;
  #Force L to contain elements and not lists of elements.
  for i in [1..Size(L)] do
   if IsList(L[i]) then
    L[i] := Product(L[i]);
   fi;
  od;
  #Force act to be a list of output symbols.
  if IsPerm(act) then
   act := List(AlphabetOfFRObject(L[1]),x->x^act);
  fi;
  
  tran := [[]];
  out := [act];
  i := 1;
  j := 2;
  for m in L do
    Add(tran[1],i+1);
    Append(tran,List(m!.transitions,x->List(x,y->y+i)));
    Append(out,m!.output);
    i := i + Length(m!.transitions);
    j := j+1;
  od;
  return MealyElement(tran,out,1);
 end);
##################################################################
#````````````````````````````````````````````````````````````````#
#`````````````````````                  `````````````````````````#
#`````````````````````    F.S. Worker   `````````````````````````#
#`````````````````````                  `````````````````````````#
#````````````````````````````````````````````````````````````````#
##################################################################
BindGlobal("CONJUGATORS_FINITE_STATE_WRAPPER@",function(start,CG)
 local v,AS,to_visit, Alph, new_v, i, found, e, Tran, Act, c,d, orbit;
   #--------- Choose one subgraph, as automaton  ---------
   AS := [start.id]; #Contains IDs of vertices, which build the subgraph
   to_visit := [start.id]; 
   Alph := AlphabetOfFRObject(start.conj_pair[1]);
   while Length(to_visit) > 0 do 
    new_v := [];
    for i in to_visit do
     v := CG[1][i];
     found := [];
     for e in CG[2] do
      if e.from = v.id then
       if e.read in found then
        Unbind(CG[2][e.id]);
       else 
        Add(found,e.read);
        if not e.to in AS then
         Add(new_v,CG[1][e.to].id);
         Add(AS,e.to);
        fi;
       fi;
      fi;
     od;
    od;
    to_visit := new_v;
   od;
   #Form an automaton out of the subgraph
   Tran := [];
   Act := [];
   for i in AS do
    Add(Tran,[]);
    Add(Act,CG[1][i].action);
   od;
   for e in CG[2] do
    if e.from in AS and e.to in AS then
     Tran[Position(AS,e.from)][Position(Alph,e.read)] := [Position(AS,e.to)];
     c := CG[1][e.from].conj_pair[1];
     d := CG[1][e.from].conj_pair[2];
     orbit := ForwardOrbit(c,e.read);
     for i in [2..Length(orbit)] do
     #The missing edges...
      Tran[Position(AS,e.from)][Position(Alph,orbit[i])] := [State(c^(i-1),e.read)^(-1),Position(AS,e.to),State(d^(i-1),e.read^(CG[1][e.from].action))];
     od;
    fi;
   od;
   return FRElement(Tran,Act,[1]);
end);
##################################################################
#````````````````````````````````````````````````````````````````#
#`````````````````````                  `````````````````````````#
#`````````````````````  Finitary Worker `````````````````````````#
#`````````````````````                  `````````````````````````#
#````````````````````````````````````````````````````````````````#
##################################################################
BindGlobal("CONJUGATORS_FINITARY_WRAPPER@",function(v,Graph,Seen,Known_vertex_conjugator)
 local CONJUGATORS_FINITARY_REK;
 CONJUGATORS_FINITARY_REK := function(v,Graph,Seen,Known_vertex_conjugator)
  local Vertices,Edges,sons,starts,conj_cand,conjugators_found,son,x,NewSeen,a,b,e,son_conj,son_conjs,tempo_conj, htemp,tempoconj,err,Indices,diction,pos,real_conj,real_conjugators,i,j,ip,son_orbit_size,Alph,action,
  w,Circle,Conjs,con;
 
  #Print("@Vertex ",v,"\n");
  if IsBound(Known_vertex_conjugator[v]) then #Don't do the same work twice.
   return Known_vertex_conjugator[v];
  fi;
  Vertices := Graph[1];
  Edges := Graph[2];
  a := Vertices[v].conj_pair[1];
  b := Vertices[v].conj_pair[2];
  Alph := AlphabetOfFRObject(a);
  action := Vertices[v].action;
 
  if v in Seen then
   Circle:=Seen{[Position(Seen,v)..Size(Seen)]}; #are all one then.
   for w in Circle do
    if not Vertices[w].action = () then
     return [];
    fi;
    if not Vertices[w].conj_pair[1] = Vertices[w].conj_pair[2] then
     return [];
    fi;
   od;
   return [One(a)];
  fi;
 
  sons := [];
  for e in Edges do
   if e.from = v then
    Add(sons,[e.to,e.read]);
   fi;
  od;
  real_conjugators := [];
  conj_cand := EmptyPlist(Size(Alph));
  for x in Alph do
   conj_cand[x] := [];
  od;
  conjugators_found := [];
 
  for son in sons do
   NewSeen := ShallowCopy(Seen);
   Add(NewSeen,v);
   son_conjs := CONJUGATORS_FINITARY_REK(son[1],Graph,NewSeen,Known_vertex_conjugator);
   son_orbit_size := Size(Orbit(Group(a),son[2]));
   for son_conj in son_conjs do
    tempo_conj := [];
    err:=0;
    for j in [1..son_orbit_size-1] do
     htemp := (State(a^j,son[2]))^(-1) * son_conj * State(b^j,son[2]^action);
     if IsFinitaryFRElement(htemp) then
      tempo_conj[son[2]^(a^j)] := htemp;
     else
      err := 1;
      break;
     fi;
    od;
    tempo_conj[son[2]] := son_conj;
    if err = 0 then #tempo_conj is indeed a valid partial_conjugator for (a,b)
     for i in Alph do
      if IsBound(tempo_conj[i]) then
       Add(conj_cand[i],[tempo_conj[i]]);
       conjugators_found[i] := 1;
      fi;
     od;
    fi;
   od;
  od;
  #Test if we have enough partial conjugators
  if IsDenseList(conjugators_found) and Size(conjugators_found) = Size(Alph) then
   #puzzle them together! 
   Conjs := DEP_CARTESIAN@(conj_cand,Orbits(Group(a),Alph));
   for con in Conjs do
    Add(real_conjugators,FRElement([con],[action],[1]));
   od;
  fi;
  Known_vertex_conjugator[v] := real_conjugators;
  return real_conjugators;
 end;
 return CONJUGATORS_FINITARY_REK(v,Graph,Seen,Known_vertex_conjugator);
end);
##################################################################
#````````````````````````````````````````````````````````````````#
#`````````````````````                  `````````````````````````#
#`````````````````````  BoundedWorker   `````````````````````````#
#`````````````````````                  `````````````````````````#
#````````````````````````````````````````````````````````````````#
##################################################################
BindGlobal("CONJUGATORS_BOUNDED_WRAPPER@",function(v,Graph,Seen,readwrite_path,Known_vertex_conjugator)
 local CONJUGATORS_BOUNDED_REK;
 CONJUGATORS_BOUNDED_REK := function(v,Graph,Seen,readwrite_path,Known_vertex_conjugator)
  local Vertices,Edges,sons,starts,conj_cand,conjugators_found,son,x,NewSeen,a,b,e,son_conj,son_conjs,tempo_conj, htemp,tempoconj,err,Indices,diction,pos,real_conj,real_conjugators,conj_cand_aux,i,j,ip,son_orbit_size,Alph,Alph_num,action, alph,beta,Conj_elm,read,write,orb_size,Conj_Tran,Conj_act,m,read_path,write_path,action_path,New_read_path, New_write_path,New_action_path,Conj_Tran_el,Conjs,circle_length,New_Seen,X,con, check_need ;
 
  #Print("@Vertex ",v,"\n");
  if IsBound(Known_vertex_conjugator[v]) then #Don't do the same work twice.
   return Known_vertex_conjugator[v];
  fi;
  #TODO REKURSIONSABBRUCH, wenn start schon gefunden wurde!!!!
  #if IsBound(Known_vertex_conjugator[start]) then
  # if Size(Known_vertex_conjugator[start]>0) then
  #  Print("Warum denn noch weitermachen... ist doch schon alles klar...\n\n");
  # fi;
  #fi;
  Vertices := Graph[1];
  Edges := Graph[2];
  a := Vertices[v].conj_pair[1];
  b := Vertices[v].conj_pair[2];
  Alph := AlphabetOfFRObject(a);
  Alph_num := [1..Size(Alph)];
  action := Vertices[v].action;
  read_path := readwrite_path[1];
  write_path := readwrite_path[2];
  action_path := readwrite_path[3];
  if v in Seen then
   m := Size(Orbit(Group(a),read_path));

   Conj_Tran:= [];
   Conj_act := [];
   circle_length:=Size(Seen)-Position(Seen,v)+1;
   check_need := false;
   for i in [Position(Seen,v)..Size(Seen)] do
    alph := Vertices[Seen[i]].conj_pair[1];
    beta := Vertices[Seen[i]].conj_pair[2];
    read:=read_path[i];
    write:=write_path[i];
    orb_size:= Size(Orbit(Group(alph),read));
    Conj_elm :=[];
    for x in Alph_num do
     Conj_elm[x]:=[];
    od;
    if not orb_size = Size(Alph) then  #Here some extra work, search for a conjugator for the non determined states, there may be more than one.
     x:= read;
     #Get a representative for the orbits
     X:=Difference(Alph,Orbit(Group(alph),x));
     while Size(X)>0 do 
      x := Minimum(X);    
      sons := [];
      for e in Edges do
       if e.from = v and e.read = x then
        Add(sons,e.to);
       fi;
      od;
      New_Seen := Seen{[1..i]};
      son_conjs:= [];
      #Here there is already one circle, so the other states have to be finitary
      for son in sons do
        Conjs :=CONJUGATORS_FINITARY_WRAPPER@(son,Graph,New_Seen,Known_vertex_conjugator);
        Append(son_conjs,Conjs);
      od;  
      for son_conj in son_conjs do
       for j in [0..Size(Orbit(Group(alph),x))-1] do 
        Add(Conj_elm[Position(Alph,x^(alph^j))],[(State(alph^j,x))^-1*son_conj*State(beta^j,x^action_path[i])]); 
       od;
      od;
      X:=Difference(X,Orbit(Group(alph),x)); #next orbit
     od;
    fi;
    Conj_elm[Position(Alph,read)]:= [[(i mod circle_length) +1]];
    for j in [1..orb_size-1] do
     Conj_elm[Position(Alph,read^(alph^j))] := [[(State(alph^j,read))^-1,Conj_elm[Position(Alph,read)][1][1],State(beta^j,write)]];
     #This may be not bounded, so check it later.
     check_need := true;
    od;
    #Remove duplicates in
    for x in Alph_num do
     Conj_elm[x] := Set(Conj_elm[x]);
    od;
    Conj_elm := DEP_CARTESIAN@(Conj_elm,Orbits(Group(alph),Alph)); #puzzle the conjugators together
    Add(Conj_act,action_path[i]);
    Add(Conj_Tran,Conj_elm);
   od;
   Conjs := [];
   for Conj_Tran_el in Cartesian(Conj_Tran) do
    conj_cand := FRElement(Conj_Tran_el,Conj_act,[1]);
    if check_need then
     if IsBoundedFRElement(conj_cand) then
      check_need := false;
     fi;
    fi;
    if not check_need then
     if IsBound(Known_vertex_conjugator[v]) then
      Add(Known_vertex_conjugator[v],conj_cand);
     else
      Known_vertex_conjugator[v] := [conj_cand];
     fi;
     Add(Conjs,conj_cand);
    fi;
   od;
   return Conjs;

  fi;
  sons := [];
  for e in Edges do
   if e.from = v then
    Add(sons,[e.to,e.read]);
   fi;
  od;
  real_conjugators := [];
  conj_cand := EmptyPlist(Size(Alph));
  for x in Alph do
   conj_cand[x] := [];
  od;
  conjugators_found := [];
 
  for son in sons do
   NewSeen := ShallowCopy(Seen);
   Add(NewSeen,v);
   New_read_path := ShallowCopy(read_path);
   Add(New_read_path,son[2]);
   New_write_path := ShallowCopy(write_path);
   Add(New_write_path,son[2]^action);
   New_action_path := ShallowCopy(action_path);
   Add(New_action_path,action);
    
   son_conjs := CONJUGATORS_BOUNDED_REK(son[1],Graph,NewSeen,[New_read_path,New_write_path,New_action_path],Known_vertex_conjugator);
   for son_conj in son_conjs do
   son_orbit_size := Size(Orbit(Group(a),son[2]));
    for j in [0..son_orbit_size-1] do
     Add(conj_cand[son[2]^(a^j)],[(State(a^j,son[2]))^(-1) * son_conj * State(b^j,son[2]^action)]);
     conjugators_found[son[2]^(a^j)] := 1;
    od;
   od;
  od;
  #Test if we have enough partial conjugators
  if IsDenseList(conjugators_found) and Size(conjugators_found) = Size(Alph) then
   #puzzle them together! 
   Conjs := DEP_CARTESIAN@(conj_cand,Orbits(Group(a),Alph));
   for con in Conjs do
    Add(real_conjugators,FRElement([con],[action],[1]));
   od;
  fi;
  Known_vertex_conjugator[v] := real_conjugators;
  return real_conjugators;
 end;
 return CONJUGATORS_BOUNDED_REK(v,Graph,Seen,readwrite_path,Known_vertex_conjugator);
end);
##################################################################
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%%      IsConjugate        %%%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%%  RepresentativeActionOp %%%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
##################################################################
InstallMethod(IsConjugate,
 "For Aut, RAut, FAut, Poly-1, Poly0",
 #The attribute FullSCVertex charakterizes all FullSCGroups
 [ IsFRGroup and HasFullSCVertex,IsFRElement,IsFRElement], 
  function(G,a,b)
   local v, Graph, sons, starts;
   if AlphabetOfFRSemigroup(G) <> AlphabetOfFRObject(a) or AlphabetOfFRSemigroup(G) <> AlphabetOfFRObject(b) then
    return false;
   fi;
   if a = b then #Spare Computing Time in trivial case.
    return true; 
   fi; 
   Graph := CONJUGATOR_GRAPH@(a,b);
   if FullSCFilter(G) = IsFRElement or FullSCFilter(G) = IsFiniteStateFRElement then
  #In this cases the conjugacy problems are equivalent,
  #----------------------FiniteState-----------------;
  #------------------FunctionalRecursive-------------;
   for v in Graph[1] do
    if v.conj_pair = [a,b] then;
     return true;
    fi;
   od;
   return false;
  elif FullSCFilter(G) = IsFinitaryFRElement then
  #----------------------Finitary--------------------;
   starts := [];
   for v in Graph[1] do
    if v.conj_pair = [a,b] then
     Add(starts,v.id);
    fi;
   od;
   for v in starts do;
    if Size(CONJUGATORS_FINITARY_WRAPPER@(v,Graph,[],[]))>0 then
     return true;
    fi;
   od;
   return false; 
  elif FullSCFilter(G) = IsBoundedFRElement then
  #----------------------Bounded---------------------;  
   starts := [];
   for v in Graph[1] do
    if v.conj_pair = [a,b] then
     Add(starts,v.id);
    fi;
   od;
   for v in starts do
    if Size(CONJUGATORS_BOUNDED_WRAPPER@(v,Graph,[],[[],[],[]],[]))>0 then
     return true;
    fi;
   od;
   return false;
  else
  #----------------------Else------------------------; 
   TryNextMethod();
  fi;
  end
);

InstallOtherMethod(RepresentativeActionOp,
 "Computes a conjugator in the given FullSCGroup ",
 #The attribute FullSCVertex charakterizes all FullSCGroups
 [ IsFRGroup and HasFullSCVertex,IsFRElement,IsFRElement], 
 function(G,a,b)
   local CG, v, start, Conjugators;
   if AlphabetOfFRSemigroup(G) <> AlphabetOfFRObject(a) or AlphabetOfFRSemigroup(G) <> AlphabetOfFRObject(b) then
    return fail;
   fi;
   if a=b then
    return One(G); 
   fi;
   CG := CONJUGATOR_GRAPH@(a,b);
   if FullSCFilter(G) = IsFRElement or FullSCFilter(G) = IsFiniteStateFRElement then
  #In this cases the conjugacy problems are equivalent,
  #----------------------FiniteState-----------------;
  #------------------FunctionalRecursive-------------;
   for v in CG[1] do
    if v.conj_pair = [a,b] then;
     start := v;
     break;
    fi;
   od;
   if not IsBound(start) then
    return fail;
   fi;
   return CONJUGATORS_FINITE_STATE_WRAPPER@(start,CG);
  elif FullSCFilter(G) = IsFinitaryFRElement then
  #----------------------Finitary--------------------;
   start := [];
   for v in CG[1] do
    if v.conj_pair = [a,b] then
     Add(start,v.id);
    fi;
   od;
   for v in start do
    Conjugators :=CONJUGATORS_FINITARY_WRAPPER@(v,CG,[],[]);
    if Size(Conjugators)>0 then
     return Conjugators[1];
    fi;
   od;
   return fail;  
  elif FullSCFilter(G) = IsBoundedFRElement then
  #----------------------Bounded---------------------;  
   start := [];
   for v in CG[1] do
    if v.conj_pair = [a,b] then
     Add(start,v.id);
    fi;
   od;
   for v in start do
    Conjugators :=CONJUGATORS_BOUNDED_WRAPPER@(v,CG,[],[[],[],[]],[]);
    if Size(Conjugators)>0 then
     return Conjugators[1];
    fi;
   od;
   return fail;
  else
  #----------------------Else------------------------; 
   TryNextMethod();
  fi;
  end);
#****************************************************************
################################################################*
################################################################*
###############                               ##################*
###############  Algorithm for branch groups  ##################*
###############                               ##################*
################################################################*
################################################################* 
#****************************************************************


#---------------------------------------------------------------
#------      InitConjugateForBranchGroups      -----------------
#--   Sets the Precomputed initial data for the branch    ---
#--  Algorithm. Stores this data for later computations.     ---   
#---------------------------------------------------------------

InstallMethod(FRBranchGroupConjugacyData,
 [ IsFRGroup ], 
  function(G)
   local init, N, g, h, b, CT, c, i;
   Info(InfoFR, 1, "Init FRBranchGroupConjugacyData");
  init := rec(initial_conj_dic:=NewDictionary([One(G),One(G)],true),
        Branchstructure:=BranchStructure(G),
        RepSystem:=List(~.Branchstructure.group,x->PreImagesRepresentativeNC(~.Branchstructure.quo,x)));
  N := TORSIONNUCLEUS@(G);
  if N = fail then return fail;fi;
  SEARCH@.INIT(G);
  for g in N do
   for h in N do
    #Find one conjugator b
    repeat 
      b := SEARCH@.CONJUGATE(G,g,h);
      while b=fail and SEARCH@.EXTEND(G)=fail do
            SEARCH@.ERROR(G,"RepresentativeAction");
         od;
         Info(InfoFR, 3, "RepresentativeAction: searching at level ",G!.FRData.level," and in sphere of radius ",G!.FRData.radius);
        until b<>fail;
      CT := []; #The Conjugator tuple
      if b <> false then
       i := 1;
       for c in init.Branchstructure.group do
        repeat
           b := SEARCH@.CONJUGATE_COSET(G,c,g,h);
         while b=fail and SEARCH@.EXTEND(G)=fail do
            SEARCH@.ERROR(G,"RepresentativeAction");
         od;
        until b<>fail;
        if b <> false then
       CT[i] := b;
      fi;
      i := i+1;
     od;
      fi;
    AddDictionary(init.initial_conj_dic,[g,h],CT);
   od;
  od;
  Info(InfoFR, 1, "Finished Init FRBranchGroupConjugacyData");
  return init;
  end);
##################################################################
#````````````````````````````````````````````````````````````````#
#`````````````````````                  `````````````````````````#
#`````````````````````   Branch Worker  `````````````````````````#
#`````````````````````                  `````````````````````````#
#````````````````````````````````````````````````````````````````#
################################################################## 
BindGlobal("CONJUGATORS_BRANCH@",function(G,g,h)
 local CP_init, Start, B, BS, Con_dic, saved_quo, quo, Alph, Conjugators_branch_rek,l,k,rek_count;
 CP_init := FRBranchGroupConjugacyData(G);
 if CP_init = fail then
  return fail;
 fi;
 BS := CP_init.Branchstructure;
 B := List(BS.group);
 Con_dic := CP_init.initial_conj_dic;
 saved_quo := NewDictionary(One(G),true);
 quo := function(elm) #Calculate only if asked for.
  local q;
  if not KnowsDictionary(saved_quo,elm) then
   Info(InfoFR,4,"Computing elm^BS.quo. May take some time...");
   q := elm^BS.quo;
   Info(InfoFR,4,"Finished");
   AddDictionary(saved_quo,elm,q);
   return q;
  fi;
  return LookupDictionary(saved_quo,elm);
 end;
 if g = h then
  return [One(g)];
 fi;
 Alph := AlphabetOfFRSemigroup(G);
 rek_count := 1;
 Conjugators_branch_rek := function(g,h)
  local L,LC,C,orbits,orb_repr,p,L_Pos,dep,L_PosC,Pos_Con,c,CT,Con,i,j;
  if not HasName(g) then
   SetName(g,Concatenation("g_",String(rek_count)));
  fi;
  if not HasName(h) then
   SetName(h,Concatenation("h_",String(rek_count)));
  fi; 
  rek_count := rek_count +1;
  Info(InfoFR,3,"Computing g,h=",Name(g),",",Name(h),"");
  if IsOne(g) or IsOne(h) then
   if g = h then
    Info(InfoFR,3,"Computing g,h=",Name(g),",",Name(h),"     g=h=1 So return B");
    return CP_init.RepSystem;
   else
    Info(InfoFR,3,"Computing g,h=",Name(g),",",Name(h),"     g,h is One but the other not. So return []");
    return [];
   fi;
  fi;
  if KnowsDictionary(Con_dic,[g,h]) then
   Info(InfoFR,3,"Computing g,h=",Name(g),",",Name(h),"     g,h are already known. So return them]");
   return LookupDictionary(Con_dic,[g,h]);
  fi;
  orbits := List(Orbits(Group(g),Alph),SortedList);
  orb_repr := List(orbits,Minimum);
  CT := []; # Resulting Conjugator Tuple
  Info(InfoFR,3,"Computing g,h=",Name(g),",",Name(h),"     Orbit: ",orbits);
  for p in LEVEL_PERM_CONJ@(g,h,BS.top) do
   Info(InfoFR,3,"Computing g,h=",Name(g),",",Name(h),"     Try a conjugator with activity ",p);
   L := [];
   L_Pos := []; #Stores the position at which the conjugator tuples are defined.
   dep := []; #Stores the dependencies
   for i in [1..Length(orb_repr)] do
    C := Conjugators_branch_rek(State(g^Length(orbits[i]),orb_repr[i]),State(h^Length(orbits[i]),orb_repr[i]^p));
    if Length(C)=0 then #not a valid conjugator
     L:=[];
     break;
    fi;
    for j in [0..Length(orbits[i])-1] do
     LC := [];
     L_PosC := [];
     for k in [1..Length(C)] do
      if IsBound(C[k]) then
       LC[k] := [State(g^j,orb_repr[i])^-1,C[k],State(h^j,orb_repr[i]^p)];
       L_PosC[k] := k;
      fi;
     od;
     L[orb_repr[i]^(g^j)]:=LC ; 
     L_Pos[orb_repr[i]^(g^j)]:=L_PosC; 
    od;
    Add(dep,orbits[i]);
   od; 
   if Size(L)>0 then
    Con := DEP_CARTESIAN@(L,dep);
    Pos_Con := DEP_CARTESIAN@(L_Pos,dep);
    for i in [1..Size(Con)] do #Now possable Conjugators.
     c:= Product([1..Size(Pos_Con[i])],x->(quo(Con[i][x][1])*B[Pos_Con[i][x]]*quo(Con[i][x][3]))^Embedding(BS.wreath,x));
     c:= (c*p^Embedding(BS.wreath,Size(Alph)+1))^BS.epi;; 
     if c <> fail then #Con is a valid element with representative c;
      Info(InfoFR,3,"Computing g,h=",Name(g),",",Name(h),"     Conjugator found. Add to conjugator tuple ");
      CT[Position(B,c)] := MEALY_FROM_STATES@(Con[i],p);
      #CT[Position(B,c)] := FRElement([Con[i]],[p],[1]);
     fi;
    od; 
   fi;
  od;
  AddDictionary(Con_dic,[g,h],CT); #Save work in case is it again asked for a CT for (g,h).
  return CT;    
 end;
 return Conjugators_branch_rek(g,h);
end);

##################################################################
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%      IsConjugate         %%%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%% RepresentativeActionOp  %%%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
##################################################################
InstallOtherMethod(RepresentativeActionOp,
 "Computes a conjugator in the given Branch group ",
 [ IsBranched and IsFinitelyGeneratedGroup,IsFRElement,IsFRElement,IsFunction], 
 function(G,g,h,f)
  local con;
  if f <> OnPoints then TryNextMethod(); fi;
  Info(InfoFR,2,"Try method for branch groups.");
  con := CONJUGATORS_BRANCH@(G,g,h);
  if con <> fail then
   if Size(con)>0 then
    return Representative(con);
   fi;
   return fail;
  fi;
  Info(InfoFR,2,"Doesn't work. Try next...");
  TryNextMethod();
  end);
InstallMethod(IsConjugate,
 "For Branch Groups",
 [ IsBranched and IsFinitelyGeneratedGroup,IsFRElement,IsFRElement], 
  function(G,g,h)
   local con;
  Info(InfoFR,2,"Try method for branch groups.");
   con := CONJUGATORS_BRANCH@(G,g,h);
  if con <> fail then
   if Size(con)>0 then
    return true;
   fi;
   return false;
  fi;
  Info(InfoFR,2,"Doesn't work. Try next...");
  TryNextMethod();
  end); 


#############################Example##############################
####        Setting the Branch Data           ###
####   for GrigorchukGroup and GuptaSidkiGroup        ###
#SetFRBranchGroupConjugacyData(GrigorchukGroup,
#  rec( initial_conj_dic:=NewDictionary([One(GrigorchukGroup),One(GrigorchukGroup)],true),
#    Branchstructure:=BranchStructure(GrigorchukGroup),
#    RepSystem:=List(~.Branchstructure.group,x->PreImagesRepresentativeNC(~.Branchstructure.quo,x)))
#  );
#CallFuncList(function(a,b,c,d) 
#       local G,D,g,h;
#       G:= GrigorchukGroup;
#       D:= FRBranchGroupConjugacyData(G).initial_conj_dic;
#       for g in [a,b,c,d] do
#        for h in [a,b,c,d] do
#         if g<>h then
#          AddDictionary(D,[g,h],[]);
#         fi;
#        od;
#       od;
#       AddDictionary(D,[a,a],[One(G),a,d*a*d,a*d*a*d]);
#       AddDictionary(D,[b,b],[One(G),,,, b,,,,c,,,,d]);
#       AddDictionary(D,[c,c],[One(G),,,, b,,,,c,,,,d]);
#       AddDictionary(D,[d,d],[One(G),,,a*d*a*d,b,,,b*a*d*a*d,c,,,b*a*d*a,d,,,a*d*a]);
#      end,GeneratorsOfGroup(GrigorchukGroup)
#  );
  
#SetFRBranchGroupConjugacyData(GuptaSidkiGroup,
#  rec( initial_conj_dic:=NewDictionary([One(GuptaSidkiGroup),One(GuptaSidkiGroup)],true),
#    Branchstructure:=BranchStructure(GuptaSidkiGroup),
#    RepSystem:=List(~.Branchstructure.group,x->PreImagesRepresentativeNC(~.Branchstructure.quo,x)))
#  );
#CallFuncList(function(a,t) 
#       local G,D,g,h;
#       G:= GuptaSidkiGroup;
#       D:= FRBranchGroupConjugacyData(G).initial_conj_dic;
#       for g in [a,a^2,t,t^2] do
#        for h in [a,a^2,t,t^2] do
#         if g<>h then
#          AddDictionary(D,[g,h],[]);
#         fi;
#        od;
#       od;
#       AddDictionary(D,[a,a],[One(G),a,a^2]);
#       AddDictionary(D,[a^2,a^2],[One(G),a,a^2]);
#       AddDictionary(D,[t,t],[One(G),,,t,,,t^2]);
#       AddDictionary(D,[t^2,t^2],[One(G),,,t,,,t^2]);
#      end,GeneratorsOfGroup(GuptaSidkiGroup)
#  );
#****************************************************************
################################################################*
################################################################*
###############                               ##################*
###############     Algorithm for the         ##################*
###############       GrigorchukGroup         ##################*
################################################################*
################################################################* 
#****************************************************************
BindGlobal("GRIG_CON@",function(G,g,h)
local f,gw,hw,Gen,a, b, c, d, Fam, aw, dw, ae, be, ce, de, Alph, x_1, x_2, K_repr, K_repr_words, D, ConTup_a, Check, alternating_a_form, shorten_word, compute_conjugates, compute_conjugates_of_word, L_Decomp, Compute_K_rep, L_word_to_Grig, Merge_Ls, conjugators_grig_rek, Res, r, Join_to_first;

############   Spare Computing Time in trivial case.     #########
  if AlphabetOfFRSemigroup(G) <> AlphabetOfFRObject(g) or AlphabetOfFRSemigroup(G) <> AlphabetOfFRObject(h) then
  return fail;
 fi;
 if g = h then 
  return One(G); 
 fi; 
############       (Local) GLOBALS           #####################
 f := EpimorphismFromFreeGroup(G);
 gw:=PreImagesRepresentativeNC(f,g);
 hw:=PreImagesRepresentativeNC(f,h);
 
 Gen := GeneratorsOfGroup(G);
 a:= Position(Gen,MealyElement([[4,2],[4,3],[5,1],[5,5],[5,5]],[(),(),(),(1,2),()],4)); 
 b:= Position(Gen,MealyElement([[4,2],[4,3],[5,1],[5,5],[5,5]],[(),(),(),(1,2),()],1)); 
 c:= Position(Gen,MealyElement([[4,2],[4,3],[5,1],[5,5],[5,5]],[(),(),(),(1,2),()],2)); 
 d:= Position(Gen,MealyElement([[4,2],[4,3],[5,1],[5,5],[5,5]],[(),(),(),(1,2),()],3)); 
 Fam := FamilyObj(gw);  
##################################################################
 aw :=AssocWordByLetterRep(Fam,[a]);  
 dw :=AssocWordByLetterRep(Fam,[d]);
 ae := ImageElm(f,AssocWordByLetterRep(Fam,[a]));
 be := ImageElm(f,AssocWordByLetterRep(Fam,[b]));
 ce := ImageElm(f,AssocWordByLetterRep(Fam,[c]));
 de := ImageElm(f,AssocWordByLetterRep(Fam,[d]));
 Alph:=AlphabetOfFRObject(g);
 x_1 := Alph[1];
 x_2 := Alph[2];

#Precomputed K-representatives:
#[[],a,ad,ada,adad,adada,adadada,adadada,b,ba,bad,bada,badad,badada,badadad,badadada]
 K_repr := [[],[a],[a,d],[a,d,a],[a,d,a,d],[a,d,a,d,a],[a,d,a,d,a,d],[a,d,a,d,a,d,a],[b],[b,a],[b,a,d],[b,a,d,a],[b,a,d,a,d],[b,a,d,a,d,a],[b,a,d,a,d,a,d],[b,a,d,a,d,a,d,a]];
 K_repr_words := List(K_repr,x->AssocWordByLetterRep(Fam,x));
 
 #Precomputed words, which decompose to the K_repr.: <K_repr[i]·l,f(K_repr[i])·l'> = D[i]·<l,l'>
 D:= List([[],[c],[c,a,c,a],[c,a,c,a,c],[c,a,c,a,c,a,c,a],[c,a,c,a,c,a,c,a,c],[c,a,c,a,c,a,c,a,c,a,c,a],[c,a,c,a,c,a,c,a,c,a,c,a,c],[a,d,a],[a,d,a,c],[a,d,a,c,a,c,a],[a,d,a,c,a,c,a,c],[a,d,a,c,a,c,a,c,a,c,a],[a,d,a,c,a,c,a,c,a,c,a,c],[a,d,a,c,a,c,a,c,a,c,a,c,a,c,a],[a,d,a,c,a,c,a,c,a,c,a,c,a,c,a,c]],x->AssocWordByLetterRep(Fam,x));
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%%        Functions       %%%%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 
 #TeporaryDebug function to locate possable errors.
 Check := function(s,g,h,C)
  local c;
  if InfoLevel(InfoFR)>2 then
   for c in C do
    if g^c <> h then
     Info(InfoFR,2,"Error at ",s);
     Info(InfoFR,3,"Error happened here: g=",g,", and h=",h,", and Conjugator c=",c," number: ",Position(C,c),"in ",C);
     return fail;
    fi;
   od;
  fi;
  return true;
 end;
 
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%%%%     Magic on words     %%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

 #Given a word w in Generators of Grig, computes the form w= (a) x1 a x2 a x3… where xi in b,c,d
 alternating_a_form := function(w)
  local i,L,red_L,change,last,last_ind;
  red_L:=List(LetterRepAssocWord(w),AbsInt);
  change := true;
  while (change) do
   change := false;
   last := 5; #not a possable generator
   last_ind := -1;
   for i in [1..Size(red_L)] do
    if IsBound(red_L[i]) then
     if red_L[i]=last then #all generators are of order two
      Unbind(red_L[i]);
      Unbind(red_L[last_ind]);
      last:=5;
      last_ind:=-1;
      change:= true;
     else 
      L := [b,c,d];
      if (not last in [a,5]) and red_L[i] in L then
       Remove(L,Position(L,last));
       Remove(L,Position(L,red_L[i]));
       red_L[last_ind] := L[1]; #bc=cb=d, bd=db=c, cd=dc=b
       last := L[1];
       Unbind(red_L[i]);
       change := true;
      else
       last:=red_L[i];
       last_ind:=i;
      fi;
     fi;
    fi; 
   od;
  od;
  #Fill the gaps
  L:= [];
  for i in red_L do
   Add(L,i);
  od;
  return AssocWordByLetterRep(FamilyObj(w),L);
 end;
#-----------------------------------------------------------------

 #Shortens a given Letter-word over Generators of L by killing all instances of x,-x and 1,1 and 2,2, -1,-1,-2,-2
 shorten_word := function(w) 
  local change, last_pos, l, new_w;
  change := true;
  last_pos := Size(w)+1;
  w[last_pos] := 0;
  while change do
   last_pos := Size(w);
   change := false;
   for l in [1..Size(w)-1] do 
    if IsBound(w[l]) then
     if w[l] = -1*(w[last_pos]) or (w[l]= w[last_pos] and w[l] in [-2,-1,1,2]) then
      change := true;
      Unbind(w[l]);
      Unbind(w[last_pos]);
      last_pos := Size(w);
     else
      last_pos := l;
     fi;
    fi;
   od;
  od;
  new_w:=[];
  for l in w do  
   Add(new_w,l);
  od;
  return new_w{[1..Size(new_w)-1]};
 end;
#-----------------------------------------------------------------
 #Given a generator gen of L and a Letter-word w in Grig, computes the gen^w in generators of L
 compute_conjugates := function(gen,w) 
  local gen_conjugates, Gen, x, g, L;
  #Precomputed list gen_conjugates[x][y] is x^y as word in L_gen
  #where L_gen = [[b],[a,b,a],[b,a,d,a,b,a,d,a],[a,b,a,d,a,b,a,d]];
  #and y in [b,c,d,a]
  gen_conjugates := [];
  gen_conjugates[1]  := [];
  gen_conjugates[1][a] := [2];
  gen_conjugates[1][b] := [1];
  gen_conjugates[1][c] := [1];
  gen_conjugates[1][d] := [1];
  
  gen_conjugates[2]  := [];
  gen_conjugates[2][a] := [1];
  gen_conjugates[2][b] := [1,2,1];
  gen_conjugates[2][c] := [1,-4,2,1];
  gen_conjugates[2][d] := [-4,2];
  
  gen_conjugates[3]  := [];
  gen_conjugates[3][a] := [4];
  gen_conjugates[3][b] := [1,3,1];
  gen_conjugates[3][c] := [-3];
  gen_conjugates[3][d] := [1,-3,1];
  
  gen_conjugates[4]  := [];
  gen_conjugates[4][a] := [3];
  gen_conjugates[4][b] := [1,4,1];
  gen_conjugates[4][c] := [1,-4,1];
  gen_conjugates[4][d] := [-4];
  
  #gen_conjugates := [[[1],[1],[1],[2]],
  #          [[1,2,1],[1,-4,2,1],[-4,2],[1]],
  #          [[1,3,1],[-3],[1,-3,1],[4]],
  #          [[1,4,1],[1,-4,1],[-4],[3]]];
  Gen := [gen];
  for x in w do
   L:= [];
   for g in Gen do
    if g<0 then
     Append(L,List(Reversed(gen_conjugates[-1*g][x]),y->-1*y));
    else 
     Append(L,gen_conjugates[g][x]);
    fi;
   od;
   Gen := shorten_word(L);
  od;
  return Gen;
 end;
#-----------------------------------------------------------------
 #Given a Letter-word w over G and a Letter-word v over L_Gen returns v^w as word over L_Gen.
 compute_conjugates_of_word := function(v,w)
  local con, x;
  con := [];
  for x in v do
   Append(con,compute_conjugates(x,w));
  od;
  return con;
 end;
#-----------------------------------------------------------------
 #Given a word w in Generators of Grig computes a unique representative of w·L and the corresponding word in Letters
 #of generators of L. 
 #The resulting representative is an element of K_repr_words{[1..8]}
 L_Decomp := function(w)
  local l_elm,l_elm_compl,k,l,i,L,red_L,new_L,change,gen_conjugates;
  w:=alternating_a_form(w);
  l_elm := []; #Will contain tuples [v,w,...] meaning l = ...b^w·b^v
  #L_gen := [[b],[a,b,a],[b,a,d,a,b,a,d,a],[a,b,a,d,a,b,a,d]];
  change := true;
  while change do
   change := false;
   new_L := [];
   red_L:=List(LetterRepAssocWord(w),AbsInt);
   for i in Reversed([1..Size(red_L)]) do
    if red_L[i] = b then
     change := true;
     Add(l_elm,Reversed(new_L));
    elif red_L[i] = c then
     change := true;
     Add(l_elm,Reversed(new_L));
     Add(new_L,d);
    else 
     Add(new_L,red_L[i]);
    fi;
   od;
   new_L := Reversed(new_L);
   w := alternating_a_form(AssocWordByLetterRep(Fam,new_L));
  od;
  l_elm_compl := [];
  for l in Reversed(l_elm) do
   Append(l_elm_compl,compute_conjugates(1,l));
  od;
  #Force the form unique beginning with a.
  if Length(w)>7 then 
   w:=Subword(w,1,Length(w) mod 8);
  fi;
  if Length(w)>0 and Subword(w,1,1) = AssocWordByLetterRep(Fam,[d]) then
   w := Subword(AssocWordByLetterRep(Fam,[a,d,a,d,a,d,a,d]),1,8-Length(w));
  fi;
  return [w,shorten_word(l_elm_compl)];
 end;
#-----------------------------------------------------------------
 #Given a word w in Generators of Grig computes a unique represantative of w·K.
 #The result is an element of K_repr_words
 Compute_K_rep := function(w)
  local l,L,red_L,new_L,change,nb,b_exist;
  w:=alternating_a_form(w);
  change := true;
  while change do
   change := false;
   new_L := [];
   #In Grig all generators are selfinverse.
   red_L:=List(LetterRepAssocWord(w),AbsInt);
   nb := 0; #Stores the number of b's occuring
   for l in red_L do
    if l = b then
     nb := nb +1;
    elif l = c then
     nb := nb +1;
     Add(new_L,d);
    else 
     Add(new_L,l);
    fi;
   od;
   w := alternating_a_form(AssocWordByLetterRep(Fam,new_L));
   if IsOddInt(nb) then
    w := AssocWordByLetterRep(Fam,[b])*w;
    b_exist := true;
   else 
    b_exist := false;
   fi;
  od;
  #Force the word to begin with a (after the possable b) to gain a unique form. 
  if b_exist then
   w := Subword(w,2,Length(w));
  fi;
  if Length(w)>7 then 
   w:=Subword(w,1,Length(w) mod 8);
  fi;
  if Length(w)>0 and Subword(w,1,1) = AssocWordByLetterRep(Fam,[d]) then
   w := Subword(AssocWordByLetterRep(Fam,[a,d,a,d,a,d,a,d]),1,8-Length(w));
  fi;
  if b_exist then
   w := AssocWordByLetterRep(Fam,[b])*w;
  fi;
  return w;
 end;
#-----------------------------------------------------------------
 #Given a Letter-word w in L_gen computes a Letter-word res in [a,b,c,d] such that <w,1>=res in Grig.
 L_word_to_Grig := function(w)
  local Pre,Res,x;
  #Precomputed set:
  Pre := [[a,d,a],[b,a,d,a,b],[c,b,a,d,a,b,a,c,a,b,a,d,a,b,a,c,a,c],[b,a,d,a,b,a,c,a,b,a,d,a,b,a,c,a]];
  Res := [];
  for x in w do
   if x<0 then
    Append(Res,Reversed(Pre[-1*x]));
   else
    Append(Res,Pre[x]);
   fi;
  od;
  return Res;
 end;

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%   Helping Functions    %%%%%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 #Computes the conjugator tuple for the pair (g,a): 
 ConTup_a := function (g)
  local g1_modL,l,Allowed_reps,Connected_conjs,con_at_1,con_word,con,Centr_a,Con_tuple;
  if IsOne(Activity(g)) then
   return [];
  fi;
  if not IsOne(State(g,1)*State(g,2)) then
   return [];
  fi;
  #L_gen := [[b],[a,b,a],[b,a,d,a,b,a,d,a],[a,b,a,d,a,b,a,d]];
  g1_modL:=L_Decomp(PreImagesRepresentativeNC(f,State(g,1))); 
  l:=g1_modL[2];
  g1_modL:=LetterRepAssocWord(g1_modL[1]);
  #See Lemma lem:conjugators_of_a for Details
  Allowed_reps:= [[],[a,d],[a,d,a,d,a,d],[a,d,a,d]];
  if not g1_modL in Allowed_reps then
   return [];
  fi;
  #See Lemma lem:conjugators_of_a for the appix conjugator
  Connected_conjs := [[],[c],[a,c],[c,a,c]];
  con := Connected_conjs[Position(Allowed_reps,g1_modL)];
  #resulting conjugator is of the form <l^((g_1modL^-1)),1>·con
  con_at_1 := compute_conjugates_of_word(l,Reversed(g1_modL));
  con_word := L_word_to_Grig(con_at_1);
  Append(con_word,con);
  Info(InfoFR,4,"Conjugator in gen_L: <",con_at_1,",1>",con,"\nConjugator in gen_Grig: ",con_word,"\n");
  #Determine Cosets of K in which the conjugator lies.
  #See Roskov CP Lemma3 for centralizer of a
  Centr_a := List([[],[a],[a,d,a,d],[a,d,a,d,a]],x -> AssocWordByLetterRep(Fam,Concatenation(con_word,x)));
  Con_tuple:= [];
  for con in Centr_a do
   Con_tuple[Position(K_repr,LetterRepAssocWord(Compute_K_rep(con)))] := ImageElm(f,con);
  od; 
  Check("ConTup_a",g,ae,Con_tuple);
  return Con_tuple;
 end; 
 #Finds all Elements <l1,l2> with <l1,l2> in Grig, for l1 in L1, l2 in L2 and return result as Conjugator tuple.
 Merge_Ls := function(L1,L2,with_action)
  local aw_w,aw_t,dw_w,res_Con,i,x; 
  aw_w := One(aw);
  aw_t := ();
  dw_w := One(dw);
  if with_action then
   aw_w := aw;
   aw_t := (x_1,x_2);
  fi;
  Info(InfoFR,4,"Computing ",g,",",h,"  Sub Conjugators: ",L1,"\n");
  Info(InfoFR,4,"Computing ",g,",",h,"  Sub Conjugators: ",L2,"\n");
  #See Lemma 6.16 for <g1,g2<in Grig,  <=> g1=v(a,d)l g2=v(d,a)l
  #So <K_repr[i],K_repr[j]> in Grig  <=> j in [17-x mod 16 +1, 25-x mod 16 +1]
  res_Con := [];
  for i in [1..16] do
   if IsBound(L1[i]) then
    #Find second entry:
    for x in [((17-i) mod 16) +1,((25-i) mod 16) +1] do
     if IsBound(L2[x]) then
      if x>8 then
       dw_w := dw;
      else
       dw_w := One(dw);
      fi;
      Info(InfoFR,4,"Computing ",g,",",h,"  Conjugator found:",i,",",x,"\n");
      if L1[i]=ImageElm(f,K_repr_words[i]) and L2[x]=ImageElm(f,K_repr_words[x]) then
       res_Con[Position(K_repr_words,Compute_K_rep(dw_w*D[i]*aw_w))] := ImageElm(f,dw_w*D[i]*aw_w);
      else #Could always compute the words as generators, but seems uneccassary
       res_Con[Position(K_repr_words,Compute_K_rep(dw_w*D[i]*aw_w))] := MEALY_FROM_STATES@([L1[i],L2[x]],aw_t);
      fi;
     fi;
    od;
   fi;
  od;
  return res_Con;
 end;
 #Joins two Lists in the first with overwriting eventually existing values.
 Join_to_first := function(L,K)
  local i;
  for i in [1..Length(K)] do
   if IsBound(K[i]) then
    L[i] := K[i];
   fi;
  od;
 end;  
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%%     Main Computor      %%%%%%%%%%%%%%%%%%%%%%%
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 conjugators_grig_rek := function(g,h)
  local Centr_bc, Centr_d, L1, L1_temp, L2, res_Con, g1, h1, x ,y;
  Info(InfoFR,3,"Compute Conjugator for pair: ",g,",",h,".\n");
  if Activity(g) <> Activity(h) then
   return [];
  fi;
  #-#-#-#-#-#-#-#-#-#-#-#-   g = identity   -#-#-#-#-#-#-#-#-#-#
  if IsOne(g) then
   if IsOne(h) then
    return List(K_repr,x -> ImageElm(f,AssocWordByLetterRep(Fam,x)));
   fi;
    return [];
  fi;
  #-#-#-#-#-#-#-#-#-#-#-   g in a,b,c,d    -#-#-#-#-#-#-#-#-#-#
  if g in [be,ce] then
   if h=g then
    Centr_bc := [[],,,,,,,[a,d,a,d,a,d,a],[b],,,,,,,[b,a,d,a,d,a,d,a]];
    return List(Centr_bc,x -> ImageElm(f,AssocWordByLetterRep(Fam,x)));
   fi;
  fi;
  if g = de then
   if h=g then
    Centr_d := [[],,,[a,d,a],[a,d,a,d],,,[a,d,a,d,a,d,a],[b],,,[b,a,d,a],[b,a,d,a,d],,,[b,a,d,a,d,a,d,a]];
    return List(Centr_d,x -> ImageElm(f,AssocWordByLetterRep(Fam,x)));
   fi;
  fi;
  if g=ae then
   return List(ConTup_a(h),x->x^-1);
  fi;
  if g in [be,ce,de] then
   if h in [be,ce,de,One(h),ae] then
    return []; #As g=h already considered in an earlier case
   fi;
   #---------------------    |h|>1     -----------------------
   #Test for Conjugator with trivial Activity
   res_Con := [];
   L1 := conjugators_grig_rek(State(g,x_1),State(h,x_1));
   if Size(L1) > 0 then
    L2 := conjugators_grig_rek(State(g,x_2),State(h,x_2));
    res_Con := Merge_Ls(L1,L2,false);
   fi;  

   #Test for Conjugator with non-trivial Activity
   L1 := conjugators_grig_rek(State(g,x_1),State(h,x_2));
   if Size(L1) = 0 then
    return res_Con;
   fi;
   L2 := conjugators_grig_rek(State(g,x_2),State(h,x_1));
   Join_to_first(res_Con,Merge_Ls(L1,L2,true));
   Check("h>1 nontrivial",g,h,res_Con);
   return res_Con;
  fi;

  #-#-#-#-#-#-#-#-#-   |g| > 1, act(g) = 1    -#-#-#-#-#-#-#
  res_Con := [];
  if IsOne(Activity(g)) then
  #Test for Conjugator with trivial Activity
   L1 := conjugators_grig_rek(State(g,x_1),State(h,x_1));
   if Size(L1) > 0 then
    L2 := conjugators_grig_rek(State(g,x_2),State(h,x_2));
    res_Con := Merge_Ls(L1,L2,false);
   fi; 
   #Test for Conjugator with non-trivial Activity
   L1 := conjugators_grig_rek(State(g,x_1),State(h,x_2));
   L2 := conjugators_grig_rek(State(g,x_2),State(h,x_1));
   Join_to_first(res_Con,Merge_Ls(L1,L2,true));
   Check("g>1, act = 1, non-trivial",g,h,res_Con);
   return res_Con;
  else
  #-#-#-#-#-#-#-#-#-   |g| > 1, act(g) = (1,2)    -#-#-#-#-#
   #Test for Conjugator with trivial Activity
   g1 := Compute_K_rep(PreImagesRepresentativeNC(f,State(g,x_1)^-1));
   h1 := Compute_K_rep(PreImagesRepresentativeNC(f,State(h,x_1)));
   L1 := conjugators_grig_rek(State(g,x_1)*State(g,x_2),State(h,x_1)*State(h,x_2));
   res_Con := [];
   if Size(L1) > 0 then
    for x in L1 do
     #Force that only <x,g1xh1> is checked. #Seems to be a bit too complicated, may be simplified.
     L1_temp := [];
     L1_temp[Position(L1,x)]:=x;
     L2 := [];
     L2[Position(K_repr_words,Compute_K_rep(Compute_K_rep(g1)*K_repr_words[Position(L1,x)]*Compute_K_rep(h1)))] := State(g,x_1)^-1*x*State(h,x_1);
     L2 :=Merge_Ls(L1_temp,L2,false);
     for y in L2 do
      res_Con[Position(L2,y)] := y;
     od;
    od;
   fi;
   #Test for Conjugator with non-trivial Activity
   h1 := Compute_K_rep(PreImagesRepresentativeNC(f,State(h,x_2)));
   L1 := conjugators_grig_rek(State(g,x_1)*State(g,x_2),State(h,x_2)*State(h,x_1));
   if Size(L1) = 0 then
    return res_Con;
   fi;
   for x in L1 do
    #Force that only <x,g1xh1> is checked.
    L1_temp := [];
    L1_temp[Position(L1,x)]:=x;
    L2 := [];
    L2[Position(K_repr_words,Compute_K_rep(Compute_K_rep(g1)*K_repr_words[Position(L1,x)]*Compute_K_rep(h1)))] := State(g,x_1)^-1*x*State(h,x_2);
    L2 :=Merge_Ls(L1_temp,L2,true);
    for y in L2 do
     res_Con[Position(L2,y)] := y;
    od;
   od;
   Check("g>1, act = (1,2), non-trivial",g,h,res_Con);
   return res_Con;
  fi;
 end;
 
 Res:= conjugators_grig_rek(g,h);
 Info(InfoFR,3,"Result of recursive computation: ",Res,"\n");
 if Size(Res) = 0 then
  return fail;
 fi;
 return Representative(Res);
end);
SetFRConjugacyAlgorithm(GrigorchukGroup,GRIG_CON@);
#################################################################
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%%      IsConjugate        %%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%%  RepresentativeActionOp %%%%%%%%%%%%%%%%%%#
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
################################################################# 
InstallMethod(IsConjugate,
 " For FR groups with optimized conjugacy algorithm ",
 [ IsFRGroup and HasFRConjugacyAlgorithm,IsFRElement,IsFRElement], 
  function(G,a,b)
   return FRConjugacyAlgorithm(G)(G,a,b) <> fail;
  end);
InstallOtherMethod(RepresentativeActionOp,
 " For FR groups with optimized conjugacy algorithm ",
 [ IsFRGroup and HasFRConjugacyAlgorithm,IsFRElement,IsFRElement,IsFunction], 
  function(G,a,b,f)
   if f <> OnPoints then TryNextMethod(); fi;
   return FRConjugacyAlgorithm(G)(G,a,b);
  end);
  
  















 
 
 
 
 












[ Dauer der Verarbeitung: 0.47 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