1
2
3
4InstallGlobalFunction("IsPNormal", function( G, p)
5#########################################################################
6##  Check if the group G is p-normal for the prime p.                  ##
7## Zassenhaus defines a finite group to be p-normal if the center of   ##
8## one of its Sylow p-groups is the center of every Sylow p-group in   ##
9## which it is contained.                                              ##
10#########################################################################
11local SylowCenter, SylowGroups, N, isPnormal, k, j;
12isPnormal := true;
13
14  SylowGroups := ConjugateSubgroups( G, SylowSubgroup( G, p));
15  N := Size( SylowGroups);
16
17  for j in [1..N] do
18
19	SylowCenter := Center( SylowGroups[j]);
20
21	for k in [1..N] do
22 	  if k <> j then
23
24		if IsSubset(SylowGroups[k], SylowCenter) then
25
26		  if SylowCenter = Center( SylowGroups[k]) then
27			; ## the condition is fulfilled for this pair ##
28		  else
29			isPnormal := false;
30#			Print("The group ",G," is not p-normal.");
31		  fi;
32		fi;
33	  fi;
34	od;
35  od;
36  return isPnormal;
37end);
38
39InstallGlobalFunction("DisplayAvailableCellComplexes", function()
40Exec( Concatenation("ls ",DirectoriesPackageLibrary("HAP")[1]![1], "Perturbations/Gcomplexes/"));
41end);
42
43InstallGlobalFunction( "GetTorsionSubcomplex", function(C, p)
44#####################################################################
45## Here, p is the prime for which to take the torsion subcomplex.  ##
46## We extract the cells the stabilizer of which contains p-torsion.##
47#####################################################################
48local vcd, stabilizerCardinalities, celldata, data, torsionPosition,
49torsionCells, numberOfTorsionCells, n, j, returnedData, warned, groupname, admissibilityCheck, x, i, b, tmpCell, cell, boundary, groupName;
50
51    admissibilityCheck := function(celldata)
52    #########################################################
53    ## A cell complex is admissible in the sense of Brown, ##
54    ## if each cell stabilizer fixes its cell pointwise.   ##
55    ## Additionally,				       ##
56    ## we gather the cardinalities of the stabilizers.     ##
57    #########################################################
58    local stabilizerCardinalities, G, card, n, j, R, vcd, warned;
59       warned := false;
60       stabilizerCardinalities := [];
61       vcd := Length(celldata)-1;
62
63       for n in [0..vcd] do
64	    stabilizerCardinalities[n+1] := [];
65	    for j in [1..Length(celldata[n+1])] do
66	       G :=   celldata[n+1][j]!.TheMatrixStab;
67	       if IsFinite(G) then
68	          card := Order(G);
69	          stabilizerCardinalities[n+1][j] := card;
70	          ## *** Now we have to compare              *** ##
71	          ## *** with the order of "TheRotSubgroup"  *** ##
72	          R := celldata[n+1][j]!.TheRotSubgroup;
73	          if card > Order(R) and warned = false then
74		    Print("****Warning: cell complex not admissible ",
75			    "in the sense of Brown!****\n",
76		    " Torsion subcomplex reduction requires cell subdivision.\n");
77		    warned := true;
78	          fi;
79	       fi;
80	    od;
81       od;
82       return [stabilizerCardinalities, warned];
83   end;
84
85   # Case 1: the input is a group name
86   if IsString(C) then
87   groupName:=C;
88   groupname := Filtered( C, function ( x )
89            return not (x = '(' or x = ')' or x = ',' or x = '[' or x = ']');
90   end );
91   Read(Concatenation( 	DirectoriesPackageLibrary("HAP")[1]![1],
92			"Perturbations/Gcomplexes/",groupname));
93   celldata := StructuralCopy(HAP_GCOMPLEX_LIST);
94
95   # Case 2: the input is a variable
96   else
97       groupName:=fail;
98       celldata:=[];
99       i:=0;
100       while C!.dimension(i) > 0 do
101           cell:=[];
102           for j in [1..C!.dimension(i)] do
103               if not i=0 then
104               boundary:=C!.boundary(i,j);
105               Add(cell,rec(TheMatrixStab :=C!.stabilizer(i,j),
106                           TheRotSubgroup:=C!.stabilizer(i,j),
107                           BoundaryImage :=rec(
108                                 ListIFace:=List(boundary,w->AbsInt(w[1])),
109                                 ListSign:=List(boundary,w->SignInt(w[1])),
110                                 ListElt:=List(boundary,w->C!.elts[w[2]])
111                           )
112                       )
113               );
114               else
115               Add(cell,rec(TheMatrixStab :=C!.stabilizer(i,j),
116                           TheRotSubgroup:=C!.stabilizer(i,j),
117                           BoundaryImage :=rec(
118                                 ListIFace:=[],
119                                 ListSign:=[],
120                                 ListElt:=[]
121                           )
122                       )
123               );
124               fi;
125           od;
126           Add(celldata,cell);
127           i:=i+1;
128       od;
129   fi;
130   vcd := Length(celldata) -1;
131#   Print("Extracting the ",p,"-torsion subcomplex of the ",
132#		vcd,"-dimensional ",groupName,"-cell complex ... \n");
133   returnedData := admissibilityCheck(celldata);
134   stabilizerCardinalities := returnedData[1];
135   warned := returnedData[2];
136   torsionCells := [];
137   numberOfTorsionCells := [];
138   for n in [0..vcd] do
139	torsionCells[n+1] := [];
140	numberOfTorsionCells[n+1] := 0;
141	for j in [1..Length(celldata[n+1])] do
142	   ## Check if the stabilizer contains p-torsion ##
143	   if stabilizerCardinalities[n+1][j] mod p = 0 then
144#		Print("Extracted ",n,"-cell numero ",j,
145#			" of stabilizer cardinality ",
146#			stabilizerCardinalities[n+1][j],".\n");
147		numberOfTorsionCells[n+1]
148			:= numberOfTorsionCells[n+1]+1;
149	        torsionCells[n+1][numberOfTorsionCells[n+1]]
150			:=[n, j];
151	   fi;
152	od;
153   od;
154#   return
155#     [torsionCells, numberOfTorsionCells, celldata, stabilizerCardinalities, warned];
156  data:=[];
157#  Print("torsionCells",torsionCells,"\n");
158  for i in [1..Length(torsionCells)] do
159      data[i]:=[];
160      for x in torsionCells[i] do
161          Add(data[i],celldata[i][x[2]]);
162      od;
163  od;
164for j in [2..Size(data)] do
165  for i in [1..Size(data[j])] do
166      tmpCell:=StructuralCopy(data[j][i]!.BoundaryImage);
167      b:=List(tmpCell!.ListIFace,w->Position(torsionCells[j-1], [j-2,w]));
168      tmpCell!.ListIFace:=b;
169      data[j][i]!.BoundaryImage:=tmpCell;
170  od;
171od;
172  torsionPosition:=torsionCells;
173  torsionCells:=[];
174  for i in [1..Size(data)] do
175     torsionCells[i]:=[];
176     for j in [1..Size(data[i])] do
177         torsionCells[i][j]:=[i-1,j];
178     od;
179  od;
180
181  return Objectify(HapTorsionSubcomplex,
182            rec(
183
184            torsion:=p,
185            groupname:=groupName,
186            torsionCells:=torsionCells,
187            torsionPosition:=torsionPosition,
188            originalData:=celldata,
189            celldata:= data,
190            numberOfTorsionCells:= numberOfTorsionCells,
191            stabilizerCardinalities:= stabilizerCardinalities,
192            warned:= warned ));
193end);
194
195DeclareGlobalFunction("GetTorsionPowerSubcomplex");
196InstallGlobalFunction( "GetTorsionPowerSubcomplex", function(C, p, rk)
197#####################################################################
198## Here, p is the prime for which to take the torsion subcomplex.  ##
199## We extract the cells the stabilizer of which contains p-torsion.##
200#####################################################################
201local vcd, stabilizerCardinalities, celldata, data, torsionPosition,
202torsionCells, numberOfTorsionCells, n, j, returnedData, warned, groupname, admissibilityCheck, x, i, b, tmpCell, cell, boundary, groupName, elementaryAbelianID, G, H, subgroupTypesOfG, numberOfSubgroups;
203
204    admissibilityCheck := function(celldata)
205    #########################################################
206    ## A cell complex is admissible in the sense of Brown, ##
207    ## if each cell stabilizer fixes its cell pointwise.   ##
208    ## Additionally,				       ##
209    ## we gather the cardinalities of the stabilizers.     ##
210    #########################################################
211    local stabilizerCardinalities, G, card, n, j, R, vcd, warned;
212       warned := false;
213       stabilizerCardinalities := [];
214       vcd := Length(celldata)-1;
215
216       for n in [0..vcd] do
217	    stabilizerCardinalities[n+1] := [];
218	    for j in [1..Length(celldata[n+1])] do
219	       G :=   celldata[n+1][j]!.TheMatrixStab;
220	       if IsFinite(G) then
221	          card := Order(G);
222	          stabilizerCardinalities[n+1][j] := card;
223	          ## *** Now we have to compare              *** ##
224	          ## *** with the order of "TheRotSubgroup"  *** ##
225	          R := celldata[n+1][j]!.TheRotSubgroup;
226	          if card > Order(R) and warned = false then
227		    Print("****Warning: cell complex not admissible ",
228			    "in the sense of Brown!****\n",
229		    " Torsion subcomplex reduction requires cell subdivision.\n");
230		    warned := true;
231	          fi;
232	       fi;
233	    od;
234       od;
235       return [stabilizerCardinalities, warned];
236   end;
237
238   # Case 1: the input is a group name
239   if IsString(C) then
240   groupName:=C;
241   groupname := Filtered( C, function ( x )
242            return not (x = '(' or x = ')' or x = ',' or x = '[' or x = ']');
243   end );
244   Read(Concatenation( 	DirectoriesPackageLibrary("HAP")[1]![1],
245			"Perturbations/Gcomplexes/",groupname));
246   celldata := StructuralCopy(HAP_GCOMPLEX_LIST);
247
248   # Case 2: the input is a variable
249   else
250       groupName:=fail;
251       celldata:=[];
252       i:=0;
253       while C!.dimension(i) > 0 do
254           cell:=[];
255           for j in [1..C!.dimension(i)] do
256               if not i=0 then
257               boundary:=C!.boundary(i,j);
258               Add(cell,rec(TheMatrixStab :=C!.stabilizer(i,j),
259                           TheRotSubgroup:=C!.stabilizer(i,j),
260                           BoundaryImage :=rec(
261                                 ListIFace:=List(boundary,w->AbsInt(w[1])),
262                                 ListSign:=List(boundary,w->SignInt(w[1])),
263                                 ListElt:=List(boundary,w->C!.elts[w[2]])
264                           )
265                       )
266               );
267               else
268               Add(cell,rec(TheMatrixStab :=C!.stabilizer(i,j),
269                           TheRotSubgroup:=C!.stabilizer(i,j),
270                           BoundaryImage :=rec(
271                                 ListIFace:=[],
272                                 ListSign:=[],
273                                 ListElt:=[]
274                           )
275                       )
276               );
277               fi;
278           od;
279           Add(celldata,cell);
280           i:=i+1;
281       od;
282   fi;
283   vcd := Length(celldata) -1;
284#   Print("Extracting the ",p,"-torsion subcomplex of the ",
285#		vcd,"-dimensional ",groupName,"-cell complex ... \n");
286   elementaryAbelianID := IdSmallGroup(DirectProduct(List([1..rk], i -> CyclicGroup(p))));
287   returnedData := admissibilityCheck(celldata);
288   stabilizerCardinalities := returnedData[1];
289   warned := returnedData[2];
290   torsionCells := [];
291   numberOfTorsionCells := [];
292   for n in [0..vcd] do
293	torsionCells[n+1] := [];
294	numberOfTorsionCells[n+1] := 0;
295	for j in [1..Length(celldata[n+1])] do
296	   ## Check if the stabilizer contains p-torsion ##
297	   if stabilizerCardinalities[n+1][j] mod p^rk = 0 then
298
299		G := C!.stabilizer(n,j);
300		subgroupTypesOfG := []; numberOfSubgroups := 0;
301		for H in ConjugacyClassesSubgroups(G) do
302			numberOfSubgroups := numberOfSubgroups+1;
303			subgroupTypesOfG[numberOfSubgroups] := IdSmallGroup(Representative(H));
304		od;
305		if IsInt(Position(subgroupTypesOfG,elementaryAbelianID)) then
306
307#			Print("Extracted ",n,"-cell numero ",j,
308#			" of stabilizer cardinality ",
309#			stabilizerCardinalities[n+1][j],".\n");
310			numberOfTorsionCells[n+1]
311				:= numberOfTorsionCells[n+1]+1;
312	        	torsionCells[n+1][numberOfTorsionCells[n+1]]
313				:=[n, j];
314		fi;
315	   fi;
316	od;
317   od;
318#   return
319#     [torsionCells, numberOfTorsionCells, celldata, stabilizerCardinalities, warned];
320  data:=[];
321  for i in [1..Length(torsionCells)] do
322      data[i]:=[];
323      for x in torsionCells[i] do
324          Add(data[i],celldata[i][x[2]]);
325      od;
326  od;
327
328for j in [2..Size(data)] do
329  for i in [1..Size(data[j])] do
330      tmpCell:=StructuralCopy(data[j][i]!.BoundaryImage);
331      b:=List(tmpCell!.ListIFace,w->Position(torsionCells[j-1], [j-2,w]));
332      tmpCell!.ListIFace:=b;
333      data[j][i]!.BoundaryImage:=tmpCell;
334  od;
335od;
336  torsionPosition:=torsionCells;
337  torsionCells:=[];
338  for i in [1..Size(data)] do
339     torsionCells[i]:=[];
340     for j in [1..Size(data[i])] do
341         torsionCells[i][j]:=[i-1,j];
342     od;
343  od;
344
345  return Objectify(HapTorsionSubcomplex,
346            rec(
347
348            torsion:=p,
349            groupname:=groupName,
350            torsionCells:=torsionCells,
351            torsionPosition:=torsionPosition,
352            originalData:=celldata,
353            celldata:= data,
354            numberOfTorsionCells:= numberOfTorsionCells,
355            stabilizerCardinalities:= stabilizerCardinalities,
356            warned:= warned ));
357end);
358
359
360InstallGlobalFunction("TorsionSubcomplex", function(groupName, p)
361############################################
362local torsionCells, numberOfTorsionCells, celldata, sortedData, warned, computeIncidenceMatrix;
363
364
365    computeIncidenceMatrix := function(torsionCells, numberOfTorsionCells, celldata)
366    ########################################################
367    ## The incidence matrix of the 1-skeleton of the      ##
368    ## p-torsion subcomplex is returned by this function. ##
369    ########################################################
370    local incidenceMatrix, j, k, q, endpoints, inverseIndex, ORIGIN, END;
371       incidenceMatrix := [];
372       for j in [1..numberOfTorsionCells[1]] do
373        	incidenceMatrix[j] := [];
374         	for k in [1..numberOfTorsionCells[1]] do
375        		incidenceMatrix[j][k] := 0;
376        	od;
377       od;
378#       Print("The edges in the quotient by the action on the torsion subcomplex are: ");
379       ## Record the indices in the torsion subcomplex of vertices in  ##
380       ## the cell complex, in order to assign the endpoints of an edge##
381       inverseIndex := [];
382       for q in [1..Length(celldata[1])] do
383        	inverseIndex[q] := "error: not a p-torsion vertex";
384       od;
385       for j in [1..numberOfTorsionCells[1]] do
386        	inverseIndex[torsionCells[1][j][2]] := j;
387       od;
388       for q in [1..numberOfTorsionCells[2]] do
389        	endpoints := celldata[2]
390			[torsionCells[2][q][2]]!.BoundaryImage.ListIFace;
391	    ORIGIN := inverseIndex[endpoints[1]];
392	    END    := inverseIndex[endpoints[2]];
393#	    Print([ORIGIN,END]);
394	    incidenceMatrix[ORIGIN][END] := incidenceMatrix[ORIGIN][END] +1;
395	    ## If we do not want to have the incidence matrix symmetric, ##
396	    ## then deactivate the following line. ##
397	    incidenceMatrix[END][ORIGIN] := incidenceMatrix[END][ORIGIN] +1;
398       od;
399#       Print(".\n");
400       return incidenceMatrix;
401    end;
402
403
404	sortedData := GetTorsionSubcomplex(groupName, p);
405	torsionCells := sortedData!.torsionCells;
406	numberOfTorsionCells := sortedData!. numberOfTorsionCells;
407	celldata := sortedData!.celldata;
408	warned := sortedData!.warned;
409	if IsPrime(p) then
410	  sortedData := [computeIncidenceMatrix(torsionCells, numberOfTorsionCells, celldata), warned];
411	else
412	  sortedData := "The number p must be prime in order to compute the incidence matrix.";
413	fi;
414   return
415     sortedData;
416end);
417
418
419
420InstallGlobalFunction("VisualizeTorsionSkeleton", function(groupName, p)
421##################################################
422local incidenceMatrix, graphData, returnedData, warned;
423    returnedData := TorsionSubcomplex(groupName, p);
424    if IsPrime(p) then
425	incidenceMatrix := returnedData[1];
426	warned := returnedData[2];
427	if warned = false then
428#	    Print("The quotient by the action on the 1-skeleton of the p-torsion #subcomplex is ");
429	else
430#	    Print("As the cell stabilizers do not fix the cells pointwise, \n",
431#		"we do not obtain the quotient by the action on the 1-skeleton of the p-#torsion subcomplex.\n",
432#		" We obtain just some graph, and the latter is ");
433	fi;
434	if Size(incidenceMatrix) = 0 then
435		Print("empty.\n");
436	fi;
437	if Size(incidenceMatrix) > 0 then
438#		Print("displayed in a separate window on screen now.\n");
439		graphData := StructuralCopy(IncidenceMatrixToGraph(incidenceMatrix));
440		GraphDisplay(graphData);
441	fi;
442   else
443#Print("The number p must be prime in order to compute the incidence matrix.\n");
444   fi;
445end);
446
447
448
449
450InstallGlobalFunction("ReduceTorsionSubcomplex", function(arg) ## The input arg consists of groupname, p, and optionally a third argument rk,
451#############################I######################
452local torsionCells, numberOfTorsionCells, celldata, sortedData, stabilizerCardinalities, fusionCandidates, reducedTorsionCells, groupname,
453terminaljMinus1cells, warned, extractPmultipleTorsionCells, cellcomplex,
454bifurcationFreeCells, pairsIntersection, groupName, p, rk,
455getIdentifier, checkStabilizerConjugacy, mergeCells, printIsotropyGroups, ReduceModP, getTerminalFacets, cutOffCells,
456terminalFacets, data, i, x, tmpCell,
457N, J, n, j, G, B, b;
458
459groupName:=arg[1];
460p:=arg[2];
461
462extractPmultipleTorsionCells := function(torsionCells, numberOfTorsionCells, celldata,stabilizerCardinalities, p)
463##################################################################
464## Make lists of n-cells of each stabilizer cardinality         ##
465## in the p-torsion subcomplex.                                 ##
466##################################################################
467local vcd, pMultipleTorsionCells, numberOfPmultipleTorsionCells, Pmultiples, PmultipleNumero, m, n, cell, j, getCardinals;
468
469
470getCardinals := function(stabilizerCardinalities, p, n)
471############################################################
472## Extract the cardinalities of n-cell stabilisers        ##
473## containing p-torsion.                                  ##
474############################################################
475local S, m, Cardinals, counter;
476    Cardinals := []; counter := 0;
477    S := stabilizerCardinalities[n+1];
478    for m in S do
479	if m mod p = 0 then
480	  if counter > 0 then
481	    if m in Cardinals then ;
482	    else
483		  counter := counter +1;
484		  Cardinals[counter] := m;
485	    fi;
486	  else counter := 1;
487	       Cardinals[counter] := m;
488	  fi;
489	fi;
490    od;
491    return Cardinals;
492end;
493#######################################
494
495
496  vcd := Length(celldata) -1;
497  pMultipleTorsionCells := [];
498  numberOfPmultipleTorsionCells := [];
499  Pmultiples := [];
500
501  for n in [0..vcd] do
502
503    pMultipleTorsionCells[n+1] := [];
504    numberOfPmultipleTorsionCells[n+1] := [];
505    Pmultiples[n+1] := getCardinals(stabilizerCardinalities, p, n);
506    PmultipleNumero := 0;
507
508    for m in Pmultiples[n+1] do
509
510      PmultipleNumero := PmultipleNumero +1;
511      numberOfPmultipleTorsionCells[n+1][PmultipleNumero] := 0;
512      pMultipleTorsionCells[n+1][PmultipleNumero] := [];
513
514      for cell in torsionCells[n+1] do
515
516 	## Check if the stabilizer contains p-torsion of multiple m ##
517
518
519	if stabilizerCardinalities[n+1][cell[2]] = m then
520
521	  numberOfPmultipleTorsionCells[n+1] :=
522		numberOfPmultipleTorsionCells[n+1] +1;
523 	  pMultipleTorsionCells[n+1][PmultipleNumero]
524		[numberOfPmultipleTorsionCells[n+1][PmultipleNumero]] :=
525		cell;
526	fi;
527      od;
528#      Print("There are ",numberOfPmultipleTorsionCells[n+1][PmultipleNumero],
529#		" orbits of ",n,"-cells in the ",p,"-torsion subcomplex",
530#		", the stabilizers of which are of cardinality ",m,
531#		", namely the ones numero "
532#	);
533      for j in [1..Length(pMultipleTorsionCells[n+1][PmultipleNumero])-1] do
534#	    Print(pMultipleTorsionCells[n+1][PmultipleNumero][j][2],", ");
535      od;
536#      Print(pMultipleTorsionCells[n+1][PmultipleNumero][
537#	Length(pMultipleTorsionCells[n+1][PmultipleNumero])][2],".\n");
538    od;
539  od;
540  return [pMultipleTorsionCells, Pmultiples];
541end;
542
543pairsIntersection := function(sortedData, celldata)
544#########################################################################
545## We establish a preliminary list of cell triples as candidates for   ##
546## fusions, consisting of a pair of n-cells that admits precisely      ##
547## one adjacent (n-1)-cell in common.                                  ##
548## This pair and their common boundary cell constitute our cell triple.##
549#########################################################################
550local pMultipleTorsionCells, Pmultiples, n, j, f, s, vcd, fusionCandidates,
551numberOfFusionCandidates, firstCell, secondCell, commonBoundary;
552  pMultipleTorsionCells := sortedData[1];
553  Pmultiples := sortedData[2];
554  vcd := Length(celldata) -1;
555  fusionCandidates := [];
556  numberOfFusionCandidates := 0;
557
558  for n in [0..vcd] do
559    for j in [1..Length(Pmultiples[n+1])] do
560      for f in [1..Length(pMultipleTorsionCells[n+1][j])] do
561	firstCell := pMultipleTorsionCells[n+1][j][f];
562        for s in [f+1..Length(pMultipleTorsionCells[n+1][j])] do
563	  secondCell := pMultipleTorsionCells[n+1][j][s];
564	  commonBoundary :=
565		Set(celldata[n+1][firstCell[2]]!.BoundaryImage!.ListIFace);
566	  IntersectSet( commonBoundary,
567	    Set(celldata[n+1][secondCell[2]]!.BoundaryImage!.ListIFace)
568	  );
569
570	  if Size(commonBoundary)=1  then
571#	    Print("The boundary of ",n,"-cell numero ",firstCell[2]," is ",
572#	      celldata[n+1][firstCell[2]]!.BoundaryImage!.ListIFace,
573#	      " and that of ",n,"-cell numero ",secondCell[2]," is ",
574#	      celldata[n+1][secondCell[2]]!.BoundaryImage!.ListIFace,
575#	      " so they have ",n-1,"-cell numero ",commonBoundary[1],
576#		" in common.\n");
577	    numberOfFusionCandidates := numberOfFusionCandidates +1;
578	    fusionCandidates[numberOfFusionCandidates] :=
579	      [firstCell, secondCell, commonBoundary[1]];
580              return fusionCandidates;
581	  fi;
582        od;
583      od;
584    od;
585  od;
586  return fusionCandidates;
587end;
588
589
590bifurcationFreeCells := function(fusionCandidates, torsionCells, celldata)
591##########################################################################
592## We keep only those cell triples as candidates for a fusion,          ##
593## that are not "bifurcated" in the p-torsion subcomplex :              ##
594## Triples such that only n-cells adjacent to the (n-1)-cell            ##
595## of the triple are the two n-cells of the triple.                     ##
596##########################################################################
597local firstCell, secondCell, boundaryCell, cellTriple, n, cell, torsionCell,
598remainingFusionCandidates;
599remainingFusionCandidates := Set(StructuralCopy(fusionCandidates));
600
601  for cellTriple in fusionCandidates do
602
603    firstCell := cellTriple[1];
604    secondCell := cellTriple[2];
605    n := firstCell[1];
606    boundaryCell := cellTriple[3];
607
608      for torsionCell in torsionCells[n+1] do
609
610	cell := celldata[n+1][torsionCell[2]];
611
612	if boundaryCell in cell!.BoundaryImage!.ListIFace then
613
614	  if torsionCell in [firstCell, secondCell] then ;
615	  	# the cell triple remains a candidate for fusion.
616	  else
617#		Print("The p-torsion subcomplex is bifurcated at the ",
618#			n-1,"-cell numero ",boundaryCell,".\n");
619	  	RemoveSet(remainingFusionCandidates, cellTriple);
620	  fi;
621	fi;
622      od;
623  od;
624  return remainingFusionCandidates;
625end;
626
627
628getIdentifier := function( cell, boundaryCell, celldata)
629##############################################################
630## Retrieve the group element sending the cell to           ##
631## a representative that is adjacent to the boundary cell.  ##
632##############################################################
633local n, boundaryIndex, j, identifiers, g;
634    n := cell[1];
635    identifiers := celldata[n+1][cell[2]]!.BoundaryImage!.ListElt;
636
637    for j in [1..Length(identifiers)] do
638
639      if celldata[n+1][cell[2]]!.BoundaryImage!.ListIFace[j]
640	 = boundaryCell then
641
642		boundaryIndex := j;
643      fi;
644    od;
645    g := celldata[n+1][cell[2]]!.BoundaryImage!.ListElt[boundaryIndex];
646  return g;
647end;
648
649
650checkStabilizerConjugacy := function(fusionCandidates, celldata, p)
651##################################################################
652## Eliminate cell triples from the fusion candidates list,      ##
653## for which the stabilizers of the n-cells are not conjugate.  ##
654## Therefore, we first conjugate the stabilizers of the n-cells ##
655## into stabilizers of representatives                          ##
656## adjacent to the (n-1)-cell.                                  ##
657## Then we check if we can conjugate them within the stabilizer ##
658## of the (n-1)-cell.     					##
659##################################################################
660local firstCell, secondCell, boundaryCell, firstStabilizer, secondStabilizer, boundaryStabilizer, cellTriple, n, g, validated, remainingFusionCandidates, controllingGroupID;
661remainingFusionCandidates := StructuralCopy(fusionCandidates);
662
663  for cellTriple in fusionCandidates do
664
665    firstCell := cellTriple[1];
666    secondCell := cellTriple[2];
667    n := firstCell[1];
668    boundaryCell := cellTriple[3];
669    firstStabilizer := celldata[n+1][firstCell[2]]!.TheMatrixStab;
670    secondStabilizer := celldata[n+1][secondCell[2]]!.TheMatrixStab;
671    boundaryStabilizer := celldata[n][boundaryCell]!.TheMatrixStab;
672    g := getIdentifier( firstCell, boundaryCell, celldata);
673    firstStabilizer := ConjugateGroup(firstStabilizer, g);
674    g := getIdentifier( secondCell, boundaryCell, celldata);
675    secondStabilizer := ConjugateGroup(secondStabilizer, g);
676    controllingGroupID := IdSmallGroup(ReduceModP(firstStabilizer,p));
677
678    if controllingGroupID =IdSmallGroup(ReduceModP(secondStabilizer,p))
679   and controllingGroupID =IdSmallGroup(ReduceModP(boundaryStabilizer,p))
680       then ;
681        else RemoveSet(remainingFusionCandidates, cellTriple);
682    fi;
683  od;
684  return remainingFusionCandidates;
685end;
686
687
688mergeCells := function( celldata, fusionCandidates, torsionCells)
689####################################################################
690## Merge the cells in that have been definitively retained        ##
691## as fusion candidates. As proven, this does not change 	  ##
692## the p-primary equivariant Farrell cohomology.		  ##
693####################################################################
694local firstCell, secondCell, boundaryCell, cellTriple, n, b, t1, t2, BI1, BI2, x,y,t01,t02,
695      i, j, reducedTorsionCells, vcd, mergedBoundary, data, p0, p1, p2, tmpCell, U, V, X;
696  mergedBoundary := [];
697  reducedTorsionCells := StructuralCopy( torsionCells);
698  vcd := Length(reducedTorsionCells) -1;
699  for n in [0..vcd] do
700	reducedTorsionCells[n+1] := Set(reducedTorsionCells[n+1]);
701	mergedBoundary[n+1] := [];
702  od;
703
704  # Extract the data of torsionCells from original cell data
705  data:=[];
706  for i in [1..Length(reducedTorsionCells)] do
707      data[i]:=[];
708      for x in reducedTorsionCells[i] do
709          Add(data[i],celldata[i][x[2]]);
710      od;
711  od;
712#Print("reducedTorsionCells", reducedTorsionCells,"\n");
713#Print("data= ",data,"\n");
714  for cellTriple in fusionCandidates do
715
716    firstCell := cellTriple[1];
717    secondCell := cellTriple[2];
718    n := firstCell[1];
719    boundaryCell := cellTriple[3];
720    p0:=Position(reducedTorsionCells[n], [n-1,boundaryCell]);
721    p1:=Position(reducedTorsionCells[n+1], [n,firstCell[2]]);
722    p2:=Position(reducedTorsionCells[n+1], [n,secondCell[2]]);
723
724#    Print("The ",n-1,"-cell numero ",boundaryCell,
725#	" is amalgamated into the merging ",n,"-cells numero ",
726#	firstCell[2]," and ",secondCell[2],".\n");
727    RemoveSet(reducedTorsionCells[n], [n-1,boundaryCell]);
728    Remove(data[n],p0);
729    mergedBoundary[n+1][firstCell[2]] := Set(Concatenation(
730	celldata[n+1][firstCell[2]]!.BoundaryImage!.ListIFace,
731	celldata[n+1][secondCell[2]]!.BoundaryImage!.ListIFace
732    ));
733
734    RemoveSet(mergedBoundary[n+1][firstCell[2]], boundaryCell);
735    t1:=Position(data[n+1][p1]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][1]);
736    if t1=fail then
737        t1:=Position(data[n+1][p1]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][2]);
738        t01:=3-t1;
739        t2:=Position(data[n+1][p2]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][1]);
740        t02:=3-t2;
741    else t2:=Position(data[n+1][p2]!. BoundaryImage!.ListIFace,mergedBoundary[n+1][firstCell[2]][2]);
742    fi;
743    t01:=3-t1;
744    t02:=3-t2;
745    BI1:=StructuralCopy(celldata[n+1][firstCell[2]]!.BoundaryImage);
746    BI2:=StructuralCopy(celldata[n+1][secondCell[2]]!.BoundaryImage);
747
748
749    x:=BI2!.ListElt[t02]*BI2!.ListElt[t01]^-1;
750    U:=ConjugateGroup(data[n+1][p2]!.TheMatrixStab,(x)^-1);
751    V:=data[n+1][p1]!.TheMatrixStab;
752    X:=ConjugateGroup(celldata[n][BI1!.ListIFace[t01]]!.TheMatrixStab,BI1!.ListElt[t01]);
753    y:=RepresentativeAction(X,U,V);
754    tmpCell:=rec(ListIFace:=[BI1!.ListIFace[t1],BI2!.ListIFace[t2]],
755                        ListSign:=BI1!.ListSign,
756                        ListElt:=[BI1!.ListElt[t1],y*x*BI2!.ListElt[t2]]
757    );
758    data[n+1][p1]!.BoundaryImage:=StructuralCopy(tmpCell);
759    Remove(data[n+1],p2);
760  od;
761  for i in [1..Size(data[2])] do
762      tmpCell:=StructuralCopy(data[2][i]!.BoundaryImage);
763      b:=List(tmpCell!.ListIFace,w->Position(reducedTorsionCells[1], [0,w]));
764      tmpCell!.ListIFace:=b;
765      data[2][i]!.BoundaryImage:=tmpCell;
766  od;
767  reducedTorsionCells:=[];
768  for i in [1..Size(data)] do
769     reducedTorsionCells[i]:=[];
770     for j in [1..Size(data[i])] do
771         reducedTorsionCells[i][j]:=[i-1,j];
772     od;
773  od;
774  return [reducedTorsionCells, data];
775end;
776
777
778printIsotropyGroups := function(reducedTorsionCells, celldata)
779#########################################################
780## Return the stabilizers of the cells in the          ##
781## reduced torsion subcomplex.                         ##
782#########################################################
783local G, n, k, j, tcd;
784   tcd := Length(reducedTorsionCells)-1;
785   Print("The following cells and stabilizers represent ",
786		"the reduced torsion subcomplex.\n");
787
788   for n in [0..tcd] do
789     for k in [1..Length(reducedTorsionCells[n+1])] do
790	j := reducedTorsionCells[n+1][k][2];
791	G :=   celldata[n+1][j]!.TheMatrixStab;
792	if IsFinite(G) then
793		Print(n,"-cell number ",j," has stabilizer ",G,"\n");
794		Print("of Abelianization ",GroupHomology(G,1),".\n");
795	fi;
796     od;
797   od;
798end;
799
800
801###################################################################
802#                       CUT OFF CELLS PROCESS                     #
803#                                                                 #
804###################################################################
805cutOffCells := function(terminalFacets, torsionCells, celldata, n)
806####################################################################
807## Cut off the n-cells that have a terminal facet which has been  ##
808## spotted to have the same p-torsion controller. As proven, this ##
809## does not change the p-primary equivariant Farrell cohomology.  ##
810####################################################################
811local facet, nCell, reducedTorsionCells, cutnCells, cellPair;
812
813  cutnCells := [];
814  reducedTorsionCells := StructuralCopy( torsionCells);
815  reducedTorsionCells[n+1] := Set(reducedTorsionCells[n+1]);
816  reducedTorsionCells[n] := Set(reducedTorsionCells[n]);
817
818  for cellPair in terminalFacets do
819
820    facet := cellPair[1];
821    nCell := cellPair[2];
822    if not nCell in cutnCells then
823#    	Print("The terminal ",n-1,"-cell numero ",facet,
824#	" is cut against ",n,"-cell numero ",nCell,".\n");
825    	RemoveSet(reducedTorsionCells[n], [n-1,facet]);
826    	RemoveSet(reducedTorsionCells[n+1], [n,nCell]);
827	cutnCells := Concatenation(cutnCells,[nCell]);
828    fi;
829  od;
830#  Print("Length of reducedTorsionCells after cut off ",n,"-cells",List(reducedTorsionCells,i->Length(i)),"\n");
831  return reducedTorsionCells;
832end;
833
834
835ReduceModP := function( G, p)
836local K, h, H, Q, P;
837
838	Q := G;
839	K := ConjugacyClassesSubgroups(G);
840	for h in K do
841          if Size(h)=1 then
842	       H := Representative(h);
843	           if Size(H) > 1 then
844	     	       if Gcd(Size(H),p) = 1 then
845            	       # We pass to the quotient Q in the extension
846		       # 1 -> H -> G -> Q -> 1,
847		       # because H has trivial mod p cohomology.
848		       # Our loop ends up using the normal subgroup H of maximal size,
849		       # because the list K is ordered from small to large.
850		           Q := Image( NaturalHomomorphismByNormalSubgroup( G,H ));
851	              fi;
852	           fi;
853	    fi;
854	od;
855       P:=Q;
856       if IsPNormal(Q,p) then P:=Normalizer(Q,Center(SylowSubgroup(Q,p)));fi;
857  return P;
858end;
859
860getTerminalFacets := function(reducedTorsionCells, celldata, p, n)
861##############################################################################
862## We single out the "terminal" (n-1)-facets of the p-torsion subcomplex :  ##
863## Those with exactly one adjacent n-cell.                                  ##
864##############################################################################
865local examinedncell, examinedFacet, examinedncellData, numberOfAdjacencies,
866	adjacentncell, reductionCandidates, numberOfTerminalFacets, G, IdGred, H, IdHred,
867  nplus1cell;
868  reductionCandidates:= []; numberOfTerminalFacets := 0;
869
870  for examinedFacet in reducedTorsionCells[n] do
871
872    examinedFacet := examinedFacet[2];
873    numberOfAdjacencies := 0;
874
875    for examinedncell in reducedTorsionCells[n+1] do
876	examinedncellData := celldata[n+1][examinedncell[2]];
877
878	if examinedFacet in examinedncellData!.BoundaryImage!.ListIFace then
879
880	  numberOfAdjacencies := numberOfAdjacencies +1;
881	  adjacentncell := examinedncell[2];
882	fi;
883    od;
884    if numberOfAdjacencies = 1 then
885        nplus1cell:=0;
886        if IsBound(reducedTorsionCells[n+2]) then
887         for examinedncell in reducedTorsionCells[n+2] do
888             examinedncellData := celldata[n+2][examinedncell[2]];
889             if adjacentncell in examinedncellData!.BoundaryImage!.ListIFace then
890                 nplus1cell := nplus1cell +1;
891             fi;
892          od;
893        fi;
894        if nplus1cell=0 then
895	        G := celldata[n+1][adjacentncell]!.TheMatrixStab;;
896	        IdGred := IdSmallGroup(ReduceModP(G,p));
897	        H := celldata[n][examinedFacet]!.TheMatrixStab;;
898	        IdHred := IdSmallGroup(ReduceModP(H,p));
899#	     Print("The ",n-1,"-facet number ",examinedFacet," is terminal.",
900#		" Its stabilizer ",IdSmallGroup(H)," is controlled by ", IdHred,
901#		". It is adjacent to the ",n,"-cell number ",adjacentncell,
902#		" of stabilizer ",IdSmallGroup(G)," controlled by ",IdGred,".\n");
903	         if IdGred = IdHred then
904#	     Print("Reduce it against the adjacent ",n,"-cell number ",adjacentncell,
905#		" of stabilizer ",IdSmallGroup(G)," controlled by ",IdGred,".\n");
906		           numberOfTerminalFacets := numberOfTerminalFacets +1;
907		           reductionCandidates[numberOfTerminalFacets] :=
908				       [examinedFacet, adjacentncell];
909	          fi;
910         fi;
911      fi;
912  od;
913#Print("Reduction Candidates of dimension",n,"    ",reductionCandidates,"\n");
914  return reductionCandidates;
915end;
916#############################
917   if Length(arg)=2 then
918     sortedData := GetTorsionSubcomplex(groupName, p);
919   else
920	rk := arg[3];
921        sortedData := GetTorsionPowerSubcomplex(groupName, p, rk);
922   fi;
923   torsionCells := sortedData!.torsionCells;
924   numberOfTorsionCells := sortedData!. numberOfTorsionCells;
925   celldata := sortedData!.celldata;
926   stabilizerCardinalities := sortedData!. stabilizerCardinalities;
927   warned := sortedData!.warned;
928   groupname:=sortedData!.groupname;
929#   originalData:=sortedData!.originalData;
930#Print("Before cutting off: ", torsionCells,"\n");
931#   torsionCells := reducedTorsionCells;
932#   numberOfTorsionCells := sortedData[2];
933#   celldata := sortedData[3];
934#   stabilizerCardinalities := sortedData[4];
935#   warned := sortedData[5];
936N:=1;
937while IsBound(torsionCells[N]) and (not IsEmpty(torsionCells[N])) do
938	N:=N+1;
939od;
940N:=N-2;
941j:=N;
942
943reducedTorsionCells :=StructuralCopy(torsionCells);
944while j>0 do
945#Print("Dimension ",j,"\n");
946terminalFacets := getTerminalFacets(reducedTorsionCells, celldata, p,j);
947
948while not terminalFacets = [] do
949	reducedTorsionCells := cutOffCells(terminalFacets, reducedTorsionCells, celldata, j);
950	terminalFacets := getTerminalFacets(reducedTorsionCells, celldata, p,j);
951od;
952
953j:=j-1;
954od;
955
956  # Extract the data of torsionCells from original cell data
957  data:=[];
958  for i in [1..Length(reducedTorsionCells)] do
959      data[i]:=[];
960      for x in reducedTorsionCells[i] do
961          Add(data[i],celldata[i][x[2]]);
962      od;
963  od;
964#Print("reducedTorsionCells",reducedTorsionCells,"\n");
965  for j in [2..Length(data)] do
966    for i in [1..Size(data[j])] do
967      tmpCell:=StructuralCopy(data[j][i]!.BoundaryImage);
968      b:=List(tmpCell!.ListIFace,w->Position(reducedTorsionCells[j-1], [j-2,w]));
969      tmpCell!.ListIFace:=b;
970      data[j][i]!.BoundaryImage:=tmpCell;
971    od;
972  od;
973  reducedTorsionCells:=[];
974  for i in [1..Size(data)] do
975     reducedTorsionCells[i]:=[];
976     for j in [1..Size(data[i])] do
977         reducedTorsionCells[i][j]:=[i-1,j];
978     od;
979  od;
980#  originalData:=celldata;
981  celldata:=StructuralCopy(data);
982#########################End of cutting off cells#################################
983
984 torsionCells := reducedTorsionCells;
985
986 if warned = false then
987   sortedData := extractPmultipleTorsionCells(torsionCells,
988		numberOfTorsionCells, celldata,stabilizerCardinalities, p);
989#Print("torsionCells  ", torsionCells,"\n");
990#Print("stabilizerCardinalities  ", stabilizerCardinalities,"\n");
991#Print("stabilizerCardinalities  ", stabilizerCardinalities,"\n");
992
993   fusionCandidates := pairsIntersection(sortedData, celldata);
994   fusionCandidates := bifurcationFreeCells(fusionCandidates, torsionCells,
995						 celldata);
996   fusionCandidates := checkStabilizerConjugacy(fusionCandidates, celldata,
997						p);
998   while not fusionCandidates=[] do
999
1000#Print("fusionCandidates  ", fusionCandidates,"\n");
1001   cellcomplex:= mergeCells( celldata, fusionCandidates,
1002					torsionCells);
1003    reducedTorsionCells:=cellcomplex[1];
1004#Print("reducedTorsionCells  ", reducedTorsionCells,"\n");
1005    celldata:=cellcomplex[2];
1006    numberOfTorsionCells:=List([1..Size(reducedTorsionCells)],
1007             i->Size(reducedTorsionCells[i]));
1008    stabilizerCardinalities:=List([1..Size(reducedTorsionCells)],
1009             i->List([1..Size(reducedTorsionCells[i])],j->Order(celldata[i][j]!.TheMatrixStab)));
1010    sortedData := extractPmultipleTorsionCells(reducedTorsionCells,
1011		numberOfTorsionCells, celldata,stabilizerCardinalities, p);
1012    fusionCandidates := pairsIntersection(sortedData, celldata);
1013   fusionCandidates := bifurcationFreeCells(fusionCandidates, torsionCells,
1014						 celldata);
1015   fusionCandidates := checkStabilizerConjugacy(fusionCandidates, celldata,
1016						p);
1017#Print("fusionCandidates:  ", fusionCandidates,"\n");
1018    od;
1019#   terminaljMinus1cells := getterminaljMinus1cells(reducedTorsionCells, celldata);
1020#   terminaljMinus1cells := checkGruenSwan( terminaljMinus1cells, celldata, p);
1021#Print("\n At the following terminal vertices, the adjacent edge can be cut off without #changing the equivariant Farrell cohomology : ",terminaljMinus1cells,"\n");
1022#   printIsotropyGroups(reducedTorsionCells, celldata);
1023 fi;
1024
1025N:=Size(celldata);
1026while N>0 do
1027    if  celldata[N]=[] then
1028        Remove(reducedTorsionCells,N);
1029        Remove(celldata,N);
1030    fi;
1031    N:=N-1;
1032od;
1033
1034#####################################################################################
1035
1036
1037  return Objectify(HapTorsionSubcomplex,
1038            rec(
1039
1040            torsion:=p,
1041            groupname:=groupname,
1042            torsionCells:=torsionCells,
1043#            originalData:=data,
1044            celldata:= celldata ));
1045
1046end);
1047
1048#####################################################################################
1049