Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

563571 views



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

#####################################################################################