#%Format: latex
#% This file is marked for TeX processing
#[caption]"Further processing for \autoref{th.Alexander}"
#================================================================
#: Further processing
#: "ReadSkeleton(...)" is intended to read a skeleton from "log/genus0.txt"
#----------------------------------------------------------------
Reread("Burau.txt");   #: (see \file{Burau})
ReadSkeleton := function(data)
 local S;
 S := CreateSkeleton(data[1], data[2], data[3], data[6]);
 S.info := data[4]; #%
 S.id := data[5]; #%
 S.orbit := data[6]; #%
 S.data := data;
 Print([data[1], data[2], data[3]], ", Count=", S.Count, "\n");
 return S;
end;
ListUnique := function(list)   #"ListUnique"
 local i, j, current, res;
 i := 1; #%
 res := [];
 while i < Length(list) do
  current := [list[i]];#%
  j := i + 1;
  while j <= Length(list) do
   if IsIsomorphic(list[i], list[j]) then
    Add(current, list[j]);#%
    Remove(list, j);#%
    continue;
   fi;
   j := j + 1;
  od;
  if Length(current) > 1 then Add(res, current); fi;
  i := i + 1;
 od;
 return res;
end;
AddUnique := function(list, S)
 local SS;
 for SS in list do if IsIsomorphic(S, SS) then return; fi; od;
 Add(list, S, 1);
end;
SplitProduct := function(S1, S2, r)
 local S, U, list, filter, p, pd, pp, s1, s2;
 filter := function(comp)
  s1 := ExtractComponent(S, comp);#%
  s2 := s1;
  if comp[1]^U in comp then
   p := MappingPermListList([1..Length(comp)], comp);
   s2 := FactorSkeleton(s1, p*RestrictedPerm(U, comp)*p^-1);
   s1.info := SkeletonInfo(s2);
  fi;
  if Genus(s2) > 0 then return fail; fi;
  s1.expected := pd;#%
  s1.p := pp;
  Unbind(s1.parent);  #: to save memory
  return s1;
 end;
 pd := S1.expected*S2.expected; #%
 pp := S1.p*S2.p;
 S := Prod(S1, S2); #%
 U := prod(S1.U, S1.Count, S2.U, S2.Count)^r;
 list := Filtered(List(Components(S), filter), s -> s <> fail);
 ListUnique(list);    #: To provide identification
 for p in [1..Length(list)] do list[p].data := [S1.data, S2.data, p, r]; od;
 return list;
end;
ReadSkeleton2 := function(data1, data2, iso1, iso2)
 return SplitProduct(ReadSkeleton(data1), ReadSkeleton(data2), 3: full);
end;
Isomorphisms := function()   #"Isomorphisms"
 local list, S, full;
 list := []; #%
 full := ValueOption("full") = true;
 \[do\] := function(data)
  S := ReadSkeleton(data);
  if full or (Genus(S) = 0) then Add(list, S); fi;
  if not full and (S.U<>One(S.U)) then Add(list, FactorSkeleton(S, S.U)); fi;
 end;
 Read("log/genus0.txt");
 return List(ListUnique(list), l -> List(l, UserData));
end;
Intersections := function()   #"Intersections"
 local list, S, i, j, k, res1, res2, iso1, iso2, process, temp;
 list := [];
 \[do\] := function(data)
  if [data[1], data[2]] = [1, 3] then return; fi;
  Add(list, ReadSkeleton(data: full));
 end;
 process := function(l)
  temp := List(l, u -> PositionProperty(list, v -> IsIsomorphic(u, v))<>fail);
  for k in [1..Length(l)] do l[k] := l[k].info; od;
  return temp;
 end;
 Read("log/genus0.txt");
 OpenOut("log/intersection.txt");
 for i in [1..Length(list)] do
  Print(UserData(list[i]), "\n");
  for j in [i+1..Length(list)] do
   res1 := SplitProduct(list[i], list[j], 1);#%
   iso1 := process(res1);
   if res1 = [] then continue; fi;
   Print(">>", UserData(list[j]), "\n");
   res2 := SplitProduct(list[i], list[j], 3);#%
   iso2 := process(res2);
   Print("  ", res1, "\n", "  ", res2, "\n");
   PrintTo(out, "\\[do\\](", UserData(list[i]), ", ", UserData(list[j]), ", ",
           iso1, ", ", iso2, ");\n\# ", res1, "\n\# ", res2, "\n");
  od;
 od;
 CloseStream(out);
