GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
############################################################ ## ## ## TorsionSubcomplex.g ## ## HAP subpackage for GAP (Groups Algorithms Programming) ## ## under the GNU GPL license (v. 3), 2012 ## ## by Alexander D. Rahm ## ## IRCSET post-doctoral Research fellow ## ## National University of Ireland at Galway ## ## ## ############################################################ ############################################################################### # HAP subpackage by Alexander D. Rahm for extracting torsion subcomplexes # # from cellular complexes with group actions. Version 1.3 of June 21st, 2012. # # In the following, whenever we talk about cell complexes, we mean a set of # # representatives for the action of the group, # # i.e. a strict fundamental domain. # # The syntax is TorsionSubcomplex(groupName,p); # # where p is the prime for which to extract the p-torsion subcomplex, # # and groupName must be a string holding between \"quotes\" an entry of the # # HAP library of cellular complexes with group actions, # # which admits the entries displayed with the following command. # # DisplayAvailableCellComplexes(); # # The incidence matrix of the 1-skeleton of the p-torsion subcomplex # # is returned by this function. To visualize this 1-skeleton as a graph, # # type instead VisualizeTorsionSkeleton(groupName,p). # # If the cell complex is admissible in the sense of Brown, # # the Farrell cohomology of the group equals # # the equivariant Farrell cohomology # # of the reduced torsion subcomplex. The syntax is # # ReduceTorsionSubcomplex(groupName,p); # # and it returns us the cells which are to merge in the torsion subcomplex. # ############################################################################### InstallGlobalFunction("IsPnormal", function( G, p) ######################################################################### ## Check if the group G is p-normal for the prime p. ## ## Zassenhaus defines a finite group to be p-normal if the center of ## ## one of its Sylow p-groups is the center of every Sylow p-group in ## ## which it is contained. ## ######################################################################### local SylowCenter, SylowGroups, N, isPnormal, k, j; isPnormal := true; SylowGroups := ConjugateSubgroups( G, SylowSubgroup( G, p)); N := Size( SylowGroups); for j in [1..N] do SylowCenter := Center( SylowGroups[j]); for k in [1..N] do if k <> j then if IsSubset(SylowGroups[k], SylowCenter) then if SylowCenter = Center( SylowGroups[k]) then ; ## the condition is fulfilled for this pair ## else isPnormal := false; Print("The group ",G," is not p-normal."); fi; fi; fi; od; od; return isPnormal; end); InstallGlobalFunction("DisplayAvailableCellComplexes", function() Exec( Concatenation("ls ",DirectoriesPackageLibrary("HAP")[1]![1], "Perturbations/Gcomplexes/")); end); admissibilityCheck := function(celldata) ######################################################### ## A cell complex is admissible in the sense of Brown, ## ## if each cell stabilizer fixes its cell pointwise. ## ## Additionally, ## ## we gather the cardinalities of the stabilizers. ## ######################################################### local stabilizerCardinalities, G, card, n, j, R, vcd, warned; warned := false; stabilizerCardinalities := []; vcd := Length(celldata)-1; for n in [0..vcd] do stabilizerCardinalities[n+1] := []; for j in [1..Length(celldata[n+1])] do G := celldata[n+1][j]!.TheMatrixStab; if IsFinite(G) then card := Order(G); stabilizerCardinalities[n+1][j] := card; ## *** Now we have to compare *** ## ## *** with the order of "TheRotSubgroup" *** ## R := celldata[n+1][j]!.TheRotSubgroup; if card > Order(R) and warned = false then Print("****Warning: cell complex not admissible ", "in the sense of Brown!****\n", " Torsion subcomplex reduction requires cell subdivision.\n"); warned := true; fi; fi; od; od; return [stabilizerCardinalities, warned]; end; computeIncidenceMatrix := function(torsionCells, numberOfTorsionCells, celldata) ######################################################## ## The incidence matrix of the 1-skeleton of the ## ## p-torsion subcomplex is returned by this function. ## ######################################################## local incidenceMatrix, j, k, q, endpoints, inverseIndex, ORIGIN, END; incidenceMatrix := []; for j in [1..numberOfTorsionCells[1]] do incidenceMatrix[j] := []; for k in [1..numberOfTorsionCells[1]] do incidenceMatrix[j][k] := 0; od; od; Print("The edges in the quotient by the action on the torsion subcomplex are: "); ## Record the indices in the torsion subcomplex of vertices in ## ## the cell complex, in order to assign the endpoints of an edge## inverseIndex := []; for q in [1..Length(celldata[1])] do inverseIndex[q] := "error: not a p-torsion vertex"; od; for j in [1..numberOfTorsionCells[1]] do inverseIndex[torsionCells[1][j][2]] := j; od; for q in [1..numberOfTorsionCells[2]] do endpoints := celldata[2] [torsionCells[2][q][2]]!.BoundaryImage.ListIFace; ORIGIN := inverseIndex[endpoints[1]]; END := inverseIndex[endpoints[2]]; Print([ORIGIN,END]); incidenceMatrix[ORIGIN][END] := incidenceMatrix[ORIGIN][END] +1; ## If we do not want to have the incidence matrix symmetric, ## ## then deactivate the following line. ## incidenceMatrix[END][ORIGIN] := incidenceMatrix[END][ORIGIN] +1; od; Print(".\n"); return incidenceMatrix; end; getCardinals := function(stabilizerCardinalities, p, n) ############################################################ ## Extract the cardinalities of n-cell stabilisers ## ## containing p-torsion. ## ############################################################ local S, m, Cardinals, counter; Cardinals := []; counter := 0; S := stabilizerCardinalities[n+1]; for m in S do if m mod p = 0 then if counter > 0 then if m in Cardinals then ; else counter := counter +1; Cardinals[counter] := m; fi; else counter := 1; Cardinals[counter] := m; fi; fi; od; return Cardinals; end; extractPmultipleTorsionCells := function(torsionCells, numberOfTorsionCells, celldata,stabilizerCardinalities, p) ################################################################## ## Make lists of n-cells of each stabilizer cardinality ## ## in the p-torsion subcomplex. ## ################################################################## local vcd, pMultipleTorsionCells, numberOfPmultipleTorsionCells, Pmultiples, PmultipleNumero, m, n, cell, j; vcd := Length(celldata) -1; pMultipleTorsionCells := []; numberOfPmultipleTorsionCells := []; Pmultiples := []; for n in [0..vcd] do pMultipleTorsionCells[n+1] := []; numberOfPmultipleTorsionCells[n+1] := []; Pmultiples[n+1] := getCardinals(stabilizerCardinalities, p, n); PmultipleNumero := 0; for m in Pmultiples[n+1] do PmultipleNumero := PmultipleNumero +1; numberOfPmultipleTorsionCells[n+1][PmultipleNumero] := 0; pMultipleTorsionCells[n+1][PmultipleNumero] := []; for cell in torsionCells[n+1] do ## Check if the stabilizer contains p-torsion of multiple m ## if stabilizerCardinalities[n+1][cell[2]] = m then numberOfPmultipleTorsionCells[n+1] := numberOfPmultipleTorsionCells[n+1] +1; pMultipleTorsionCells[n+1][PmultipleNumero] [numberOfPmultipleTorsionCells[n+1][PmultipleNumero]] := cell; fi; od; Print("There are ",numberOfPmultipleTorsionCells[n+1][PmultipleNumero], " orbits of ",n,"-cells in the ",p,"-torsion subcomplex", ", the stabilizers of which are of cardinality ",m, ", namely the ones numero " ); for j in [1..Length(pMultipleTorsionCells[n+1][PmultipleNumero])-1] do Print(pMultipleTorsionCells[n+1][PmultipleNumero][j][2],", "); od; Print(pMultipleTorsionCells[n+1][PmultipleNumero][ Length(pMultipleTorsionCells[n+1][PmultipleNumero])][2],".\n"); od; od; return [pMultipleTorsionCells, Pmultiples]; end; pairsIntersection := function(sortedData, celldata) ######################################################################### ## We establish a preliminary list of cell triples as candidates for ## ## fusions, consisting of a pair of n-cells that admits precisely ## ## one adjacent (n-1)-cell in common. ## ## This pair and their common boundary cell constitute our cell triple.## ######################################################################### local pMultipleTorsionCells, Pmultiples, n, j, f, s, vcd, fusionCandidates, numberOfFusionCandidates, firstCell, secondCell, commonBoundary; pMultipleTorsionCells := sortedData[1]; Pmultiples := sortedData[2]; vcd := Length(celldata) -1; fusionCandidates := []; numberOfFusionCandidates := 0; for n in [0..vcd] do for j in [1..Length(Pmultiples[n+1])] do for f in [1..Length(pMultipleTorsionCells[n+1][j])] do firstCell := pMultipleTorsionCells[n+1][j][f]; for s in [f+1..Length(pMultipleTorsionCells[n+1][j])] do secondCell := pMultipleTorsionCells[n+1][j][s]; commonBoundary := Set(celldata[n+1][firstCell[2]]!.BoundaryImage!.ListIFace); IntersectSet( commonBoundary, Set(celldata[n+1][secondCell[2]]!.BoundaryImage!.ListIFace) ); if Size(commonBoundary) = 1 then Print("The boundary of ",n,"-cell numero ",firstCell[2]," is ", celldata[n+1][firstCell[2]]!.BoundaryImage!.ListIFace, " and that of ",n,"-cell numero ",secondCell[2]," is ", celldata[n+1][secondCell[2]]!.BoundaryImage!.ListIFace, " so they have ",n-1,"-cell numero ",commonBoundary[1], " in common.\n"); numberOfFusionCandidates := numberOfFusionCandidates +1; fusionCandidates[numberOfFusionCandidates] := [firstCell, secondCell, commonBoundary[1]]; fi; od; od; od; od; return fusionCandidates; end; bifurcationFreeCells := function(fusionCandidates, torsionCells, celldata) ########################################################################## ## We keep only those cell triples as candidates for a fusion, ## ## that are not "bifurcated" in the p-torsion subcomplex : ## ## Triples such that only n-cells adjacent to the (n-1)-cell ## ## of the triple are the two n-cells of the triple. ## ########################################################################## local firstCell, secondCell, boundaryCell, cellTriple, n, cell, torsionCell, remainingFusionCandidates; remainingFusionCandidates := Set(StructuralCopy(fusionCandidates)); for cellTriple in fusionCandidates do firstCell := cellTriple[1]; secondCell := cellTriple[2]; n := firstCell[1]; boundaryCell := cellTriple[3]; for torsionCell in torsionCells[n+1] do cell := celldata[n+1][torsionCell[2]]; if boundaryCell in cell!.BoundaryImage!.ListIFace then if torsionCell in [firstCell, secondCell] then ; # the cell triple remains a candidate for fusion. else Print("The p-torsion subcomplex is bifurcated at the ", n-1,"-cell numero ",boundaryCell,".\n"); RemoveSet(remainingFusionCandidates, cellTriple); fi; fi; od; od; return remainingFusionCandidates; end; IsInnerConjugate := function(G, A, B) ################################################################# ## Check if the subgroups A and B of G are conjugate inside G. ## ## For groups with high cardinality, we use GAP's function ## ## IsConjugate(G, A, B), whilst for low cardinalities we ## ## implement an algorithm that is faster for our matrix groups.## ################################################################# local areConjugate, j, g, card, subcard, a, setOfElements, gAgInv, timeDifference; timeDifference := Runtime(); if IsFinite(G) then card := Size(G); if card < 1001 then j := 1; setOfElements := Set(G); areConjugate := false; subcard := Size(A); while j < card/subcard +1 and areConjugate = false do g := setOfElements[1]; gAgInv := ConjugateGroup(A, g); if IsSubset(gAgInv, B) then if IsSubset(B, gAgInv) then areConjugate := true; fi; fi; for a in A do RemoveSet(setOfElements, a*g); od; j := j+1; od; else areConjugate := IsConjugate(G, A, B); fi; else areConjugate := IsConjugate(G, A, B); fi; Print("Computing conjugation took ",Runtime()-timeDifference," ms.\n"); return areConjugate; end; getIdentifier := function( cell, boundaryCell, celldata) ############################################################## ## Retrieve the group element sending the cell to ## ## a representative that is adjacent to the boundary cell. ## ############################################################## local n, boundaryIndex, j, identifiers, g; n := cell[1]; identifiers := celldata[n+1][cell[2]]!.BoundaryImage!.ListElt; for j in [1..Length(identifiers)] do if celldata[n+1][cell[2]]!.BoundaryImage!.ListIFace[j] = boundaryCell then boundaryIndex := j; fi; od; g := celldata[n+1][cell[2]]!.BoundaryImage!.ListElt[boundaryIndex]; return g; end; checkStabilizerConjugacy := function(fusionCandidates, celldata, p) ################################################################## ## Eliminate cell triples from the fusion candidates list, ## ## for which the stabilizers of the n-cells are not conjugate. ## ## Therefore, we first conjugate the stabilizers of the n-cells ## ## into stabilizers of representatives ## ## adjacent to the (n-1)-cell. ## ## Then we check if we can conjugate them within the stabilizer ## ## of the (n-1)-cell. ## ################################################################## local firstCell, secondCell, boundaryCell, firstStabilizer, secondStabilizer, boundaryStabilizer, cellTriple, n, g, validated, remainingFusionCandidates; remainingFusionCandidates := StructuralCopy(fusionCandidates); for cellTriple in fusionCandidates do firstCell := cellTriple[1]; secondCell := cellTriple[2]; n := firstCell[1]; boundaryCell := cellTriple[3]; firstStabilizer := celldata[n+1][firstCell[2]]!.TheMatrixStab; secondStabilizer := celldata[n+1][secondCell[2]]!.TheMatrixStab; boundaryStabilizer := celldata[n][boundaryCell]!.TheMatrixStab; g := getIdentifier( firstCell, boundaryCell, celldata); firstStabilizer := ConjugateGroup(firstStabilizer, g); g := getIdentifier( secondCell, boundaryCell, celldata); secondStabilizer := ConjugateGroup(secondStabilizer, g); if IsSubset( boundaryStabilizer, firstStabilizer) then if IsSubset( boundaryStabilizer, secondStabilizer) then if IsSubset(firstStabilizer, secondStabilizer) then validated := true; else validated := IsConjugate( boundaryStabilizer, firstStabilizer, secondStabilizer); fi; else Print("****Error: ",n,"-cell numero ",secondCell[2], " not pointwise fixed.****\n"); fi; else Print("****Error: ",n,"-cell numero ",firstCell[2], " not pointwise fixed.****\n"); fi; if validated then if IsSubset(firstStabilizer, boundaryStabilizer) then ; ## in this case, we can clearly merge the cell triple ## ## without changing p-primary equivariant Farrell cohomology ## Print("The ",n,"-cells numero ",firstCell[2]," and ", secondCell[2]," are subject to a cell fusion.\n"); else if IsPnormal( boundaryStabilizer, p) then g := Normalizer(boundaryStabilizer, Center(SylowSubgroup( boundaryStabilizer, p) )); if IsSubset(firstStabilizer, g) and IsSubset(g, firstStabilizer) then validated := true; ## if firstStabilizer is isomorphic to g, it is proven ## ## that we can merge the cell triple ## ## without changing p-primary equivariant Farrell cohomology ## else validated := IsInnerConjugate( boundaryStabilizer, firstStabilizer, g); fi; if validated then Print("The ",n,"-cells numero ",firstCell[2]," and ", secondCell[2]," are subject to a non-trivial fusion.\n"); fi; else validated := false; fi; fi; fi; if validated then ; ## the cell triple is subject ot a cell fusion. ## else RemoveSet(remainingFusionCandidates, cellTriple); fi; od; return remainingFusionCandidates; end; mergeCells := function( celldata, fusionCandidates, torsionCells) #################################################################### ## Merge the cells in that have been definitively retained ## ## as fusion candidates. As proven, this does not change ## ## the p-primary equivariant Farrell cohomology. ## #################################################################### local firstCell, secondCell, boundaryCell, cellTriple, n, j, reducedTorsionCells, vcd, mergedBoundary; mergedBoundary := []; reducedTorsionCells := StructuralCopy( torsionCells); vcd := Length(reducedTorsionCells) -1; for n in [0..vcd] do reducedTorsionCells[n+1] := Set(reducedTorsionCells[n+1]); mergedBoundary[n+1] := []; od; for cellTriple in fusionCandidates do firstCell := cellTriple[1]; secondCell := cellTriple[2]; n := firstCell[1]; boundaryCell := cellTriple[3]; Print("The ",n-1,"-cell numero ",boundaryCell, " is amalgamated into the merging ",n,"-cells numero ", firstCell[2]," and ",secondCell[2],".\n"); RemoveSet(reducedTorsionCells[n], [n-1,boundaryCell]); mergedBoundary[n+1][firstCell[2]] := Set(Concatenation( celldata[n+1][firstCell[2]]!.BoundaryImage!.ListIFace, celldata[n+1][secondCell[2]]!.BoundaryImage!.ListIFace )); RemoveSet(mergedBoundary[n+1][firstCell[2]], boundaryCell); Print("The merged boundary of these two cells is ", mergedBoundary[n+1][firstCell[2]],".\n"); # RemoveSet(mergedBoundary[n+1][firstCell[2]], boundaryCell); #Print(mergedBoundary[n+1][firstCell[2]]); od; return reducedTorsionCells; end; getTorsionSubcomplex := function(groupName, p) ##################################################################### ## Here, p is the prime for which to take the torsion subcomplex. ## ## We extract the cells the stabilizer of which contains p-torsion.## ##################################################################### local vcd, stabilizerCardinalities, celldata, torsionCells, numberOfTorsionCells, n, j, returnedData, warned, groupname; groupname := Filtered( groupName, function ( x ) return not (x = '(' or x = ')' or x = ',' or x = '[' or x = ']'); end ); Read(Concatenation( DirectoriesPackageLibrary("HAP")[1]![1], "Perturbations/Gcomplexes/",groupname)); celldata := StructuralCopy(HAP_GCOMPLEX_LIST); vcd := Length(celldata) -1; Print("Extracting the ",p,"-torsion subcomplex of the ", vcd,"-dimensional ",groupName,"-cell complex ... \n"); returnedData := admissibilityCheck(celldata); stabilizerCardinalities := returnedData[1]; warned := returnedData[2]; torsionCells := []; numberOfTorsionCells := []; for n in [0..vcd] do torsionCells[n+1] := []; numberOfTorsionCells[n+1] := 0; for j in [1..Length(celldata[n+1])] do ## Check if the stabilizer contains p-torsion ## if stabilizerCardinalities[n+1][j] mod p = 0 then Print("Extracted ",n,"-cell numero ",j, " of stabilizer cardinality ", stabilizerCardinalities[n+1][j],".\n"); numberOfTorsionCells[n+1] := numberOfTorsionCells[n+1]+1; torsionCells[n+1][numberOfTorsionCells[n+1]] :=[n, j]; fi; od; od; return [torsionCells, numberOfTorsionCells, celldata, stabilizerCardinalities, warned]; end; InstallGlobalFunction("TorsionSubcomplex", function(groupName, p) ############################################ local torsionCells, numberOfTorsionCells, celldata, sortedData, warned; sortedData := getTorsionSubcomplex(groupName, p); torsionCells := sortedData[1]; numberOfTorsionCells := sortedData[2]; celldata := sortedData[3]; warned := sortedData[5]; if IsPrime(p) then sortedData := [computeIncidenceMatrix(torsionCells, numberOfTorsionCells, celldata), warned]; else sortedData := "The number p must be prime in order to compute the incidence matrix."; fi; return sortedData; end); InstallGlobalFunction("VisualizeTorsionSkeleton", function(groupName, p) ################################################## local incidenceMatrix, graphData, returnedData, warned; returnedData := TorsionSubcomplex(groupName, p); if IsPrime(p) then incidenceMatrix := returnedData[1]; warned := returnedData[2]; if warned = false then Print("The quotient by the action on the 1-skeleton of the p-torsion subcomplex is "); else Print("As the cell stabilizers do not fix the cells pointwise, \n", "we do not obtain the quotient by the action on the 1-skeleton of the p-torsion subcomplex.\n", " We obtain just some graph, and the latter is "); fi; if Size(incidenceMatrix) = 0 then Print("empty.\n"); fi; if Size(incidenceMatrix) > 0 then Print("displayed in a separate window on screen now.\n"); graphData := StructuralCopy(IncidenceMatrixToGraph(incidenceMatrix)); GraphDisplay(graphData); fi; else Print("The number p must be prime in order to compute the incidence matrix.\n"); fi; end); printIsotropyGroups := function(reducedTorsionCells, celldata) ######################################################### ## Return the stabilizers of the cells in the ## ## reduced torsion subcomplex. ## ######################################################### local G, n, k, j, tcd; tcd := Length(reducedTorsionCells)-1; Print("The following cells and stabilizers represent ", "the reduced torsion subcomplex.\n"); for n in [0..tcd] do for k in [1..Length(reducedTorsionCells[n+1])] do j := reducedTorsionCells[n+1][k][2]; G := celldata[n+1][j]!.TheMatrixStab; if IsFinite(G) then Print(n,"-cell number ",j," has stabilizer ",G,"\n"); Print("of Abelianization ",GroupHomology(G,1),".\n"); fi; od; od; end; getTerminalVertices := function(reducedTorsionCells, celldata) ########################################################################## ## We single out the "terminal" vertices of the p-torsion subcomplex : ## ## Those with exactly one adjacent edge. ## ########################################################################## local examinedVertex, examinedEdge, examinedEdgeData, numberOfAdjacencies, adjacentEdge, reductionCandidates, numberOfTerminalVertices; reductionCandidates:= []; numberOfTerminalVertices := 0; for examinedVertex in reducedTorsionCells[1] do examinedVertex := examinedVertex[2]; numberOfAdjacencies := 0; for examinedEdge in reducedTorsionCells[1+1] do examinedEdgeData := celldata[1+1][examinedEdge[2]]; if examinedVertex in examinedEdgeData!.BoundaryImage!.ListIFace then numberOfAdjacencies := numberOfAdjacencies +1; adjacentEdge := examinedEdge[2]; fi; od; if numberOfAdjacencies = 1 then Print("The vertex number ",examinedVertex," is terminal.\n"); numberOfTerminalVertices := numberOfTerminalVertices +1; reductionCandidates[numberOfTerminalVertices] := [examinedVertex, adjacentEdge]; fi; od; return reductionCandidates; end; checkGruenSwan := function( terminalVertices, celldata, p) ######################################################################### ## Keep only those of the terminal vertices, the stabilizers of which ## ## satisfy the hypotheses of the Gruen/Swan theorem. ## ######################################################################### local boundaryCell, examinedEdge, EdgeStabilizer, boundaryStabilizer, cellPair, n, g, validated, verticesToReduce; verticesToReduce := StructuralCopy( terminalVertices); for cellPair in terminalVertices do boundaryCell := cellPair[1]; examinedEdge := cellPair[2]; EdgeStabilizer := celldata[1+1][examinedEdge]!.TheMatrixStab; boundaryStabilizer := celldata[0+1][boundaryCell]!.TheMatrixStab; g := getIdentifier( [1,examinedEdge], boundaryCell, celldata); EdgeStabilizer := ConjugateGroup(EdgeStabilizer, g); if IsSubset(EdgeStabilizer, boundaryStabilizer) then validated := true; ## in this case, we can clearly cut off the edge ## ## without changing p-primary equivariant Farrell cohomology ## else if IsPnormal( boundaryStabilizer, p) then g := Normalizer(boundaryStabilizer, Center(SylowSubgroup( boundaryStabilizer, p) )); if IsSubset(EdgeStabilizer, g) and IsSubset(g, EdgeStabilizer) then validated := true; else validated := IsInnerConjugate( boundaryStabilizer, EdgeStabilizer, g); fi; ## if firstStabilizer is isomorphic to g, it is proven ## ## that we can cut off the edge ## ## without changing p-primary equivariant Farrell cohomology ## else validated := false; fi; fi; if validated then Print("The terminal vertex ",boundaryCell, " with edge ",examinedEdge," is subject to a reduction.\n"); else RemoveSet(verticesToReduce, cellPair); fi; od; return verticesToReduce; end; InstallGlobalFunction("ReduceTorsionSubcomplex", function(groupName, p) ################################################### local torsionCells, numberOfTorsionCells, celldata, sortedData, stabilizerCardinalities, fusionCandidates, reducedTorsionCells, terminalVertices, warned; sortedData := getTorsionSubcomplex(groupName, p); torsionCells := sortedData[1]; numberOfTorsionCells := sortedData[2]; celldata := sortedData[3]; stabilizerCardinalities := sortedData[4]; warned := sortedData[5]; if warned = false then sortedData := extractPmultipleTorsionCells(torsionCells, numberOfTorsionCells, celldata,stabilizerCardinalities, p); fusionCandidates := pairsIntersection(sortedData, celldata); fusionCandidates := bifurcationFreeCells(fusionCandidates, torsionCells, celldata); fusionCandidates := checkStabilizerConjugacy(fusionCandidates, celldata, p); reducedTorsionCells := mergeCells( celldata, fusionCandidates, torsionCells); terminalVertices := getTerminalVertices(reducedTorsionCells, celldata); terminalVertices := checkGruenSwan( terminalVertices, celldata, p); Print("\n At the following terminal vertices, the adjacent edge can be cut off without changing the equivariant Farrell cohomology : ",terminalVertices,"\n"); printIsotropyGroups(reducedTorsionCells, celldata); fi; # return reducedTorsionCells; end);