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