end;
Inclusions := function()
 local list, S, S1, S2, i, Exceptions, less, remove, print;
 list := []; #%
 Exceptions := [[7, 43], [7, 29], [9, 19]];
 less := function(S1, S2)
  i := Length(S1.sub) - Length(S2.sub);
  if i = 0 then i := S1.Count - S2.Count; fi;
  if i = 0 then i := S2.p - S1.p; fi;
  return i > 0;
 end;
 remove := function(S, list, l)
  if l = 0 then list := S.sup; fi;
  for S1 in list do
   if l > 0 then
    i := Position(S1.sub, S);
    if i <> fail then Remove(S1.sub, i); fi;
   fi;
   remove (S, S1.sup, l+1);
  od;
 end;
 print := function(S, l)
  if (l = 0) and IsBound(S.printed) then return; fi;
  S.printed := 1;
  i := Concatenation(String("", l), String(Position(list, S), -2),
                     String(SkeletonInfo(S), l-42));
  Print(i, "\n");#%
  PrintTo(out, i, " <- ", S.data, "\n");
  for S in S.sub do print(S, l+1); od;
 end;
 \[do\] := function(data1, data2, iso1, iso2)
  if [data2[1], data2[2]] in Exceptions then return; fi;
  S1 := ReadSkeleton(data1: full); S2 := ReadSkeleton(data2: full);
  AddUnique(list, S1); AddUnique(list, S2);
  for S in SplitProduct(S1, S2, 3) do AddUnique(list, S); od;
  for S in SplitProduct(S1, S2, 1) do AddUnique(list, S); od;
 end;
 Read("log/intersection.txt");
 Print("Read ", Length(list), " skeletons. Sorting...\n");
 for S in list do S.sub := []; S.sup := []; od;
 for S1 in list do for S2 in list do
  if S1.Count <> S2.Count then
   if Morphisms(S1, S2) <> [] then Add(S1.sub, S2); Add(S2.sup, S1); fi;
  fi;
 od; od;
 Sort(list, less); #%
 for S in list do Sort(S.sub, less); od;
 for S in list do remove(S, fail, 0); od;
 OpenOut("log/inclusion.txt");
 for S in list do print(S, 0); od;
 CloseStream(out);
end;
Intersections2 := function()   #"Intersections"
 local list1, list2, i, j, k;
 \[do\] := function(data1, data2, iso1, iso2)
  AddSet(list1, data1); AddSet(list1, data2);
  Add(list2, [data1, data2]); Add(list2, [data2, data1]);
 end;
 list1 := Set([]);  list2 := [];
 Read("log/intersection.txt");
 for i in [1..Length(list1)] do
  for j in [i+1..Length(list1)] do
   for k in [j+1..Length(list1)] do
    if ([list1[i], list1[j]] in list2) and
       ([list1[i], list1[k]] in list2) and
       ([list1[j], list1[k]] in list2) then
     Print([list1[i], list1[j], list1[k]], "\n");
    fi;
   od;
  od;
 od;
end;
#================================================================
#: Computation of $\pi_1$
#----------------------------------------------------------------
Skipped := function(S)
 local except;
 Unbind(S.info); #%
 Print("-> ", SkeletonInfo(S));
 except := ValueOption("except");
 if except <> fail then
  if SkeletonInfo(S) in except then Print(": skipped\n"); return true; fi;
 fi;
 Print("\n"); #%
 return false;
end;
analyzePi1 := function(S)
 local g, ab, size, expected, isinf;
 isinf := function(gr)
  g := gr;#%
  ab := AbelianInvariants(g);#%
  Print("  ", ab, ",");
  if 0 in ab then Print("  skipped\n"); return true; fi;
  return false;
 end;
 if Skipped(S) then return; fi;
 g := Pi1(S: simplified); #%
 expected := S.expected;
 if isinf(g) then return; fi;
 if isinf(DerivedSubgroup(g)) then return; fi;
 size := Size(g);#%
 Print("  ", size, "/", expected, ";");
 expected := size/expected;
 if expected <> 1 then
  Print("  >>");#%
  if isinf(DerivedSubgroup(g)) then return; fi;
  Print("  ", Size(g));#%
  if Size(g) <> expected then Print("  !!!"); fi;
 fi;
 Print("\n");
