1#############################################################################
2##
3#W plane_isomorphisms.gi 			 RDS Package		 Marc Roeder
4##
5##  Methods for calculations with projective planes
6##
7##
8#Y	 Copyright (C) 2006-2011 Marc Roeder
9#Y
10#Y This program is free software; you can redistribute it and/or
11#Y modify it under the terms of the GNU General Public License
12#Y as published by the Free Software Foundation; either version 2
13#Y of the License, or (at your option) any later version.
14#Y
15#Y This program is distributed in the hope that it will be useful,
16#Y but WITHOUT ANY WARRANTY; without even the implied warranty of
17#Y MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18#Y GNU General Public License for more details.
19#Y
20#Y You should have received a copy of the GNU General Public License
21#Y along with this program; if not, write to the Free Software
22#Y Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23##
24##############################################################################
25###
26##O  DualPlane( <plane> )  generate dual plane
27###
28#InstallMethod(DualPlane,
29#        "for projective planes",
30#        [IsRecord],
31#        function(plane)
32#    local   points,  returnblocks,  image,  p,  locblocks,  dualblock;
33#    if not IsBlockDesign(plane)
34#       then
35#        Error("projective plane must be a block design");
36#    fi;
37#    points:=[1..plane.v];
38#    returnblocks:=[];
39#    image:=ListWithIdenticalEntries(Size(points),0);;
40#    for p in points
41#      do
42#        locblocks:=Filtered(blocks,b->p in b);
43#        dualblock:=Set(locblocks,b->Position(blocks,b));
44#        Add(returnblocks,dualblock);
45#        image[p]:=dualblock;
46#    od;
47#    return rec(blocks:=Set(returnblocks),image:=image);;
48#end);
49#
50#############################################################################
51##
52#O ProjectiveClosureOfPointSet(<points>,<plane>)
53##
54InstallMethod(ProjectiveClosureOfPointSet,
55        "for projective planes",
56        [IsDenseList,IsRecord],
57        function(points,plane)
58    return ProjectiveClosureOfPointSet(points,0,plane);
59end);
60
61#############################################################################
62##
63#O ProjectiveClosureOfPointSet(<points>,<maxsize>,<plane>)
64##
65InstallMethod(ProjectiveClosureOfPointSet,
66        "for projective planes",
67        [IsDenseList,IsInt,IsRecord],
68        function(points,maxsize,plane)
69    local   newpoints,  oldpoints,  newblocks,  oldblocks,
70            returnplane,  embedding,  invemb;
71
72    if not IsProjectivePlane(plane)
73       then
74        TryNextMethod();
75    fi;
76    newpoints:=[];
77    oldpoints:=Set(points);
78    newblocks:=Set(Combinations(oldpoints,2),i->plane.jblock[i[1]][i[2]]);
79    oldblocks:=[];
80    if maxsize=0
81       then
82        maxsize:=plane.v-1;
83    fi;
84    repeat
85        newpoints:=Set(Cartesian(oldblocks,newblocks),i->Intersection(plane.blocks[i[1]],plane.blocks[i[2]])[1]);
86        UniteSet(newpoints,List(Combinations(newblocks,2),i->Intersection(plane.blocks[i[1]],plane.blocks[i[2]])[1]));
87        SubtractSet(newpoints,oldpoints);
88        UniteSet(oldblocks,newblocks);
89        newblocks:=Set(Cartesian(oldpoints,newpoints),i->plane.jblock[i[1]][i[2]]);
90        UniteSet(newblocks,List(Combinations(newpoints,2),i->plane.jblock[i[1]][i[2]]));
91        SubtractSet(newblocks,oldblocks);
92        UniteSet(oldpoints,newpoints);
93    until newpoints=[] or newblocks=[] or Size(oldpoints)>maxsize;
94
95    if Size(oldpoints)>maxsize
96       then
97        oldpoints:=[1..plane.v];
98    fi;
99    if oldpoints=[1..plane.v]
100       then
101        returnplane:=plane;
102        embedding:=();
103    elif Size(oldpoints)=1
104      then
105        embedding:=(1,oldpoints[1]);
106        returnplane:=BlockDesign(1,[[1]]);
107    else
108        newblocks:=Set(plane.blocks,i->Intersection(i,oldpoints));
109        newblocks:=Filtered(newblocks,i->Size(i)>1);
110        embedding:=MappingPermListList([1..Size(oldpoints)],Set(oldpoints));
111        invemb:=embedding^-1;
112        Apply(newblocks,i->OnSets(i,invemb));
113        if Number(newblocks,b->Size(b)>2)<7
114           then
115            returnplane:=BlockDesign(Size(oldpoints),newblocks);
116        else
117            newblocks:=Filtered(newblocks,i->Size(i)>2);
118            returnplane:=ProjectivePlane(newblocks);
119            if IsBound(plane.jpoint)
120               then
121                PointJoiningLinesProjectivePlane(returnplane);
122            fi;
123        fi;
124    fi;
125    if IsBound(plane.pointNames)
126       then
127        returnplane.pointNames:=Immutable(List([1..returnplane.v],i->
128                                        plane.pointNames[i^embedding]));
129    fi;
130    return rec(closure:=returnplane,embedding:=embedding);
131end);
132
133
134#############################################################################
135##
136#O  IsIsomorphismOfProjectivePlanes( <perm>,<plane1>,<plane2> )  test for isomorphism of projective planes.
137##
138InstallMethod(IsIsomorphismOfProjectivePlanes,
139        "for projective planes",
140        [IsPerm,IsRecord,IsRecord],
141        function(perm,plane1,plane2)
142    local   points,  point,  pointblocks,  pointblocks_image;
143
144    if not IsBlockDesign(plane1) and IsBlockDesign(plane2)
145       then
146        Error("this does just work for block designs");
147    fi;
148    points:=[1..plane1.v];
149    return ForAll(plane1.blocks,b->OnSets(b,perm) in plane2.blocks);
150end);
151
152
153#############################################################################
154##
155#O  IsCollineationOfProjectivePlane( <perm>,<plane> )  test if a permutation is a collineation of a projective plane
156##
157InstallMethod(IsCollineationOfProjectivePlane,
158        "for projective planes",
159        [IsPerm,IsRecord],
160        function(perm,plane)
161    return IsIsomorphismOfProjectivePlanes(perm,plane,plane);
162end);
163
164
165#############################################################################
166##
167#O  ElationByPair( <centre>,<axis>,<pair>,<plane>)  calculate elations of projective planes.
168##
169InstallMethod(ElationByPair,
170        "for projective planes",
171        [IsInt,IsVector,IsVector,IsRecord],
172        function(centre,axis,pair,plane)
173    local   points,  blockslist,  axispos,  init_cblocks,  axispoints,
174            returnlist,  permlist,  cblocks,  projpairs,  pairblock,
175            point,  pblock1,  pblock2,  cblock,  x,  y,  cblockpair,
176            nogood,  ppair,  perm;
177
178    if not IsProjectivePlane(plane)
179       then
180        Error("this is not a projective plane");
181    fi;
182
183    if not IsBound(plane.jpoint)
184       then
185        TryNextMethod();
186    fi;
187
188    points:=[1..plane.v];
189
190    if not IsSubset(points,pair)
191       then
192        Error("<pair> must be a pair of points");
193    fi;
194
195    if not axis in plane.blocks
196       then
197        Error("The axis must be a block");
198    fi;
199    blockslist:=[1..plane.v];
200    axispos:=Position(plane.blocks,axis);
201
202    init_cblocks:=Difference(Set(plane.jblock[centre]),[0]);
203    RemoveSet(init_cblocks,axispos);
204
205    axispoints:=Difference(axis,[centre]);
206
207    returnlist:=[];
208
209    if Intersection(pair,axis)<>[]
210       then
211        Error("The axis must be fixed pointwise");
212    fi;
213    permlist:=[1..plane.v];
214    cblocks:=ShallowCopy(init_cblocks);
215    projpairs:=[];
216    pairblock:=plane.jblock[pair[1]][pair[2]];
217
218    if not centre in plane.blocks[pairblock]
219       then
220        Error("The centre must be fixed blockwise");
221    fi;
222    RemoveSet(cblocks,pairblock);
223
224    for point in axispoints
225      do
226        pblock1:=plane.jblock[point][pair[1]];
227        pblock2:=plane.jblock[point][pair[2]];
228        for cblock in cblocks
229          do
230            x:=plane.jpoint[cblock][pblock1];
231            y:=plane.jpoint[cblock][pblock2];
232            Add(projpairs,[x,y]);
233        od;
234    od;
235    cblockpair:=Representative(projpairs);
236    cblock:=plane.jblock[cblockpair[1]][cblockpair[2]];
237
238    for point in axispoints
239      do
240        pblock1:=plane.jblock[point][cblockpair[1]];
241        pblock2:=plane.jblock[point][cblockpair[2]];
242        x:=plane.jpoint[pblock1][pairblock];
243        y:=plane.jpoint[pblock2][pairblock];
244        Add(projpairs,[x,y]);
245    od;
246    nogood:=false;
247
248    for ppair in projpairs
249      do
250        if permlist[ppair[1]] in [ppair[1],ppair[2]]
251           then
252            permlist[ppair[1]]:=ppair[2];
253        else
254            nogood:=true;
255        fi;
256    od;
257
258    if not nogood
259       then
260        perm:=PermList(permlist);
261        if IsCollineationOfProjectivePlane(perm,plane)
262           then
263            return perm;
264        else
265            Error("Unable to generate elation");
266        fi;
267    else
268        Error("Unable to generate elation");
269    fi;
270end);
271
272
273#############################################################################
274##
275#O  ElationByPair( <centre>,<axis>,<pair>,<plane>)  calculate elations of projective planes.
276##  This is the "small" implementation. It does not use .jpoint
277##
278InstallMethod(ElationByPair,
279        "for projective planes",
280        [IsInt,IsVector,IsVector,IsRecord],
281        function(centre,axis,pair,plane)
282    local   blockslist,  axispos,  init_cblocks,  axispoints,
283            permlist,  cblocks,  projpairs,  pairblock,  point,
284            pblock1,  pblock2,  cblock,  x,  y,  cblockpair,  nogood,
285            ppair,  perm;
286
287    if not IsProjectivePlane(plane)
288       then
289        Error("this is not a projective plane");
290    fi;
291    if IsBound(plane.jpoint)
292       then
293        TryNextMethod();
294    fi;
295
296    if not IsSubset([1..plane.v],pair)
297       then
298        Error("<pair> must be a pair of points");
299    fi;
300
301    # die Punkte muessen integers sein!
302    if not axis in plane.blocks
303       then
304        Error("The axis must be a block");
305    fi;
306    if not centre in axis
307       then
308        Error("The centre must lie on the axis");
309    fi;
310    blockslist:=[1..plane.v];
311    axispos:=PositionSet(plane.blocks,axis);
312
313    init_cblocks:=Set(Filtered(plane.blocks,b->centre in b));
314    RemoveSet(init_cblocks,axis);
315
316    axispoints:=Difference(axis,[centre]);
317
318    if pair[1]=pair[2]
319       then
320        Error("There can only be one axis. <pair> must contain two different points.");
321    fi;
322    if Intersection(pair,axis)<>[]
323       then
324        Error("The axis must be fixed pointwise");
325    fi;
326    permlist:=[1..plane.v];
327    cblocks:=ShallowCopy(init_cblocks);
328    projpairs:=[];
329    pairblock:=plane.blocks[plane.jblock[pair[1]][pair[2]]];
330
331    if not centre in pairblock
332       then
333        Error("The centre must be fixed blockwise");
334    fi;
335    RemoveSet(cblocks,pairblock);
336
337    for point in axispoints
338      do
339        pblock1:=plane.blocks[plane.jblock[point][pair[1]]];
340        pblock2:=plane.blocks[plane.jblock[point][pair[2]]];
341        for cblock in cblocks
342          do
343#                x:=First(cblock,i->i in pblock1);
344#                y:=First(cblock,i->i in pblock2);
345            x:=Intersection2(cblock,pblock1)[1];
346            y:=Intersection2(cblock,pblock2)[1];
347            Add(projpairs,[x,y]);
348        od;
349    od;
350    cblockpair:=Representative(projpairs);
351    cblock:=plane.blocks[plane.jblock[cblockpair[1]][cblockpair[2]]];
352    for point in axispoints
353      do
354        pblock1:=plane.blocks[plane.jblock[point][cblockpair[1]]];
355        pblock2:=plane.blocks[plane.jblock[point][cblockpair[2]]];
356#            x:=First(pblock1,i->i in pairblock);
357#            y:=First(pblock2,i->i in pairblock);
358        x:=Intersection2(pblock1,pairblock)[1];
359        y:=Intersection2(pblock2,pairblock)[1];
360        Add(projpairs,[x,y]);
361    od;
362    nogood:=false;
363
364    for ppair in projpairs
365      do
366        if permlist[ppair[1]] in [ppair[1],ppair[2]]
367           then
368            permlist[ppair[1]]:=ppair[2];
369        else
370            nogood:=true;
371        fi;
372    od;
373
374    if not nogood
375       then
376        perm:=PermList(permlist);
377        if IsCollineationOfProjectivePlane(perm,plane)
378           then
379            return perm;
380        else
381            Error("Unable to generate elation");
382        fi;
383    else
384        Error("Unable to generate elation");
385    fi;
386end);
387
388
389#############################################################################
390##
391#O  AllElationsCentAx( <centre>,<axis>,<plane>)  calculate group of elations
392#O  AllElationsCentAx( <centre>,<axis>,<plane>,"generators")  calculate all elations
393##
394InstallMethod(AllElationsCentAx,
395        "for projective planes",
396        [IsInt,IsVector,IsRecord],
397        function(centre,axis,plane)
398    return Group(AllElationsCentAx(centre,axis,plane,"generators"));
399end);
400
401InstallMethod(AllElationsCentAx,
402        "for projective planes",
403        [IsInt,IsVector,IsRecord,IsString],
404        function(centre,axis,plane,genstring)
405    local   blocks,  ellist,  pairs,  block,  pointset,  point,
406            genset,  pointsetsize,  newelation;
407
408    if not genstring="generators"
409       then
410        Error("please pass >generators< as an option");
411    fi;
412    if not IsProjectivePlane(plane)
413       then
414        Error("<plane> must be a projective plane");
415    fi;
416
417    blocks:=plane.blocks;
418    ellist:=[];
419    pairs:=[];
420
421    block:=First(blocks,b->centre in b and not b=axis);
422    pointset:=Difference(block,[centre]);
423    point:=Representative(pointset);
424    RemoveSet(pointset,point);
425
426    genset:=[];
427    while pointset<>[]
428      do
429        pointsetsize:=Size(pointset);
430        newelation:=ElationByPair(centre,axis,[point,pointset[pointsetsize]],plane);
431        Unbind(pointset[pointsetsize]);
432        Add(genset,newelation);
433        SubtractSet(pointset,Orbit(Group(genset),point));
434    od;
435    return genset;
436end);
437
438
439#############################################################################
440##
441#O  AllElationsAx(<axis>,<plane>)  calcualte group of elations with given axis.
442#O  AllElationsAx(<axis>,<plane>,"generators")  calcualte generators of the gorup of elations with given axis.
443##
444InstallMethod(AllElationsAx,
445        "for projective planes",
446        [IsDenseList,IsRecord],
447        function(axis,plane)
448    return Group(AllElationsAx(axis,plane,"generators"));
449end);
450
451InstallMethod(AllElationsAx,
452        "for projective planes",
453        [IsDenseList,IsRecord,IsString],
454        function(axis,plane,genstring)
455    local   points,  ellist,  centre;
456
457    if not genstring="generators"
458       then
459        Error("please pass >generators< as an option");
460    fi;
461    if not IsProjectivePlane(plane)
462       then
463        Error("this is not a projective plane");
464    fi;
465
466    points:=Difference([1..plane.v],axis);
467    ellist:=[];
468    for centre in axis
469      do
470        if ellist<>[] and IsTransitive(Group(ellist),points)
471           then
472            return Set(ellist);
473        else
474            Append(ellist,AllElationsCentAx(centre,axis,plane,"generators"));
475        fi;
476    od;
477    return Set(ellist);
478end);
479
480
481
482#############################################################################
483##
484#O IsTranslationPlane(<infline>,<plane>)
485##
486InstallMethod(IsTranslationPlane,
487        "for projective planes",
488        [IsRecord],
489        function(plane)
490    if not IsProjectivePlane(plane)
491       then
492        return false;
493    fi;
494    return ForAny(plane.blocks,b->IsTranslationPlane(b,plane));
495end);
496
497
498#############################################################################
499##
500#O IsTranslationPlane(<infline>,<plane>)
501##
502InstallMethod(IsTranslationPlane,
503        "for projective planes",
504        [IsDenseList,IsRecord],
505        function(infline,plane)
506    local   cent1,  t1gens,  cent2,  t2gens;
507    cent1:=Random(infline);
508    t1gens:=AllElationsCentAx(cent1,infline,plane,"generators");
509    if t1gens=[] or Size(Group(t1gens))<>Size(infline)-1
510       then
511        return false;
512    else
513        cent2:=Random(Difference(infline,[cent1]));
514        t2gens:=AllElationsCentAx(cent2,infline,plane,"generators");
515    fi;
516    if Size(Group(Concatenation(t2gens,t1gens)))=plane.v-Size(infline)
517       then
518        return true;
519    else
520        return false;
521    fi;
522end);
523
524#############################################################################
525##
526#O GroupOfHomologies(<cetre>,<axis>,<plane>)
527##
528InstallMethod(GroupOfHomologies,
529        "for projective planes",
530        [IsInt,IsDenseList,IsRecord],
531        function(centre,axis,plane)
532    local   line,  pointset,  point,  genlist,
533            pointsetsize,  newhomology;
534
535    if not IsProjectivePlane(plane)
536       then
537        Error("this is not a projective plane");
538    fi;
539    line:=plane.blocks[plane.jblock[centre][axis[1]]];
540    pointset:=Difference(line,[centre,axis[1]]);
541    point:=pointset[1];
542    RemoveSet(pointset,point);
543    genlist:=[];
544    while pointset<>[]
545      do
546        pointsetsize:=Size(pointset);
547        newhomology:=HomologyByPair(centre,axis,[point,pointset[pointsetsize]],plane);
548        Unbind(pointset[pointsetsize]);
549        if not newhomology=fail
550           then
551            Add(genlist,newhomology);
552            SubtractSet(pointset,Set(Orbit(Group(genlist),point)));
553        fi;
554    od;
555    if genlist=[]
556       then
557        return Group(());
558    else
559        return Group(genlist);
560    fi;
561end);
562
563#############################################################################
564##
565#O HomologyByPair(<centre>,<axis>,<pair>,<plane>);
566##
567
568InstallMethod(HomologyByPair,
569        "for projective planes",
570        [IsInt,IsDenseList,IsDenseList,IsRecord],
571        function(centre,axis,pair,plane)
572    local   points,  blocks,  jblock,  blockslist,  axispos,  cblocks,
573            returnlist,  permlist,  projpairs,  pairblock,  axpoint,
574            plineSource,  plineDest,  line,  ppoint,  point,  perm;
575
576    if not IsProjectivePlane(plane)
577       then
578        Error("this is not a projective plane");
579    fi;
580    points:=[1..plane.v];
581    blocks:=plane.blocks;
582    jblock:=plane.jblock;
583    if  not axis in blocks
584        then
585        Error("The axis must be a block");
586        return fail;
587    fi;
588    blockslist:=[1..Size(blocks)];
589    axispos:=PositionSet(blocks,axis);
590    cblocks:=Set(Filtered(blocks,b->centre in b));
591    if axis in cblocks
592       then
593        Error("The axis must not contain the centre");
594        return fail;
595    fi;
596    returnlist:=[];
597    if Intersection(pair,axis)<>[]
598       then
599        Error("The axis must be fixed pointwise");
600        return fail;
601    fi;
602    permlist:=[1..Maximum(points)];
603    permlist[pair[1]]:=pair[2];
604    projpairs:=[];
605    pairblock:=blocks[jblock[pair[1]][pair[2]]];
606    if not centre in pairblock
607       then
608        Error("The centre must be fixed blockwise");
609        return fail;
610    fi;
611    RemoveSet(cblocks,pairblock);
612
613    for axpoint in Difference(axis,pairblock)
614      do
615        plineSource:=blocks[jblock[pair[1]][axpoint]];
616        plineDest:=blocks[jblock[pair[2]][axpoint]];
617        for line in cblocks
618          do
619            if not axpoint in line
620               then
621                permlist[Intersection2(plineSource,line)[1]]:=Intersection2(plineDest,line)[1];
622            fi;
623        od;
624    od;
625    #and now the line <pair> lives on.
626    line:=cblocks[1];
627    ppoint:=First(axis,p->not (p in line or p in pairblock));
628    for point in Difference(pairblock,Union(axis,[pair[1]],[centre]))
629      do
630        plineSource:=blocks[jblock[point][ppoint]];
631        plineDest:=blocks[jblock[ppoint][permlist[Intersection(plineSource,line)[1]]]];
632        permlist[point]:=Intersection(plineDest,pairblock)[1];
633    od;
634    perm:=PermList(permlist);
635    if IsCollineationOfProjectivePlane(perm,plane)
636       then
637        return perm;
638    else
639        return fail;
640    fi;
641end);
642
643#############################################################################
644##
645#O InducedCollineation(<baerplane>,<baercoll>,<point>,<image>,<plane>,<embedding>)
646##
647InstallMethod(InducedCollineation,
648        "for projective planes",
649        [IsRecord,IsPerm,IsInt,IsInt,IsRecord,IsPerm],
650        function(baerplane,baercoll,point,image,plane,liftingperm)
651    local   blocks,  jblock,  jpoint,  baerindices,
652            liftedcollineation,  pointtangents,  pointsecant,
653            pointsecantnr,  imagesecant,  fixpoint,  imagetangents,
654            shortimagesecant,  shortpointsecant,  baerblocks,
655            permlist,  tpoint,  tangent,  tangentimage,  secant,  p,
656            shortsecant,  secantimage,  ppoint,  ppointimage,
657            linepoint,  pline,  pointinbetween,  plineimage,  perm;
658
659    if not IsProjectivePlane(plane)
660       then
661        Error("this is not a projective plane");
662    fi;
663
664    if not IsProjectivePlane(baerplane)
665       then
666        Error("the Baer plane is not a projective plane");
667    fi;
668
669    if not IsBound(plane.jpoint)
670       then
671       PointJoiningLinesProjectivePlane(plane);;
672    fi;
673    blocks:=plane.blocks;
674    jblock:=plane.jblock;
675    jpoint:=plane.jpoint;
676    baerindices:=OnSets([1..baerplane.v],liftingperm);
677    liftedcollineation:=RestrictedPerm(baercoll^liftingperm,baerindices);
678    if (point in baerindices) or (image in baerindices)
679       then
680        Error("point and image must not lie in the Baer subplane");
681        return fail;
682    fi;
683    pointtangents:=Set(blocks{Set(jblock[point]{baerindices})});
684    pointsecant:=First(pointtangents,b->Size(Intersection(b,baerindices))>1);
685    pointsecantnr:=PositionSet(blocks,pointsecant);
686
687    if image in pointsecant
688       then
689        imagesecant:=pointsecant;
690        if point=image
691           then
692            fixpoint:=true;
693        else
694            fixpoint:=false;
695        fi;
696    else
697        fixpoint:=false;
698        imagetangents:=Set(blocks{Set(jblock[image]{baerindices})});
699        imagesecant:=First(imagetangents,b->Size(Intersection(b,baerindices))>1);
700        shortimagesecant:=Set(Intersection(imagesecant,baerindices));
701        shortpointsecant:=Set(Intersection(pointsecant,baerindices));
702        if OnSets(shortimagesecant,liftedcollineation)=shortimagesecant
703           then
704            Info(DebugRDS,1,"Wrong:point and image define different secants and image secant is fixed");
705            return fail;
706        fi;
707        if 1 in OrbitLengths(Group(liftedcollineation),shortimagesecant)
708           then
709            #here a tangent would be mapped to a secant.
710            #This is impossible.
711            Info(DebugRDS,1,"Wrong:image secant contains a fixed point");
712            return fail;
713        fi;
714    fi;
715    shortimagesecant:=Set(Intersection(imagesecant,baerindices));
716    shortpointsecant:=Set(Intersection(pointsecant,baerindices));
717    if not OnSets(shortpointsecant,liftedcollineation)=shortimagesecant
718       then
719        Info(DebugRDS,1,"point secant is not mapped to image secant");
720        return fail;
721    fi;
722    baerblocks:=List(baerplane.blocks,b->OnSets(b,liftingperm));
723    baerblocks:=Set(baerblocks,b->blocks[jblock[b[1]][b[2]]]);
724    RemoveSet(baerblocks,pointsecant);
725    permlist:=List(OnTuples([1..plane.v],liftedcollineation));
726    permlist[point]:=image;
727    for tpoint in Difference(baerindices,pointsecant)
728      do
729        tangent:=blocks[jblock[tpoint][point]];
730        tangentimage:=jblock[permlist[tpoint]][image];
731        for secant in baerblocks
732          do
733            p:=Intersection(secant,tangent)[1];
734            shortsecant:=Intersection(secant,baerindices);
735            secantimage:=jblock[permlist[shortsecant[1]]][permlist[shortsecant[2]]];
736            permlist[p]:=jpoint[secantimage][tangentimage];
737        od;
738    od;
739    ppoint:=Representative(Difference([1..plane.v],Concatenation(baerindices,pointsecant)));
740    ppointimage:=permlist[ppoint];
741    for linepoint in Difference(pointsecant,Concatenation(baerindices,[point]))
742      do
743        pline:=blocks[jblock[linepoint][ppoint]];
744        pointinbetween:=First(pline,i->not i in [ppoint,linepoint]);
745        plineimage:=jblock[permlist[pointinbetween]][ppointimage];
746        permlist[linepoint]:=jpoint[pointsecantnr][plineimage];
747    od;
748    perm:=PermList(permlist);
749    if perm=fail and not IsSubset(pointsecant,Set(Filtered(Collected(permlist),i->i[2]>1),j->j[1]))
750       then
751        Error("da gibt's noch ein Problem...");
752    elif perm=fail
753      then
754        return fail;
755    elif IsCollineationOfProjectivePlane(perm,plane)
756      then
757        return perm;
758    else
759        return fail;
760    fi;
761end);
762
763#############################################################################
764##
765#O  NrFanoPlanesAtPoints(<points>,<plane>)  invariant for projective planes
766##
767InstallMethod(NrFanoPlanesAtPoints,
768        "for projective planes",
769        [IsDenseList,IsRecord],
770        function(pointlist,plane)
771    local   returnlist,  points,  jblock,  jpoint,  blocks,  x,
772            nrfanos,  localblocks,  localblockssize,  points1size,
773            block1number,  block1,  points1,  block2number,  block2,
774            points2,  block3number,  block3,  point2number,  point2,
775            point3,  point4,  b24,  p24,  b34,  p34,  b324,  b234;
776    if not IsProjectivePlane(plane)
777       then
778        Error("<plane> is not a projective plane");
779    fi;
780    if not IsBound(plane.jpoint)
781       then
782        TryNextMethod();
783    fi;
784
785    returnlist:=[];
786    points:=[1..plane.v];
787    jblock:=plane.jblock;
788    jpoint:=plane.jpoint;
789    blocks:=plane.blocks;
790    for x in pointlist
791      do
792        nrfanos:=0;
793        localblocks:=Difference(Set(jblock[x]),[0]);
794        localblockssize:=Size(localblocks);
795        points1size:=localblockssize-1;
796        for block1number in [1..localblockssize-2]
797          do
798            block1:=localblocks[block1number];
799            points1:=Difference(blocks[block1],[x]);
800            for block2number in [block1number+1..localblockssize-1]
801              do
802                block2:=localblocks[block2number];
803                points2:=Difference(blocks[block2],[x]);
804                for block3number in [block2number+1..localblockssize]
805                  do
806                    block3:=localblocks[block3number];
807                    for point2number in [1..points1size-1]
808                      do
809                        point2:=points1[point2number];
810                        for point3 in points1{[point2number+1..points1size]}
811                          do
812                            for point4 in points2
813                              do
814                                b24:=jblock[point2][point4];
815                                p24:=jpoint[block3][b24];
816
817                                b34:=jblock[point3][point4];
818                                p34:=jpoint[block3][b34];
819
820                                b324:=jblock[point3][p24];
821                                b234:=jblock[point2][p34];
822
823                                if jpoint[block2][b234]=jpoint[block2][b324]
824                                   then
825                                    nrfanos:=nrfanos+1;
826                                fi;
827                            od;
828                        od;
829                    od;
830                od;
831            od;
832        od;
833        Add(returnlist,[x,nrfanos]);
834    od;
835    return returnlist;
836end);
837
838
839#############################################################################
840##
841#O  NrFanoPlanesAtPoints(<pointlist>,<plane>)  invariant for projective planes
842##
843## This is the "small" version
844##
845InstallMethod(NrFanoPlanesAtPoints,
846        "for projective planes",
847        [IsDenseList,IsRecord],
848        function(pointlist,plane)
849    local   returnlist,  points,  jblock,  blocks,  x,  nrfanos,
850            localblocks,  localblockssize,  points1size,
851            block1number,  block1,  points1,  block2number,  block2,
852            points2,  block3number,  block3,  points3,  point2number,
853            point2,  point3,  point4,  b24,  p24,  b34,  p34,  b324,
854            b234;
855    if not IsProjectivePlane(plane)
856       then
857        Error("<plane> is not a projective plane");
858    fi;
859
860    if IsBound(plane.jpoint)
861       then
862        TryNextMethod();
863    fi;
864
865    returnlist:=[];
866    points:=[1..plane.v];
867    jblock:=plane.jblock;
868    blocks:=plane.blocks;
869
870    for x in pointlist
871      do
872        nrfanos:=0;
873        localblocks:=Difference(Set(jblock[x]),[0]);
874        localblockssize:=Size(localblocks);
875        points1size:=localblockssize-1;
876        for block1number in [1..localblockssize-2]
877          do
878            block1:=localblocks[block1number];
879            points1:=AsSet(Difference(blocks[block1],[x]));
880            for block2number in [block1number+1..localblockssize-1]
881              do
882                block2:=localblocks[block2number];
883                points2:=AsSet(Difference(blocks[block2],[x]));
884                for block3number in [block2number+1..localblockssize]
885                  do
886                    block3:=localblocks[block3number];
887                    points3:=AsSet(blocks[block3]);
888                    for point2number in [1..points1size-1]
889                      do
890                        point2:=points1[point2number];
891                        for point3 in points1{[point2number+1..points1size]}
892                          do
893                            for point4 in points2
894                              do
895                                b24:=jblock[point2][point4];
896                                p24:=Intersection(points3,blocks[b24])[1];
897
898                                b34:=jblock[point3][point4];
899                                p34:=Intersection(points3,blocks[b34])[1];
900
901                                b324:=jblock[point3][p24];
902                                b234:=jblock[point2][p34];
903
904                                if Intersection(points2,blocks[b234])=Intersection(points2,blocks[b324])
905                                   then
906                                    nrfanos:=nrfanos+1;
907                                fi;
908                            od;
909                        od;
910                    od;
911                od;
912            od;
913        od;
914        Add(returnlist,[x,nrfanos]);
915    od;
916    return returnlist;
917end);
918
919
920#############################################################################
921##
922#O IncidenceMatrix(<design>)
923##
924InstallMethod(IncidenceMatrix,
925        [IsRecord],
926        function(plane)
927    local   blocknumber,  mat,  blocknr,  blocksize;
928
929    if not IsBlockDesign(plane)
930       then
931        Error("This is not a block design");
932    fi;
933    blocknumber:=Size(plane.blocks);
934    mat:=NullMat(plane.v,blocknumber);
935    for blocknr in [1..blocknumber]
936      do
937        blocksize:=Size(plane.blocks[blocknr]);
938        mat{plane.blocks[blocknr]}[blocknr]:=List([1..blocksize],i->1);
939    od;
940    return mat;
941end);
942
943#############################################################################
944##
945#O pRank(<plane>,<p>)
946##
947InstallMethod(PRank@,
948        "for projective planes",
949        [IsRecord,IsInt],
950        function(plane,p)
951    local   pointlist;
952
953    if not IsProjectivePlane(plane)
954       then
955        Error("This is not projective plane");
956    fi;
957    if not Size(Set(FactorsInt(p)))=1
958       then
959        Error("<p> must be a primepower or 0");
960    fi;
961    if p=0
962       then
963        return RankMatDestructive(IncidenceMatrix(plane));
964    else
965        return RankMatDestructive(IncidenceMatrix(plane)*Z(p));
966    fi;
967end);
968
969#############################################################################
970##
971#O FingerprintAntiFlag(<point>,<linenr>,<plane>)
972##
973InstallMethod(FingerprintAntiFlag,
974        [IsInt,IsInt,IsRecord],
975        function(point,linenr,plane)
976    local   infline,  lblocks,  mat,  lpoint,  projlines,  lblock,
977            permlist,  pointnr,  lblockpoint;
978
979    if not IsProjectivePlane(plane)
980       then
981        Error("this is not a projective plane");
982    fi;
983    if point in plane.blocks[linenr]
984       then
985        Error("This is not an anti- flag!");
986    fi;
987    infline:=plane.blocks[linenr];
988    lblocks:=Set(plane.jblock[point]);
989    RemoveSet(lblocks,0);
990    Apply(lblocks,i->plane.blocks[i]);
991
992    mat:=NullMat(Size(infline),Size(infline));;
993    for lpoint in infline
994      do
995        projlines:=Set(plane.jblock[lpoint]);
996        RemoveSet(projlines,0);
997        Apply(projlines,i->plane.blocks[i]);
998        for lblock in Filtered(lblocks,b->not lpoint in b)
999          do
1000            permlist:=[1..Size(lblock)];
1001            for pointnr in [1..Size(lblock)]
1002              do
1003                lblockpoint:=lblock[pointnr];
1004                permlist[pointnr]:=PositionProperty(projlines,b->lblockpoint in b);
1005            od;
1006            mat[PositionSet(infline,lpoint)][PositionSet(lblocks,lblock)]:= SignPerm(PermList(permlist));
1007
1008        od;
1009    od;
1010    #    return Collected(List(Concatenation(mat*TransposedMat(mat)),AbsoluteValue));
1011    return Collected(List(Concatenation(MatTimesTransMat(mat)),AbsoluteValue));
1012end);
1013
1014
1015#############################################################################
1016##
1017#O FingerprintProjPlane(<plane>)
1018##
1019InstallMethod(FingerprintProjPlane,
1020        [IsRecord],
1021        function(plane)
1022    local   nrOfBlocks,  mat,  points,  point,  lblocks,
1023            lblocksindex,  linenr,  line,  permlist,  pointnr;
1024
1025    if not IsProjectivePlane(plane)
1026      then
1027        Error("this is not a projective plane");
1028    fi;
1029    mat:=NullMat(plane.v,plane.v);
1030    for point in [1..plane.v]
1031      do
1032        lblocks:=Set(Filtered(plane.blocks,b->point in b));
1033        lblocksindex:=Set(lblocks,b->PositionSet(plane.blocks,b));
1034        for linenr in Difference([1..plane.v],lblocksindex)
1035          do
1036            line:=plane.blocks[linenr];
1037            permlist:=[1..Size(line)];
1038            for pointnr in [1..Size(line)]
1039              do
1040                permlist[pointnr]:=PositionProperty(lblocks,b->line[pointnr] in
1041 b);
1042            od;
1043            mat[point][linenr]:=SignPerm(PermList(permlist));
1044        od;
1045    od;
1046    return Collected(List(Concatenation(MatTimesTransMat(mat)),AbsoluteValue));
1047end);
1048
1049#############################################################################
1050##
1051#O IsomorphismProjPlanesByGenerators(<gens1>,<plane1>,<gens2>,<plane2>)
1052##
1053InstallMethod(IsomorphismProjPlanesByGenerators,
1054        "for projective planes",
1055        [IsDenseList,IsRecord,IsDenseList,IsRecord],
1056        function(gens1,plane1,gens2,plane2)
1057    local   N,  hasfailed;
1058
1059    if Size(gens1)<>Size(gens2)
1060       then
1061        Error("<gens1> and <gens2> must be of the same length!");
1062    fi;
1063    if not IsProjectivePlane(plane1) and IsProjectivePlane(plane2)
1064       then
1065        Error("plane1 and plane2 must be projective planes");
1066    fi;
1067    N:=plane1.v;
1068    hasfailed:=false;
1069    if not plane2.v=N
1070       then
1071        Error("The planes must be of the same size");
1072        hasfailed:=true;
1073    fi;
1074    if ProjectiveClosureOfPointSet(gens1,0,plane1).closure.v<>N
1075       or ProjectiveClosureOfPointSet(gens2,0,plane2).closure.v<>N
1076      then
1077        hasfailed:=true;
1078    fi;
1079    if not hasfailed
1080       then
1081        return IsomorphismProjPlanesByGeneratorsNC(gens1,plane1,gens2,plane2);
1082    else
1083        return fail;
1084    fi;
1085end);
1086
1087#############################################################################
1088##
1089#O IsomorphismProjPlanesByGeneratorsNC(<gens1>,<plane1>,<gens2>,<plane2>)
1090##
1091InstallMethod(IsomorphismProjPlanesByGeneratorsNC,
1092        "for projective planes",
1093        [IsDenseList,IsRecord,IsDenseList,IsRecord],
1094        function(gens1,plane1,gens2,plane2)
1095    local   newpoints,  oldpoints,  newblocks,  pointimagelist,
1096            blockimagelist,  pair,  oldblocks,  x,  iso;
1097
1098    if Size(gens1)<>Size(gens2)
1099       then
1100        Error("<gens1> and <gens2> must be of the same length!");
1101    fi;
1102    if not (IsProjectivePlane(plane1) and IsProjectivePlane(plane2))
1103       then
1104        Error("plane1 and plane2 must be projective planes");
1105    fi;
1106
1107    newpoints:=[];
1108    oldpoints:=Set(gens1);
1109    newblocks:=[];
1110    pointimagelist:=ListWithIdenticalEntries(plane2.v,0);
1111    pointimagelist{gens1}:=gens2;
1112    blockimagelist:=ListWithIdenticalEntries(plane2.v,0);
1113    newblocks:=Set(Combinations(oldpoints,2),i->
1114                   [plane1.jblock[i[1]][i[2]],
1115                    plane2.jblock[pointimagelist[i[1]]][pointimagelist[i[2]]]]);
1116    if Size(Set(newblocks,i->i[1]))<>Size(Set(newblocks,i->i[1]))
1117       then
1118        Info(DebugRDS,2,"bad generators");
1119        return fail;
1120    fi;
1121    for pair in newblocks
1122      do
1123        blockimagelist[pair[1]]:=pair[2];
1124    od;
1125    newblocks:=Set(newblocks,i->i[1]);
1126    oldblocks:=[];
1127    repeat
1128        newpoints:=Set(Cartesian(oldblocks,newblocks),i->
1129                       [Intersection(plane1.blocks[i[1]],plane1.blocks[i[2]])[1],
1130                        Intersection(plane2.blocks[blockimagelist[i[1]]],plane2.blocks[blockimagelist[i[2]]])[1]]);
1131        UniteSet(newpoints,List(Combinations(newblocks,2),i->
1132                [Intersection(plane1.blocks[i[1]],plane1.blocks[i[2]])[1],
1133                 Intersection(plane2.blocks[blockimagelist[i[1]]],plane2.blocks[blockimagelist[i[2]]])[1]]));
1134        for pair in newpoints
1135          do
1136            x:=pair[1];
1137            if pointimagelist[x]<>0 and pair[2]<>pointimagelist[x]
1138               then
1139                return fail;
1140            elif pointimagelist[x]=0
1141              then
1142                pointimagelist[x]:=pair[2];
1143            fi;
1144        od;
1145
1146        if Number(pointimagelist,i->i=0)<>0
1147           then
1148            newpoints:=Difference(Set(newpoints,i->i[1]),oldpoints);
1149            UniteSet(oldblocks,newblocks);
1150            newblocks:=Set(Cartesian(oldpoints,newpoints),i->
1151                           [plane1.jblock[i[1]][i[2]],
1152                            plane2.jblock[pointimagelist[i[1]]][pointimagelist[i[2]]]]
1153                           );
1154            UniteSet(newblocks,List(Combinations(newpoints,2),i->
1155                    [plane1.jblock[i[1]][i[2]],
1156                     plane2.jblock[pointimagelist[i[1]]][pointimagelist[i[2]]]
1157                     ]
1158                    ));
1159            for pair in newblocks
1160              do
1161                x:=pair[1];
1162                if blockimagelist[x]<>0 and pair[2]<>blockimagelist[x]
1163                   then
1164                    return fail;
1165                elif blockimagelist[x]=0
1166                  then
1167                    blockimagelist[x]:=pair[2];
1168                fi;
1169            od;
1170            newblocks:=Difference(Set(newblocks,i->i[1]),oldblocks);
1171            UniteSet(oldpoints,newpoints);
1172        else
1173            newpoints:=[];
1174        fi;
1175    until newpoints=[];
1176    iso:=PermListList([1..plane1.v],pointimagelist);
1177    if IsPerm(iso) and IsIsomorphismOfProjectivePlanes(iso,plane1,plane2)
1178       then
1179        return iso;
1180    else
1181        return fail;
1182    fi;
1183end);
1184
1185#############################################################################
1186##
1187#E  END
1188##
1189