GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#(C) Graham Ellis, 2005-2006
#####################################################################
InstallGlobalFunction(IdentityAmongRelators,
function(arg)
local
R,idnum,
Dimension,
Boundary,
Elts, Mult, Inv,
Frels, rels,
Fgens,gens,
FirstBoundaryHomomorphism,
Boundary2Relator,
start,
ActWord,
idnt,
gennum,
CommonChord,
Amalgamate,
b, r, x,i,X;
R:=arg[1];
idnum:=arg[2];
if not (IsHapResolution(R) or IsHapNonFreeResolution(R)) then
Print("This function must be applied to a resolution. \n");
return fail;
fi;
if not EvaluateProperty(R,"reduced")=true then
if R!.dimension(0)>1 then
Print("This function must be applied to a REDUCED resolution. \n");
return fail; fi;
fi;
if not EvaluateProperty(R,"characteristic")=0 then
Print("This function only works in characteristic 0. \n");
return fail;
fi;
Dimension:=R!.dimension;
Boundary:=R!.boundary;
Elts:=R!.elts;
Frels:=[];
start:=List([1..Dimension(2)],x->List(Boundary(2,x),y->y[2]));
start:=SortedList(Intersection(start))[1];
gens:=[];
#####################################################################
Mult:=function(g,h);
return Position(Elts,Elts[g]*Elts[h]);
end;
#####################################################################
#####################################################################
Inv:=function(g);
return Position(Elts,Elts[g]^-1);
end;
#####################################################################
#####################################################################
FirstBoundaryHomomorphism:=function(x)
local r;
r:=Boundary(1,x[1]);
r:=List(r,y->Mult(x[2],y[2]));
if x[1]>0 then return r;
else return Reversed(r); fi;
end;
#####################################################################
#####################################################################
Boundary2Relator:=function(b)
local c, rel, w;
b:=SortedList(AlgebraicReduction(b));
rel:=[start];
while Length(b)>0 do
for x in b do
w:=FirstBoundaryHomomorphism(x);
if w[1]= rel[Length(rel)] then
Append(rel, [w[2]]); RemoveSet(b,x); break;
else
if w[2]= rel[Length(rel)] then
Append(rel, [w[1]]); RemoveSet(b,x); break;
fi;
fi;
od;
od;
return rel;
end;
#####################################################################
for r in [1..Dimension(2)] do
Append(Frels,[Boundary2Relator(Boundary(2,r))]);
od;
for r in Frels do
if (not Inv(r[2]) in gens) then AddSet(gens,r[2]);fi;
if (not Inv(r[Length(r)-1]) in gens) then AddSet(gens,r[Length(r)-1]);fi;
od;
#####################################################################
gennum:=function(r)
local g,h;
for g in gens do
if Mult(r[1],g)=r[2] then h:=Position(gens,g); break; fi;
if Mult(r[1],Inv(g))=r[2] then h:=Position(gens,g); break; fi;
od;
h:=(h-1) mod 6;
h:=h+1;
return h;
end;
#####################################################################
#####################################################################
CommonChord:=function(A,BB)
#Returns the common contractible chord between loops
#A and B if such a chord exists. Otherwise it returns
#fail. This is a clumsy piece of code!
local B, C, i, chord,chordA,chordB,comp ;
B:=StructuralCopy(BB);
C:=Intersection(A,B);
if Length(C)<2 then return fail; fi;
chordA:=[];
chordB:=[];
for i in [1..Length(B)-1] do
if B[i] in C and B[i+1] in C then
Add(chordB, [B[i],B[i+1]]);
fi;
od;
for i in [1..Length(A)-1] do
if A[i] in C and A[i+1] in C then
Add(chordA, [A[i],A[i+1]]);
fi;
od;
chord:=Intersection(chordA,chordB);
if not Length(chord)=Length(C)-1 then
return fail;
fi;
#########################
if not B[1] in C then
chord:=List(chordB,x->x[1]);
Add(chord,chordB[Length(chordB)][2] );
chordA:=Reversed(B{[1..Position(B,chord[1])]});
chordB:=Reversed(B{[Position(B,chord[Length(chord)])..Length(B)-1]});
comp:=Concatenation(chordA,chordB);
fi;
########################
########################
if B[1] in C then
chordA:=[];
chordB:=[];
for x in B{[2..Length(B)]} do
if x in C then Add(chordA,x); else break;fi;
od;
for x in Reversed(B) do
if x in C then Add(chordB,x); else break;fi;
od;
chord:=Concatenation(Reversed(chordB),chordA);
if B[2] in C and B[Length(B)-1] in C and B[2] in C then
comp:=Reversed(B{[Position(B,chord[Length(chord)])..Position(B,chord[1])]});
fi;
if B[2] in C and not B[Length(B)-1] in C then
comp:=Reversed(B{[Position(B,chord[Length(chord)])..Length(B)]});
fi;
if not B[2] in C and B[Length(B)-1] in C then
comp:=Reversed(B{[1..Position(B,chord[1])]});
fi;
fi;
#######################
return [chord,comp];
end;
#####################################################################
#####################################################################
Amalgamate:=function(A,B)
local C,D, #Here A is the big loop and B the small loop.
Begin,End,amalg;
D:=CommonChord(A,B);
C:=D[2];;
if C=fail then return fail; fi;
if not A[1] in D[1] then
Begin:=A{[1..Position(A,C[1])-1]};
End:=A{[Position(A,C[Length(C)])+1..Length(A)]};
amalg:=Concatenation(Begin,C,End);
fi;
if A[1] in D[1] then
End:=A{[Position(A,C[Length(C)])+1..Position(A,C[1])-1]};
amalg:=Concatenation(C,End);
Add(amalg,C[1]);
fi;
return amalg;
end;
#####################################################################
#####################################################################
idnt:=[];
for b in Boundary(3,idnum) do
x:=Boundary(2,AbsInt(b[1]));
x:=Boundary2Relator(x);
if SignInt(b[1])=-1 then x:=Reversed(x); fi;
x:=List(x,t->Mult(b[2],t));
Add(idnt,x);
od;
####################################################################
#return CommonChord;
return [Amalgamate,idnt];
end);
#####################################################################