end;
Exceptions := Set([ #: Artificial exceptions:
 [ 200, 0, 0, "5^40", 20 ], # [10, 3], #: coset table calculation fails
 [ 840, 0, 0, "1^28 7^116", 28 ],  # [7, 29], #: too slow
 [ 1848, 0, 0, "1^42 7^258", 42 ], # [7, 43], #: too slow
 [ 300, 0, 0, "5^60", 300 ], #: coset table calculation fails
 [ 640, 0, 0, "8^80", 64 ],  #: coset table calculation fails
[]]);
Pi1s := function()   #"Pi1s"
 OutputLogTo("log/pi1.txt");
 \[do\] := function(data)
  if data[5] = fail then return; fi;
  analyzePi1(ReadSkeleton(data): full, except := Exceptions);
 end;
 Read("log/genus0.txt");
 \[do\] := function(data1, data2, iso1, iso2)
  local S, list, i;
  if not(false in iso2) then return; fi;
  list := ReadSkeleton2(data1, data2, iso1, iso2);
  for i in [1..Length(list)] do if iso2[i] then list[i] := fail; fi; od;
  list := Filtered(list, S -> S <> fail);
  Print("*Processing ", Length(list), " group(s)\n");
  for S in list do
   Print("*", SkeletonInfo(S), " ");#%
   analyzePi1(S: except := Exceptions);
  od;
 end;
 Read("log/intersection.txt");
 OutputLogTo();
end;

analyzePi1 := function(S)
 local res, g, gg, ab, absize, size, expected, isinf;
 isinf := function(gr)
  g := gr;#%
  ab := AbelianInvariants(g);#%
  Add(res, ab);
  if 0 in ab then Add(res, "skipped"); return true; fi;
  return false;
 end;
 gg := Pi1(S: simplified); #%
 expected := S.expected; #%
 res := [];
 if isinf(gg) then return res; fi;
 absize := Product(ab);
 if isinf(DerivedSubgroup(g)) then return res; fi;
 size := Size(gg)/absize;#%
 Add(res, size);#%
 Add(res, expected);
 expected := size/expected;
 if expected <> 1 then
  if isinf(DerivedSubgroup(g)) then return res; fi;
  Add(res, Size(g));#%
  if Size(g) <> expected then Add(res, "!!!"); fi;
 fi;
 if not IsString(res[Length(res)]) then Add(res, "OK"); fi;
 return res;
end;
Pi1s := function()   #"2Pi1s"
 local Res, res, fname, i, j, list, shorten, process, done, save;
 Res := []; #%
 fname := "log/BurauPi1.txt";
 if IsReadableFile(fname) then Res := ReadAsFunction(fname)(); fi;
 shorten := function(data) return [data[1], data[2], data[3], data[6]]; end;
 done := function(ID)
  for j in Res do if j[1] = ID then return true; fi; od;
  return false;
 end;
 save := function()
  OpenOut(fname);
  PrintTo(out, "return [\n", Res[1]);
  for j in [2..Length(Res)] do PrintTo(out, ",\n", Res[j]); od;
  PrintTo(out, "\n];\n");
  CloseStream(out);
 end;
 process := function(ID, S)
  for i in Res do if i[1] = ID then return; fi; od;
  res := analyzePi1(S);
  Print("*", SkeletonInfo(S), ": ", res, "\n");
  Add(Res, [ID, res]); #%
  save();
 end;
 \[do\] := function(data1, data2, iso1, iso2)
  if not(false in iso2) then return; fi;
  if done([shorten(data1), shorten(data2)]) then return; fi;
  list := ReadSkeleton2(data1, data2, iso1, iso2);
  for i in [1..Length(list)] do if iso2[i] then list[i] := fail; fi; od;
  list := Filtered(list, S -> S <> fail);
  Print("*Processing ", Length(list), " group(s)\n");
  for i in [1..Length(list)] do
   process([shorten(data1), shorten(data2), i], list[i]);
  od;
  Add(Res, [[shorten(data1), shorten(data2)], "done"]);
  save();
 end;
 Read("log/intersection.txt");
 \[do\] := function(data)
  if data[5] = fail then return; fi;
  if done(shorten(data)) then return; fi;
  process(shorten(data), ReadSkeleton(data: full));
 end;
 Read("log/genus0.txt");
end;
#================================================================
#[endinput]
