GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
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);
InstallGlobalFunction( "GetTorsionSubcomplex", function(C, 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, data,
torsionCells, numberOfTorsionCells, n, j, returnedData, warned, groupname, admissibilityCheck, x, i, b, tmpCell, cell, boundary, groupName;
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;
# Case 1: the input is a group name
if IsString(C) then
groupName:=C;
groupname := Filtered( C, 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);
# Case 2: the input is a variable
else
groupName:=fail;
celldata:=[];
i:=0;
while C!.dimension(i) > 0 do
cell:=[];
for j in [1..C!.dimension(i)] do
if not i=0 then
boundary:=C!.boundary(i,j);
Add(cell,rec(TheMatrixStab :=C!.stabilizer(i,j),
TheRotSubgroup:=C!.stabilizer(i,j),
BoundaryImage :=rec(
ListIFace:=List(boundary,w->AbsInt(w[1])),
ListSign:=List(boundary,w->SignInt(w[1])),
ListElt:=List(boundary,w->C!.elts[w[2]])
)
)
);
else
Add(cell,rec(TheMatrixStab :=C!.stabilizer(i,j),
TheRotSubgroup:=C!.stabilizer(i,j),
BoundaryImage :=rec(
ListIFace:=[],
ListSign:=[],
ListElt:=[]
)
)
);
fi;
od;
Add(celldata,cell);
i:=i+1;
od;
fi;
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];
data:=[];
for i in [1..Length(torsionCells)] do
data[i]:=[];
for x in torsionCells[i] do
Add(data[i],celldata[i][x[2]]);
od;
od;
for j in [2..Size(data)] do
for i in [1..Size(data[j])] do
tmpCell:=StructuralCopy(data[j][i]!.BoundaryImage);
b:=List(tmpCell!.ListIFace,w->Position(torsionCells[j-1], [j-2,w]));
tmpCell!.ListIFace:=b;
data[j][i]!.BoundaryImage:=tmpCell;
od;
od;
torsionCells:=[];
for i in [1..Size(data)] do
torsionCells[i]:=[];
for j in [1..Size(data[i])] do
torsionCells[i][j]:=[i-1,j];
od;
od;
return Objectify(HapTorsionSubcomplex,
rec(
torsion:=p,
groupname:=groupName,
torsionCells:=torsionCells,
celldata:= data,
numberOfTorsionCells:= numberOfTorsionCells,
stabilizerCardinalities:= stabilizerCardinalities,
warned:= warned ));
end);
InstallGlobalFunction("TorsionSubcomplex", function(groupName, p)
############################################
local torsionCells, numberOfTorsionCells, celldata, sortedData, warned, computeIncidenceMatrix;
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;
sortedData := GetTorsionSubcomplex(groupName, p);
torsionCells := sortedData!.torsionCells;
numberOfTorsionCells := sortedData!. numberOfTorsionCells;
celldata := sortedData!.celldata;
warned := sortedData!.warned;
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);
InstallGlobalFunction("ReduceTorsionSubcomplex", function(groupName, p)
#############################I######################
local torsionCells, numberOfTorsionCells, celldata, sortedData, stabilizerCardinalities, fusionCandidates, reducedTorsionCells, groupname,
terminalVertices, warned, extractPmultipleTorsionCells, cellcomplex,
bifurcationFreeCells, pairsIntersection, IsInnerConjugate,
getIdentifier, checkStabilizerConjugacy, mergeCells, printIsotropyGroups, checkGruenSwan, getTerminalVertices, ReduceModP, getTerminalFacets, cutOffCells,
terminalFacets, data, i, x, tmpCell,
N, J, n, j, G, B, b;
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, getCardinals;
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;
#######################################
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]];
return fusionCandidates;
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 IdSmallGroup(ReduceModP(firstStabilizer,p))=IdSmallGroup(ReduceModP(secondStabilizer,p))
and IdSmallGroup(ReduceModP(firstStabilizer,p))=IdSmallGroup(ReduceModP(boundaryStabilizer,p))
then ;
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, b, t1, t2, BI1, BI2, x,y,t01,t02,
i, j, reducedTorsionCells, vcd, mergedBoundary, data, p0, p1, p2, tmpCell, U, V, X;
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;
# Extract the data of torsionCells from original cell data
data:=[];
for i in [1..Length(reducedTorsionCells)] do
data[i]:=[];
for x in reducedTorsionCells[i] do
Add(data[i],celldata[i][x[2]]);
od;
od;
#Print("reducedTorsionCells", reducedTorsionCells,"\n");
#Print("data= ",data,"\n");
for cellTriple in fusionCandidates do
firstCell := cellTriple[1];
secondCell := cellTriple[2];
n := firstCell[1];
boundaryCell := cellTriple[3];
p0:=Position(reducedTorsionCells[n], [n-1,boundaryCell]);
p1:=Position(reducedTorsionCells[n+1], [n,firstCell[2]]);
p2:=Position(reducedTorsionCells[n+1], [n,secondCell[2]]);
# 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]);
Remove(data[n],p0);
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);
t1:=Position(data[n+1][p1]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][1]);
if t1=fail then
t1:=Position(data[n+1][p1]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][2]);
t01:=3-t1;
t2:=Position(data[n+1][p2]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][1]);
t02:=3-t2;
else t2:=Position(data[n+1][p2]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][2]);
fi;
t01:=3-t1;
t02:=3-t2;
BI1:=StructuralCopy(celldata[n+1][firstCell[2]]!.BoundaryImage);
BI2:=StructuralCopy(celldata[n+1][secondCell[2]]!.BoundaryImage);
x:=BI2!.ListElt[t02]*BI2!.ListElt[t01]^-1;
U:=ConjugateGroup(data[n+1][p2]!.TheMatrixStab,(x)^-1);
V:=data[n+1][p1]!.TheMatrixStab;
X:=ConjugateGroup(celldata[n][BI1!.ListIFace[t01]]!.TheMatrixStab,BI1!.ListElt[t01]);
y:=RepresentativeAction(X,U,V);
tmpCell:=rec(ListIFace:=[BI1!.ListIFace[t1],BI2!.ListIFace[t2]],
ListSign:=BI1!.ListSign,
ListElt:=[BI1!.ListElt[t1],y*x*BI2!.ListElt[t2]]
);
data[n+1][p1]!.BoundaryImage:=StructuralCopy(tmpCell);
Remove(data[n+1],p2);
od;
for i in [1..Size(data[2])] do
tmpCell:=StructuralCopy(data[2][i]!.BoundaryImage);
b:=List(tmpCell!.ListIFace,w->Position(reducedTorsionCells[1], [0,w]));
tmpCell!.ListIFace:=b;
data[2][i]!.BoundaryImage:=tmpCell;
od;
reducedTorsionCells:=[];
for i in [1..Size(data)] do
reducedTorsionCells[i]:=[];
for j in [1..Size(data[i])] do
reducedTorsionCells[i][j]:=[i-1,j];
od;
od;
return [reducedTorsionCells, data];
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;
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;
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;
###################################################################
# CUT OFF CELLS PROCESS #
# #
###################################################################
cutOffCells := function(terminalFacets, torsionCells, celldata, n)
####################################################################
## Cut off the n-cells that have a terminal facet which has been ##
## spotted to have the same p-torsion controller. As proven, this ##
## does not change the p-primary equivariant Farrell cohomology. ##
####################################################################
local facet, nCell, reducedTorsionCells, cutnCells, cellPair;
cutnCells := [];
reducedTorsionCells := StructuralCopy( torsionCells);
reducedTorsionCells[n+1] := Set(reducedTorsionCells[n+1]);
reducedTorsionCells[n] := Set(reducedTorsionCells[n]);
for cellPair in terminalFacets do
facet := cellPair[1];
nCell := cellPair[2];
if not nCell in cutnCells then
# Print("The terminal ",n-1,"-cell numero ",facet,
# " is cut against ",n,"-cell numero ",nCell,".\n");
RemoveSet(reducedTorsionCells[n], [n-1,facet]);
RemoveSet(reducedTorsionCells[n+1], [n,nCell]);
cutnCells := Concatenation(cutnCells,[nCell]);
fi;
od;
return reducedTorsionCells;
end;
ReduceModP := function( G, p)
local K, h, H, Q, P;
Q := G;
K := ConjugacyClassesSubgroups(G);
for h in K do
if Size(h)=1 then
H := Representative(h);
if Size(H) > 1 then
if Gcd(Size(H),p) = 1 then
# We pass to the quotient Q in the extension
# 1 -> H -> G -> Q -> 1,
# because H has trivial mod p cohomology.
# Our loop ends up using the normal subgroup H of maximal size,
# because the list K is ordered from small to large.
Q := Image( NaturalHomomorphismByNormalSubgroup( G,H ));
fi;
fi;
fi;
od;
P:=Q;
if IsPNormal(Q,p) then P:=Normalizer(Q,Center(SylowSubgroup(Q,p)));fi;
return P;
end;
getTerminalFacets := function(reducedTorsionCells, celldata, p, n)
##############################################################################
## We single out the "terminal" (n-1)-facets of the p-torsion subcomplex : ##
## Those with exactly one adjacent n-cell. ##
##############################################################################
local examinedncell, examinedFacet, examinedncellData, numberOfAdjacencies,
adjacentncell, reductionCandidates, numberOfTerminalFacets, G, IdGred, H, IdHred;
reductionCandidates:= []; numberOfTerminalFacets := 0;
for examinedFacet in reducedTorsionCells[n] do
examinedFacet := examinedFacet[2];
numberOfAdjacencies := 0;
for examinedncell in reducedTorsionCells[n+1] do
examinedncellData := celldata[n+1][examinedncell[2]];
if examinedFacet in examinedncellData!.BoundaryImage!.ListIFace then
numberOfAdjacencies := numberOfAdjacencies +1;
adjacentncell := examinedncell[2];
fi;
od;
if numberOfAdjacencies = 1 then
G := celldata[n+1][adjacentncell]!.TheMatrixStab;;
IdGred := IdSmallGroup(ReduceModP(G,p));
H := celldata[n][examinedFacet]!.TheMatrixStab;;
IdHred := IdSmallGroup(ReduceModP(H,p));
if IdGred = IdHred then
# Print("The ",n-1,"-facet number ",examinedFacet," is terminal.",
# " Its stabilizer ",IdSmallGroup(H)," is controlled by ", IdHred,
# ". Reduce it against the ",n,"-cell number ",adjacentncell,
# " of stabilizer ",IdSmallGroup(G)," controlled by ",IdGred,".\n");
numberOfTerminalFacets := numberOfTerminalFacets +1;
reductionCandidates[numberOfTerminalFacets] :=
[examinedFacet, adjacentncell];
fi;
fi;
od;
return reductionCandidates;
end;
#############################
sortedData := GetTorsionSubcomplex(groupName, p);
torsionCells := sortedData!.torsionCells;
numberOfTorsionCells := sortedData!. numberOfTorsionCells;
celldata := sortedData!.celldata;
stabilizerCardinalities := sortedData!. stabilizerCardinalities;
warned := sortedData!.warned;
groupname:=sortedData!.groupname;
#Print("Before cutting off: ", torsionCells,"\n");
# torsionCells := reducedTorsionCells;
# numberOfTorsionCells := sortedData[2];
# celldata := sortedData[3];
# stabilizerCardinalities := sortedData[4];
# warned := sortedData[5];
terminalFacets := getTerminalFacets(torsionCells, celldata, p,2);
#Print("terminalFacets ", terminalFacets,"\n");
reducedTorsionCells := cutOffCells(terminalFacets, torsionCells, celldata, 2);
#Print("reducedTorsionCells ", reducedTorsionCells,"\n");
while not terminalFacets = [] do
terminalFacets := getTerminalFacets(reducedTorsionCells, celldata, p,2);
reducedTorsionCells := cutOffCells(terminalFacets, reducedTorsionCells, celldata, 2);
od;
terminalFacets := getTerminalFacets(reducedTorsionCells, celldata, p,1);
reducedTorsionCells := cutOffCells(terminalFacets, reducedTorsionCells, celldata, 1);
while not terminalFacets = [] do
terminalFacets := getTerminalFacets(reducedTorsionCells, celldata, p,1);
reducedTorsionCells := cutOffCells(terminalFacets, reducedTorsionCells, celldata, 1);
od;
#Print("After cutting off: ", reducedTorsionCells,"\n");
#N:=Size(reducedTorsionCells);
#while N>0 do if reducedTorsionCells[N]=[] then #Remove(reducedTorsionCells,N);fi;N:=N-1;od;
# Extract the data of torsionCells from original cell data
data:=[];
for i in [1..Length(reducedTorsionCells)] do
data[i]:=[];
for x in reducedTorsionCells[i] do
Add(data[i],celldata[i][x[2]]);
od;
od;
for i in [1..Size(data[2])] do
tmpCell:=StructuralCopy(data[2][i]!.BoundaryImage);
b:=List(tmpCell!.ListIFace,w->Position(reducedTorsionCells[1], [0,w]));
tmpCell!.ListIFace:=b;
data[2][i]!.BoundaryImage:=tmpCell;
od;
reducedTorsionCells:=[];
for i in [1..Size(data)] do
reducedTorsionCells[i]:=[];
for j in [1..Size(data[i])] do
reducedTorsionCells[i][j]:=[i-1,j];
od;
od;
celldata:=StructuralCopy(data);
#########################End of cutting off cells#################################
##################
# sortedData := gettorsionSubcomplex(groupName, p);
# torsionCells := sortedData[1];
# numberOfTorsionCells := sortedData[2];
# celldata := sortedData[3];
# stabilizerCardinalities := sortedData[4];
# warned := sortedData[5];
torsionCells := reducedTorsionCells;
if warned = false then
sortedData := extractPmultipleTorsionCells(torsionCells,
numberOfTorsionCells, celldata,stabilizerCardinalities, p);
#Print("torsionCells ", torsionCells,"\n");
#Print("stabilizerCardinalities ", stabilizerCardinalities,"\n");
#Print("stabilizerCardinalities ", stabilizerCardinalities,"\n");
fusionCandidates := pairsIntersection(sortedData, celldata);
fusionCandidates := bifurcationFreeCells(fusionCandidates, torsionCells,
celldata);
fusionCandidates := checkStabilizerConjugacy(fusionCandidates, celldata,
p);
while not fusionCandidates=[] do
#Print("fusionCandidates ", fusionCandidates,"\n");
cellcomplex:= mergeCells( celldata, fusionCandidates,
torsionCells);
reducedTorsionCells:=cellcomplex[1];
#Print("reducedTorsionCells ", reducedTorsionCells,"\n");
celldata:=cellcomplex[2];
numberOfTorsionCells:=List([1..Size(reducedTorsionCells)],
i->Size(reducedTorsionCells[i]));
stabilizerCardinalities:=List([1..Size(reducedTorsionCells)],
i->List([1..Size(reducedTorsionCells[i])],j->Order(celldata[i][j]!.TheMatrixStab)));
sortedData := extractPmultipleTorsionCells(reducedTorsionCells,
numberOfTorsionCells, celldata,stabilizerCardinalities, p);
fusionCandidates := pairsIntersection(sortedData, celldata);
fusionCandidates := bifurcationFreeCells(fusionCandidates, torsionCells,
celldata);
fusionCandidates := checkStabilizerConjugacy(fusionCandidates, celldata,
p);
#Print("fusionCandidates: ", fusionCandidates,"\n");
od;
# 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;
N:=Size(celldata);
while N>0 do
if celldata[N]=[] then
Remove(reducedTorsionCells,N);
Remove(celldata,N);
fi;
N:=N-1;
od;
#####################################################################################
return Objectify(HapTorsionSubcomplex,
rec(
torsion:=p,
groupname:=groupname,
torsionCells:=torsionCells,
celldata:= celldata ));
end);
#####################################################################################