Prescribed Automorphism Groups (PAG) is a GAP package for constructing combinatorial objects with prescribed automorphism groups.
The package is loaded by
gap> LoadPackage("PAG");
Let us start with a small example from the paper [Krc18]. In Theorem 8.1, a simple 5-(16,7,10) design with the following automorphism group was constructed.
gap> g:=Group((2,3,4)(5,6,7,8,9,10)(11,12,13,14,15,16), > (1,5)(2,12)(3,15)(4,8)(6,14)(7,16)(9,10)(11,13));
The design can be obtained by typing
gap> KramerMesnerSearch(5,16,7,10,g); Computing t-subset orbit representatives... 28 Computing k-subset orbit representatives... 71 Computing the Kramer-Mesner matrix... [ 29, 72 ] Starting solver... No BOUNDS The RHS is fixed ! No upper bounds: 0/1 variables are assumed Orthogonal defect: 26.953339 First reduction successful Orthogonal defect: 20.216092 Second reduction successful . . .
Comments during the calculation can be supressed by setting global options.
gap> PAGGlobalOptions.Silent:=true; true gap> d:=KramerMesnerSearch(5,16,7,10,g); [ rec( autSubgroup := Group([ (2,3,4)(5,6,7,8,9,10)(11,12,13,14,15,16), (1,5)(2,12)(3,15)(4,8)(6,14)(7,16)(9,10)(11,13) ]), blocks := [ [ 1, 2, 3, 4, 5, 6, 13 ], [ 1, 2, 3, 4, 5, 6, 14 ], [ 1, 2, 3, 4, 5, 7, 9 ], [ 1, 2, 3, 4, 5, 7, 12 ], [ 1, 2, 3, 4, 5, 9, 16 ], [ 1, 2, 3, 4, 5, 10, 12 ], [ 1, 2, 3, 4, 5, 10, 13 ], [ 1, 2, 3, 4, 5, 11, 12 ], [ 1, 2, 3, 4, 5, 11, 16 ], [ 1, 2, 3, 4, 5, 12, 14 ], [ 1, 2, 3, 4, 6, 7, 14 ], [ 1, 2, 3, 4, 6, 7, 15 ], . . .
The output is a list of non-isomorphic designs in the Design package format DESIGN: Design. We can check that it is really a 5-design.
gap> List(d,AllTDesignLambdas); [ [ 2080, 910, 364, 130, 40, 10 ] ]
The output is large because the Design format includes a list of all blocks, and 5-(16,7,10) designs have 2080 blocks. Instead, we can ask just for the base blocks.
gap> bb:=KramerMesnerSearch(5,16,7,10,g,rec(BaseBlocks:=true)); [ [ [ 1, 2, 3, 4, 5, 6, 13 ], [ 1, 2, 3, 4, 5, 6, 14 ], [ 1, 2, 3, 5, 6, 7, 11 ], [ 1, 2, 3, 5, 6, 8, 9 ], [ 1, 2, 3, 5, 6, 9, 10 ], [ 1, 2, 3, 5, 6, 9, 12 ], [ 1, 2, 3, 5, 6, 10, 15 ], [ 1, 2, 3, 5, 6, 14, 16 ], [ 1, 2, 3, 5, 8, 11, 12 ], [ 1, 2, 5, 6, 7, 8, 16 ], [ 1, 2, 5, 6, 7, 9, 14 ], [ 1, 2, 5, 6, 7, 12, 13 ], [ 1, 2, 5, 6, 7, 14, 15 ] ], [ [ 1, 2, 3, 4, 5, 6, 8 ], [ 1, 2, 3, 4, 5, 6, 14 ], [ 1, 2, 3, 5, 6, 7, 11 ], [ 1, 2, 3, 5, 6, 9, 12 ], [ 1, 2, 3, 5, 6, 10, 12 ], [ 1, 2, 3, 5, 6, 10, 16 ], [ 1, 2, 3, 5, 6, 12, 13 ], [ 1, 2, 3, 5, 6, 14, 15 ], [ 1, 2, 3, 5, 8, 11, 12 ], [ 1, 2, 5, 6, 7, 8, 9 ], [ 1, 2, 5, 6, 7, 9, 14 ], [ 1, 2, 5, 6, 7, 12, 13 ], [ 1, 2, 5, 6, 11, 14, 16 ] ] ]
In this case isomorph rejection is not performed and we get two sets of base blocks. They can be turned into designs by calling the BlockDesign
(DESIGN: BlockDesign) function: List(bb,x->BlockDesign(16,x,g));
.
The PAG package requires GAP 4.11 and the following packages:
Images 1.3
GRAPE 4.8
Design 1.7
The following packages are also loaded, if available. They are needed for a limited number of PAG functions.
AssociationSchemes 2.0
DifSets 2.3.1
GUAVA 3.15
FinInG 1.4.1
The current installation file for PAG is available at https://vkrcadinac.github.io/PAG/. To install PAG, unpack it to the pkg
directory of your local GAP installation. The package uses external binaries. To compile them on UNIX-like environments, change to the pkg/PAG-*
directory and call
$ ./configure.sh
This produces a Makefile
in the current directory. Now call
$ make all
to compile the binares. They are placed in the bin
subdirectory. Documentation in the doc
subdirectory is already compiled and can be read in PDF, html or from within GAP. To recompile the documentation, call GAP with the makedoc.g
file.
The PAG function KramerMesnerSearch
performs a search for t-designs with given parameters and a given permutation group as group of automorphisms. See the paper by B. Schmalz [Sch93] for an introduction to the Kramer-Mesner approach to constructing t-designs. Our first two examples are from this paper. The original paper of Earl Kramer and Dale Mesner is [KM76].
The summary about known 6-designs on page 130 of [Sch93] mentions that there are exactly two 6-(14,7,4) designs with cyclic derived designs. This means that the two 6-designs have automorphisms of order 13. They can be constructed by the following GAP commands.
gap> g:=Group(CyclicPerm(13)); Group([ (1,2,3,4,5,6,7,8,9,10,11,12,13) ]) gap> d:=KramerMesnerSearch(6,14,7,4,g);; gap> List(d,AllTDesignLambdas); [ [ 1716, 858, 396, 165, 60, 18, 4 ], [ 1716, 858, 396, 165, 60, 18, 4 ] ]
The solver quickly finds 24 solutions of the Kramer-Mesner system. Most of the computation time is used to eliminate isomorphic designs. This can be turned off:
gap> d2:=KramerMesnerSearch(6,14,7,4,g,rec(NonIsomorphic:=false));; gap> Size(d2); 30 gap> Size(AsSet(d2)); 24
Now we get a list of 30 designs. By default, A. Wassermann's LLL solver [Was98] is used; it may return the same solution more than once. The number of distinct designs is 24. The two non-isomorphic designs have ℤ_13 as their full automorphism group.
gap> List(d,BlockDesignAut); [ Group([ (1,2,3,4,5,6,7,8,9,10,11,12,13) ]), Group([ (1,2,3,4,5,6,7,8,9,10,11,12,13) ]) ]
In [Sch93], the existence of 6-(28,8,λ) designs was established for λ=42, 63, 84, and 105. The exact numbers of these designs with automorphism group PΓ L(2,27) were computed. While the projective general linear groups are readily available in GAP through the PGL
command, there seems to be no equivalent command for semilinear groups. We can get PΓ L(2,27) using the FinInG package, as the collineation group of the projective line over GF(27).
gap> LoadPackage("FinInG"); gap> g1:=CollineationGroup(ProjectiveSpace(1,27)); The FinInG collineation group PGammaL(2,27)
We need a permutation representation of this group on 28 points.
gap> g:=Image(ActionOnAllProjPoints(g1)); Group([ (3,28,27,26,25,24,23,22,21,20,19,18,17,4,16,15,14,13,12,11,10,9,8,7,6,5), (1,2,4)(5,8,24)(6,21,10)(7,16,15)(9,25,28)(11,13,14)(12,27,23)(17,26,18) (19,20,22), (5,7,13)(6,10,21)(8,16,14)(9,18,22)(11,24,15)(12,27,23)(17,19,25) (20,28,26) ])
Alternatively, we can get PΓ L(2,27) from the library of small primitive permutation groups.
gap> PrimitiveGroupsOfDegree(28); [ PGL(2, 7), PSL(2, 8), PGammaL(2, 8), PSU(3, 3), PGammaU(3, 3), PSp(6, 2), A(8), S(8), PSL(2, 27), PGL(2, 27), PSL(2, 27):3, PGammaL(2, 27), A(28), S(28) ]
Now we can construct the designs with λ=42.
gap> d:=KramerMesnerSearch(6,28,8,42,g,rec(BaseBlocks:=true));; gap> Size(AsSet(d)); 3
Most of the CPU time in the example above was used to compute the Kramer-Mesner matrix. The left side of the Kramer-Mesner system is the same matrix for all λ, so we can compute it once and reuse it to save time.
gap> tsub:=SubsetOrbitRep(g,28,6);; gap> ksub:=SubsetOrbitRep(g,28,8);; gap> m:=KramerMesnerMat(g,tsub,ksub);;
Now we can quickly get the exact numbers of designs from the paper [Sch93].
gap> Size(AsSet(SolveKramerMesner(ExpandMatRHS(m,42)))); 3 gap> Size(AsSet(SolveKramerMesner(ExpandMatRHS(m,63)))); 367 gap> Size(AsSet(SolveKramerMesner(ExpandMatRHS(m,84)))); 21743 gap> Size(AsSet(SolveKramerMesner(ExpandMatRHS(m,105)))); 38277
The first simple 2-(81,6,2) design was recently found by A. Nakic [Nak21]. Here are the base blocks of this design copy-pasted from the paper.
gap> bb:=[[[0,0,0,0],[0,0,0,1],[0,0,0,2],[0,1,0,0],[0,1,0,1],[0,1,0,2]], > [[0,0,0,0],[0,0,1,1],[0,0,2,2],[2,1,0,0],[2,1,1,1],[2,1,2,2]], > [[0,0,0,0],[0,1,1,1],[0,2,2,2],[0,0,1,0],[0,1,2,1],[0,2,0,2]], > [[0,0,0,0],[0,1,2,0],[0,2,1,0],[2,0,2,1],[2,1,1,1],[2,2,0,1]], > [[0,0,0,0],[1,0,0,0],[2,0,0,0],[0,2,2,1],[1,2,2,1],[2,2,2,1]], > [[0,0,0,0],[1,0,1,0],[2,0,2,0],[0,1,0,0],[1,1,1,0],[2,1,2,0]], > [[0,0,0,0],[1,0,1,1],[2,0,2,2],[0,0,2,0],[1,0,0,1],[2,0,1,2]], > [[0,0,0,0],[1,0,2,0],[2,0,1,0],[0,2,1,1],[1,2,0,1],[2,2,2,1]], > [[0,0,0,0],[1,0,2,2],[2,0,1,1],[0,1,2,1],[1,1,1,0],[2,1,0,2]], > [[0,0,0,0],[1,1,0,0],[2,2,0,0],[0,2,0,1],[1,0,0,1],[2,1,0,1]], > [[0,0,0,0],[1,1,0,1],[2,2,0,2],[0,2,2,0],[1,0,2,1],[2,1,2,2]], > [[0,0,0,0],[1,1,2,0],[2,2,1,0],[0,0,2,1],[1,1,1,1],[2,2,0,1]], > [[0,0,0,0],[1,1,2,1],[2,2,1,2],[0,2,1,1],[1,0,0,2],[2,1,2,0]], > [[0,0,0,0],[1,1,2,2],[2,2,1,1],[0,2,2,0],[1,0,1,2],[2,1,0,1]], > [[0,0,0,0],[1,2,1,2],[2,1,2,1],[0,0,2,1],[1,2,0,0],[2,1,1,2]], > [[0,0,0,0],[1,2,2,0],[2,1,1,0],[0,2,2,1],[1,1,1,1],[2,0,0,1]]]*Z(3)^0;;
The points of this design are elements of the 4-dimensional vector space V over GF(3). Here is how to get the desing in the Design package format.
gap> V:=Tuples([0,1,2],4)*Z(3)^0;; gap> d1:=Union(List(bb,y->List(V,x->AsSet(x+y))));; gap> d:=BlockDesign(81,List(d1,y->List(y,x->Position(V,x))));; gap> AllTDesignLambdas(d); [ 432, 32, 2 ]
The full automorphism group of the design is of order 2592. It is a semidirect product of the additive group of V and a group of order 32.
gap> aut:=BlockDesignAut(d); <permutation group with 5 generators> gap> Size(aut); 2592 gap> StructureDescription(aut); "(C3 x C3 x C3 x C3) : (C16 : C2)"
This group has three subgroups of order 648 up to conjugation. We can use the second subgroup to construct four more simple 2-(81,6,2) designs.
gap> g:=Filtered(AllSubgroupsConjugation(aut),x->Size(x)=648); [ <permutation group of size 648 with 7 generators>, <permutation group of size 648 with 7 generators>, <permutation group of size 648 with 7 generators> ] gap> dd:=KramerMesnerSearch(2,81,6,2,g[2]);; gap> List(dd,x->Size(AutomorphismGroup(x))); [ 1296, 2592, 3888, 1944, 15552 ]
Two of the new designs have larger full automorphism groups than the design from [Nak21]. Using their subgroups, more simple 2-(81,6,2) designs can be constructed.
Here is how the quasi-symmetric 2-(56,16,18) designs with intersection numbers x=4, y=8 from the paper [KV16] can be constructed.
gap> g:=Group((1,2,3,4,5)(6,7,8,9,10)(11,12,13,14,15)(16,17,18,19,20) > (21,22,23,24,25)(26,27,28,29,30)(31,32,33,34,35)(36,37,38,39,40) > (41,42,43,44,45)(46,47,48,49,50)(51,52,53,54,55), > (1,6,8)(2,21,26)(3,32,34)(4,11,5)(7,15,22)(9,16,13)(10,29,17) > (12,33,30)(14,19,31)(18,23,35)(24,28,36)(25,37,39)(27,38,40) > (42,51,49)(43,52,45)(44,46,47)(48,54,53)(50,56,55)); <permutation group with 2 generators> gap> d:=KramerMesnerSearch(2,56,16,18,g,rec(IntersectionNumbers:=[4,8]));; gap> Size(d); 3
We check that they have all required properties and compute their full automorphism groups:
gap> List(d,AllTDesignLambdas); [ [ 231, 66, 18 ], [ 231, 66, 18 ], [ 231, 66, 18 ] ] gap> List(d,IntersectionNumbers); [ [ 4, 8 ], [ 4, 8 ], [ 4, 8 ] ] gap> aut:=List(d,BlockDesignAut);; gap> List(aut,StructureDescription); [ "(C2 x C2 x C2 x C2) : S5", "(C2 x C2 x C2 x C2) : A5", "PSL(3,4) : C2" ]
See [KD15] for an introduction to Latin squares and definitions of isotopy, paratopy, etc. Multiplication tables of groups are examples of Latin squares.
gap> MultiplicationTable(CyclicGroup(7)); [ [ 1, 2, 3, 4, 5, 6, 7 ], [ 2, 3, 4, 5, 6, 7, 1 ], [ 3, 4, 5, 6, 7, 1, 2 ], [ 4, 5, 6, 7, 1, 2, 3 ], [ 5, 6, 7, 1, 2, 3, 4 ], [ 6, 7, 1, 2, 3, 4, 5 ], [ 7, 1, 2, 3, 4, 5, 6 ] ]
We can construct more examples by prescribing symmetry groups. The PAG function KramerMesnerMOLS
performs a search for sets of s mutually orthogonal Latin squares (MOLS) of order n and a given permutation group as autotopy or autoparatopy group. The group must act on the s+2 point classes of the corresponding transversal design. By [Fal12] and [SVW12], an autotopy of order 5 of a Latin square of order 7 must have the following cycle structure.
gap> a:=MultiPerm(CyclicPerm(5),[1..7],3); (1,2,3,4,5)(8,9,10,11,12)(15,16,17,18,19)
There are two main classes of such Latin squares. They are multiplication tables of non-associative quasigroups.
gap> KramerMesnerMOLS(7,1,Group(a)); [ [ [ [ 1, 3, 2, 6, 7, 4, 5 ], [ 7, 2, 4, 3, 6, 5, 1 ], [ 6, 7, 3, 5, 4, 1, 2 ], [ 5, 6, 7, 4, 1, 2, 3 ], [ 2, 1, 6, 7, 5, 3, 4 ], [ 3, 4, 5, 1, 2, 6, 7 ], [ 4, 5, 1, 2, 3, 7, 6 ] ] ], [ [ [ 1, 3, 5, 6, 7, 2, 4 ], [ 7, 2, 4, 1, 6, 3, 5 ], [ 6, 7, 3, 5, 2, 4, 1 ], [ 3, 6, 7, 4, 1, 5, 2 ], [ 2, 4, 6, 7, 5, 1, 3 ], [ 4, 5, 1, 2, 3, 6, 7 ], [ 5, 1, 2, 3, 4, 7, 6 ] ] ] ]
Single Latin squares are treated as MOLS sets of size s=1, hence the excess brackets. When the order n is a prime power, complete sets of s=n-1 MOLS are easily constructed from finite fields.
gap> ls4:=FieldToMOLS(GF(4)); [ [ [ 1, 2, 3, 4 ], [ 2, 1, 4, 3 ], [ 3, 4, 1, 2 ], [ 4, 3, 2, 1 ] ], [ [ 1, 2, 3, 4 ], [ 3, 4, 1, 2 ], [ 4, 3, 2, 1 ], [ 2, 1, 4, 3 ] ], [ [ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ], [ 2, 1, 4, 3 ], [ 3, 4, 1, 2 ] ] ] gap> AreMOLS(ls4); true
The package Guava contains a function AreMOLS
(GUAVA: AreMOLS) to test sets of MOLS. A famous problem is to find MOLS of order 10. The Handbook of Combinatorial Designs [CD07], III.5.6 contains an example of a 1-diagonally cyclic self-orthogonal Latin square L of order 10. Self-orthogonal means that L is orthogonal to its transpose. In other words, the MOLS set {L,L^t} is invariant under the following conjugation, simultaneously exchanging rows–columns and the two Latin squares.
gap> c:=Sortex(Concatenation([11..20],[1..10],[31..40],[21..30])); (1,11)(2,12)(3,13)(4,14)(5,15)(6,16)(7,17)(8,18)(9,19)(10,20)(21, 31)(22,32)(23,33)(24,34)(25,35)(26,36)(27,37)(28,38)(29,39)(30,40)
Furthermore, the example from [CD07] has an autotopy of order 9.
gap> a:=MultiPerm(CyclicPerm(9),[1..10],4); (1,2,3,4,5,6,7,8,9)(11,12,13,14,15,16,17,18,19)(21,22,23,24,25,26, 27,28,29)(31,32,33,34,35,36,37,38,39)
The permutations a and c generate an autoparatopy group of order 18 we can use to construct the example.
gap> g:=Group(a,c);; gap> Size(g); 18 gap> ls10:=KramerMesnerMOLS(10,2,g);; gap> List(ls10,AreMOLS); [ true, true, true, true, true ]
We see that there are 5 inequivalent pairs of MOLS with g as autoparatopy group. Here is one pair.
gap> ls10[1]; [ [ [ 1, 3, 6, 9, 2, 10, 5, 7, 4, 8 ], [ 5, 2, 4, 7, 1, 3, 10, 6, 8, 9 ], [ 9, 6, 3, 5, 8, 2, 4, 10, 7, 1 ], [ 8, 1, 7, 4, 6, 9, 3, 5, 10, 2 ], [ 10, 9, 2, 8, 5, 7, 1, 4, 6, 3 ], [ 7, 10, 1, 3, 9, 6, 8, 2, 5, 4 ], [ 6, 8, 10, 2, 4, 1, 7, 9, 3, 5 ], [ 4, 7, 9, 10, 3, 5, 2, 8, 1, 6 ], [ 2, 5, 8, 1, 10, 4, 6, 3, 9, 7 ], [ 3, 4, 5, 6, 7, 8, 9, 1, 2, 10 ] ], [ [ 1, 5, 9, 8, 10, 7, 6, 4, 2, 3 ], [ 3, 2, 6, 1, 9, 10, 8, 7, 5, 4 ], [ 6, 4, 3, 7, 2, 1, 10, 9, 8, 5 ], [ 9, 7, 5, 4, 8, 3, 2, 10, 1, 6 ], [ 2, 1, 8, 6, 5, 9, 4, 3, 10, 7 ], [ 10, 3, 2, 9, 7, 6, 1, 5, 4, 8 ], [ 5, 10, 4, 3, 1, 8, 7, 2, 6, 9 ], [ 7, 6, 10, 5, 4, 2, 9, 8, 3, 1 ], [ 4, 8, 7, 10, 6, 5, 3, 1, 9, 2 ], [ 8, 9, 1, 2, 3, 4, 5, 6, 7, 10 ] ] ]
Cubes of symmetric designs are studied in the paper [KPT24]. Here is an example.
gap> c:=DifferenceCube(Group((1,2,3,4,5,6,7)),[1,2,4],3); [ [ [ 1, 1, 0, 1, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 1, 1 ], [ 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 1, 1, 0, 1 ], [ 0, 0, 1, 1, 0, 1, 0 ], [ 0, 1, 1, 0, 1, 0, 0 ] ], [ [ 1, 0, 1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 1, 1 ], [ 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 1, 1, 0, 1 ], [ 0, 0, 1, 1, 0, 1, 0 ], [ 0, 1, 1, 0, 1, 0, 0 ], [ 1, 1, 0, 1, 0, 0, 0 ] ], [ [ 0, 1, 0, 0, 0, 1, 1 ], [ 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 1, 1, 0, 1 ], [ 0, 0, 1, 1, 0, 1, 0 ], [ 0, 1, 1, 0, 1, 0, 0 ], [ 1, 1, 0, 1, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 1 ] ], [ [ 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 1, 1, 0, 1 ], [ 0, 0, 1, 1, 0, 1, 0 ], [ 0, 1, 1, 0, 1, 0, 0 ], [ 1, 1, 0, 1, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 1, 1 ] ], [ [ 0, 0, 0, 1, 1, 0, 1 ], [ 0, 0, 1, 1, 0, 1, 0 ], [ 0, 1, 1, 0, 1, 0, 0 ], [ 1, 1, 0, 1, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 1, 1 ], [ 1, 0, 0, 0, 1, 1, 0 ] ], [ [ 0, 0, 1, 1, 0, 1, 0 ], [ 0, 1, 1, 0, 1, 0, 0 ], [ 1, 1, 0, 1, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 1, 1 ], [ 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 1, 1, 0, 1 ] ], [ [ 0, 1, 1, 0, 1, 0, 0 ], [ 1, 1, 0, 1, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 1, 1 ], [ 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 1, 1, 0, 1 ], [ 0, 0, 1, 1, 0, 1, 0 ] ] ]
This is a 3-dimensional array of zeros and ones such that all 2-dimensional slices are incidence matrices of (7,3,1) designs. For example, here is a slice obtained by varying coordinates 1,3 and setting coordinate 2 to 7.
gap> m:=CubeSlice(c,1,3,[7]); [ [ 0, 1, 1, 0, 1, 0, 0 ], [ 1, 1, 0, 1, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 1 ], [ 0, 1, 0, 0, 0, 1, 1 ], [ 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 1, 1, 0, 1 ], [ 0, 0, 1, 1, 0, 1, 0 ] ] gap> m*TransposedMat(m); [ [ 3, 1, 1, 1, 1, 1, 1 ], [ 1, 3, 1, 1, 1, 1, 1 ], [ 1, 1, 3, 1, 1, 1, 1 ], [ 1, 1, 1, 3, 1, 1, 1 ], [ 1, 1, 1, 1, 3, 1, 1 ], [ 1, 1, 1, 1, 1, 3, 1 ], [ 1, 1, 1, 1, 1, 1, 3 ] ]
A cube of arbitrary dimension n≥ 2 can be constructed from a difference set in a group by calling DifferenceCube
(2.6-1). The function uses the representation of difference sets from the DifSets package DifSets: Difference Sets. For n=2, the difference cube is simply an incidence matrix of the associated symmetric design, i.e. the development of the difference set.
gap> g:=SmallGroup(15,1); <pc group of size 15 with 2 generators> gap> StructureDescription(g); "C15" gap> ds:=DifferenceSets(g); [ [ 1, 2, 3, 4, 8, 11, 12 ] ] gap> m:=DifferenceCube(g,ds[1],2); [ [ 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0 ], [ 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1 ], [ 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0 ], [ 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 ], [ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0 ], [ 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1 ], [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1 ], [ 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0 ], [ 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0 ], [ 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0 ], [ 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0 ], [ 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1 ], [ 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0 ], [ 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1 ] ] gap> d:=BlockDesign(15,List(m,x->Positions(x,1)));; gap> AllTDesignLambdas(d); [ 15, 7, 3 ]
The function DifferenceSets
(DifSets: DifferenceSets) returns a list of all difference sets up to equivalence in a given group. Here is a small 4-dimensional (3,2,1) cube.
gap> c:=DifferenceCube(Group((1,2,3)),[1,2],4); [ [ [ [ 1, 1, 0 ], [ 1, 0, 1 ], [ 0, 1, 1 ] ], [ [ 1, 0, 1 ], [ 0, 1, 1 ], [ 1, 1, 0 ] ], [ [ 0, 1, 1 ], [ 1, 1, 0 ], [ 1, 0, 1 ] ] ], [ [ [ 1, 0, 1 ], [ 0, 1, 1 ], [ 1, 1, 0 ] ], [ [ 0, 1, 1 ], [ 1, 1, 0 ], [ 1, 0, 1 ] ], [ [ 1, 1, 0 ], [ 1, 0, 1 ], [ 0, 1, 1 ] ] ], [ [ [ 0, 1, 1 ], [ 1, 1, 0 ], [ 1, 0, 1 ] ], [ [ 1, 1, 0 ], [ 1, 0, 1 ], [ 0, 1, 1 ] ], [ [ 1, 0, 1 ], [ 0, 1, 1 ], [ 1, 1, 0 ] ] ] ] gap> CubeTest(c); [ [ 3, 2, 1 ] ]
The function CubeTest
(2.6-13) looks at all possible slices and checks if they are incidence matrices of (v,k,λ) designs. In the next example we construct all 3-dimensional difference cubes of order 21.
gap> g:=AllSmallGroups(21);; gap> List(g,StructureDescription); [ "C7 : C3", "C21" ] gap> ds:=List(g,DifferenceSets); [ [ [ 1, 2, 3, 9, 10 ] ], [ [ 1, 2, 7, 10, 16 ] ] ] gap> c1:=DifferenceCube(g[1],ds[1][1],3);; gap> c2:=DifferenceCube(g[2],ds[2][1],3);; gap> List([c1,c2],CubeTest); [ [ [ 21, 5, 1 ] ], [ [ 21, 5, 1 ] ] ] gap> Size(CubeAut(c1)); 1323 gap> Size(CubeAut(c2)); 2646
The function CubeAut
(2.6-15) computes the full autotopy group of a cube. By setting options, full autoparatopy groups can also be obtained. We can make a non-difference cube by the "group cube" construction of Theorem 4.1 from [KPT24]. First we search for all (21,5,1) designs with blocks being difference sets in the Frobenius group of order 21.
gap> allds:=Filtered(Combinations([1..21],5),x->IsDifferenceSet(g[1],x));; gap> Size(allds); 294 gap> A:=KramerMesnerMat(Group(()),Combinations([1..21],2),allds,1,21);; gap> PAGGlobalOptions.Silent:=true;; gap> sol:=AsSet(SolveKramerMesner(A));; gap> des:=List(sol,x->BaseBlocks(allds,x));; gap> Size(des); 70
Among these 70 designs, 14 are left developments, and 14 are right developments. The remaining 42 designs are not developments, but all of their blocks are difference sets.
gap> dev1:=AsSet(List(allds,x->LeftDevelopment(g[1],x).blocks));; gap> Size(dev1); 14 gap> dev2:=AsSet(List(allds,x->RightDevelopment(g[1],x).blocks));; gap> Size(dev2); 14 gap> nondev:=Difference(des,Union(dev1,dev2));; gap> Size(nondev); 42
Now we apply the group cube construction to these 42 designs. The obtained cubes are equivalent.
gap> cc:=List(nondev,x->GroupCube(g[1],x,3));; gap> Size(CubeFilter(cc)); 1
The function CubeFilter
(2.6-16) eliminates equivalent copies from a list of cubes. Our new cube is not equivalent with the two (21,5,1) difference cubes.
gap> c3:=cc[1];; gap> CubeTest(c3); [ [ 21, 5, 1 ] ] gap> Size(CubeFilter([c1,c2,c3])); 3 gap> Size(CubeAut(c3)); 441
However, the three cubes have the same slice invariant; see [KPT24] for the definition.
gap> List([c1,c2,c3],SliceInvariant); [ [ [ [ [ 120960, 21 ] ], 3 ] ], [ [ [ [ 120960, 21 ] ], 3 ] ], [ [ [ [ 120960, 21 ] ], 3 ] ] ]
Cubes with slice invariants different from any difference cube can be constructed for parameters of the form (4^m,2^m-1(2^m-1),2^m-1(2^m-1-1)), m≥ 2.
gap> m:=2;; n:=3;; gap> cl:=List([1,2,3],i->GroupCube(SDPSeriesGroup(m),SDPSeriesDesign(m,i),n));; gap> List(cl,CubeTest); [ [ [ 16, 6, 2 ] ], [ [ 16, 6, 2 ] ], [ [ 16, 6, 2 ] ] ] gap> List(cl,SliceInvariant); [ [ [ [ [ 11520, 16 ] ], 3 ] ], [ [ [ [ 768, 16 ] ], 2 ], [ [ [ 11520, 16 ] ], 1 ] ], [ [ [ [ 384, 16 ] ], 2 ], [ [ [ 11520, 16 ] ], 1 ] ] ]
The first cube in the list cl
is a difference cube. The other two cubes are not, because they have non-isomorphic slices in different directions. This construction works for all m≥ 2 and dimensions n≥ 3, but it takes a lot of time and memory for bigger values of m and n. We classified all 3-dimensional group cubes of (16,6,2) designs; they are available at https://web.math.pmf.unizg.hr/~krcko/results/cubes.html. A list of 1423 non-group cubes of (16,6,2) designs is also provided.
The package DifSets contains precomputed lists of difference sets up to equivalence. They are loaded by the function LoadDifferenceSets
(DifSets: LoadDifferenceSets). We can use them to compute all difference cubes up to equivalence.
gap> v:=27; 27 gap> l1:=Concatenation(List([1..NrSmallGroups(v)], > i->List(LoadDifferenceSets(v,i),x->[i,x]))); [ [ 4, [ 1, 2, 3, 4, 5, 6, 9, 12, 16, 19, 20, 23, 26 ] ], [ 4, [ 1, 2, 3, 4, 5, 7, 8, 9, 13, 15, 18, 19, 23 ] ], [ 5, [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 23, 25, 27 ] ] ]
The list l1
now contains all inequivalent difference sets in groups of order 27. The first entry is the group ID from the GAP library of small groups, followed by the difference set.
gap> StructureDescription(SmallGroup(27,4)); "C9 : C3" gap> StructureDescription(SmallGroup(27,5)); "C3 x C3 x C3" gap> l2:=List(l1,x->DifferenceCube(SmallGroup(v,x[1]),x[2],3));; gap> l3:=l1{CubeFilter(l2,rec(Positions:=true))}; [ [ 4, [ 1, 2, 3, 4, 5, 6, 9, 12, 16, 19, 20, 23, 26 ] ], [ 5, [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 23, 25, 27 ] ] ]
The list l3
contains difference sets giving 3-cubes that are inequivalent (not paratopic). Notice that the two cubes arising from difference sets in ℤ_9⋊ ℤ_3 (group ID 4) are paratopic, but not isotopic:
gap> l4:=l1{CubeFilter(l2,rec(Positions:=true,Isotopy:=true))}; [ [ 4, [ 1, 2, 3, 4, 5, 6, 9, 12, 16, 19, 20, 23, 26 ] ], [ 4, [ 1, 2, 3, 4, 5, 7, 8, 9, 13, 15, 18, 19, 23 ] ], [ 5, [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 23, 25, 27 ] ] ]
We will now construct some non-difference group cubes in ℤ_9⋊ ℤ_3. Here is an way to get all difference sets, including equivalent ones.
gap> g:=SmallGroup(v,4); <pc group of size 27 with 3 generators> gap> ds:=LoadDifferenceSets(v,4); [ [ 1, 2, 3, 4, 5, 6, 9, 12, 16, 19, 20, 23, 26 ], [ 1, 2, 3, 4, 5, 7, 8, 9, 13, 15, 18, 19, 23 ] ] gap> allds:=EquivalentDifferenceSets(g,ds);; gap> Size(allds); 972
For parameters (21,5,1) we could search for all designs with difference sets as blocks. This would take too much time for (27,13,6), so we prescribe an automorphism group of order 3.
gap> ge:=ExtendedPermRepresentation(g); <permutation group with 7 generators> gap> sub:=AllSubgroupsConjugation(ge);; gap> h:=sub[4]; Group([ (1,10,4)(2,15,7)(3,17,9)(5,20,12)(6,22,14)(8,23,16) (11,25,19)(13,26,21)(18,27,24) ]) gap> alldsorb:=List(Orbits(h,allds,OnSets),Representative);; gap> Size(alldsorb); 324 gap> pairsorb:=List(Orbits(h,Combinations([1..27],2),OnSets),Representative);; gap> Size(pairsorb); 117 gap> A:=KramerMesnerMat(h,pairsorb,alldsorb,6,27);; gap> sol:=AsSet(SolveKramerMesner(A));; gap> des:=List(sol,x->BlockDesign(27,BaseBlocks(alldsorb,x),h).blocks);; gap> Size(des); 288
We get 288 designs with difference sets as blocks. Let us remove the ones which are developments of their blocks.
gap> dev1:=AsSet(List(allds,x->LeftDevelopment(g,x).blocks));; gap> dev2:=AsSet(List(allds,x->RightDevelopment(g,x).blocks));; gap> nondev:=List(Difference(des,Union(dev1,dev2)),x->[4,x]);; gap> Size(nondev); 216
Next, we remove the ones leading to equivalent 3-cubes.
gap> cc:=List(nondev,x->GroupCube(SmallGroup(v,x[1]),x[2],3));; gap> l5:=nondev{CubeFilter(cc,rec(Positions:=true))}; [ [ 4, [ [ 1, 2, 3, 4, 5, 6, 9, 12, 16, 19, 20, 23, 26 ], [ 1, 2, 3, 4, 5, 7, 10, 13, 14, 19, 21, 22, 24 ], [ 1, 2, 3, 7, 11, 12, 13, 15, 20, 23, 24, 25, 27 ], [ 1, 2, 4, 6, 10, 11, 13, 14, 15, 17, 18, 20, 26 ], [ 1, 2, 4, 8, 9, 12, 13, 16, 17, 18, 22, 24, 27 ], [ 1, 2, 9, 10, 11, 14, 16, 17, 19, 21, 23, 25, 27 ], [ 1, 3, 4, 7, 8, 11, 17, 18, 19, 22, 23, 25, 26 ], [ 1, 3, 5, 8, 9, 10, 14, 15, 18, 23, 24, 26, 27 ], [ 1, 3, 5, 8, 10, 11, 12, 15, 16, 17, 20, 21, 22 ], [ 1, 4, 6, 7, 9, 10, 12, 15, 21, 22, 25, 26, 27 ], [ 1, 5, 6, 7, 9, 11, 14, 16, 18, 20, 22, 24, 25 ], [ 1, 5, 6, 8, 13, 17, 19, 20, 21, 24, 25, 26, 27 ], [ 1, 6, 7, 8, 12, 13, 14, 15, 16, 18, 19, 21, 23 ], [ 2, 3, 5, 6, 9, 13, 15, 17, 18, 21, 22, 23, 25 ], [ 2, 3, 6, 7, 8, 9, 11, 12, 14, 17, 21, 24, 26 ], [ 2, 3, 6, 8, 10, 12, 14, 18, 19, 20, 22, 25, 27 ], [ 2, 4, 5, 7, 8, 9, 11, 15, 18, 19, 20, 21, 27 ], [ 2, 4, 8, 14, 15, 16, 20, 21, 22, 23, 24, 25, 26 ], [ 2, 5, 6, 7, 8, 10, 11, 13, 16, 22, 23, 26, 27 ], [ 2, 5, 7, 10, 12, 15, 16, 17, 18, 19, 24, 25, 26 ], [ 3, 4, 5, 11, 12, 13, 14, 16, 18, 21, 25, 26, 27 ], [ 3, 4, 6, 7, 10, 16, 17, 18, 20, 21, 23, 24, 27 ], [ 3, 4, 6, 8, 9, 10, 11, 13, 15, 16, 19, 24, 25 ], [ 3, 7, 9, 13, 14, 15, 16, 17, 19, 20, 22, 26, 27 ], [ 4, 5, 6, 11, 12, 14, 15, 17, 19, 22, 23, 24, 27 ], [ 4, 5, 7, 8, 9, 10, 12, 13, 14, 17, 20, 23, 25 ], [ 9, 10, 11, 12, 13, 18, 19, 20, 21, 22, 23, 24, 26 ] ] ], [ 4, [ [ 1, 2, 3, 4, 5, 6, 9, 12, 16, 19, 20, 23, 26 ], [ 1, 2, 3, 5, 7, 11, 14, 15, 18, 20, 23, 24, 25 ], [ 1, 2, 3, 7, 9, 13, 14, 17, 19, 20, 21, 22, 27 ], [ 1, 2, 4, 6, 7, 8, 10, 11, 13, 18, 20, 22, 26 ], [ 1, 2, 4, 10, 12, 14, 15, 21, 22, 23, 25, 26, 27 ], [ 1, 2, 5, 8, 12, 13, 17, 18, 19, 21, 24, 25, 26 ], [ 1, 3, 4, 6, 8, 11, 13, 15, 17, 19, 23, 25, 27 ], [ 1, 3, 5, 8, 10, 11, 12, 15, 16, 17, 20, 21, 22 ], [ 1, 3, 6, 7, 8, 9, 10, 12, 18, 21, 23, 24, 27 ], [ 1, 4, 5, 6, 7, 10, 13, 14, 15, 16, 19, 21, 24 ], [ 1, 4, 8, 9, 14, 15, 16, 17, 18, 20, 24, 26, 27 ], [ 1, 5, 6, 9, 11, 12, 13, 14, 16, 18, 22, 25, 27 ], [ 1, 7, 9, 10, 11, 16, 17, 19, 22, 23, 24, 25, 26 ], [ 2, 3, 4, 5, 10, 13, 16, 17, 18, 22, 23, 24, 27 ], [ 2, 3, 4, 8, 9, 10, 11, 14, 16, 18, 19, 21, 25 ], [ 2, 3, 6, 9, 10, 11, 12, 13, 14, 15, 17, 24, 26 ], [ 2, 4, 5, 7, 8, 9, 11, 12, 15, 19, 22, 24, 27 ], [ 2, 5, 6, 7, 8, 11, 14, 16, 17, 21, 23, 26, 27 ], [ 2, 6, 7, 10, 12, 15, 16, 17, 18, 19, 20, 25, 27 ], [ 2, 6, 8, 9, 13, 15, 16, 20, 21, 22, 23, 24, 25 ], [ 3, 4, 5, 6, 7, 9, 15, 17, 18, 21, 22, 25, 26 ], [ 3, 4, 7, 11, 12, 13, 16, 20, 21, 24, 25, 26, 27 ], [ 3, 5, 6, 8, 10, 14, 19, 20, 22, 24, 25, 26, 27 ], [ 3, 7, 8, 12, 13, 14, 15, 16, 18, 19, 22, 23, 26 ], [ 4, 5, 7, 8, 9, 10, 12, 13, 14, 17, 20, 23, 25 ], [ 4, 6, 11, 12, 14, 17, 18, 19, 20, 21, 22, 23, 24 ], [ 5, 9, 10, 11, 13, 15, 18, 19, 20, 21, 23, 26, 27 ] ] ] ]
We have constructed two (27,13,6) designs with blocks being difference sets in ℤ_9⋊ ℤ_3, which are not their developments. Here are the slice invariants of the difference and non-difference group 3-cubes constructed so far.
gap> dc:=List(l3,x->DifferenceCube(SmallGroup(v,x[1]),x[2],3));; gap> gc:=List(l5,x->GroupCube(SmallGroup(v,x[1]),x[2],3));; gap> List(dc,SliceInvariant); [ [ [ [ [ 1053, 27 ] ], 3 ] ], [ [ [ [ 1053, 27 ] ], 3 ] ] ] gap> List(gc,SliceInvariant); [ [ [ [ [ 27, 27 ] ], 2 ], [ [ [ 1053, 27 ] ], 1 ] ], [ [ [ [ 27, 27 ] ], 2 ], [ [ [ 1053, 27 ] ], 1 ] ] ]
More examples of difference and non-difference group cubes are available on our web page:
https://web.math.pmf.unizg.hr/~krcko/results/cubes.html
Projection cubes of symmetric designs are introduced and studied in [KR24]. They are n-dimensional matrices of zeros and ones such that all 2-dimensional projections are incidence matrices of symmetric (v,k,λ) designs. The set of all such matrices is denoted P^n(v,k,λ). Here are two pictures of P^3(7,3,1)-cubes.
These are the cubes C_1 and C_3 from [KR24]. Incidence cubes can be represented as sets of indices of the 1-entries. The two cubes above have the following ``orthogonal array representations''.
gap> C1:=[[1,2,3],[1,4,5],[1,6,7],[2,3,1],[2,4,6],[2,7,5],[3,1,2],[3,6,5], > [3,7,4],[4,3,7],[4,5,1],[4,6,2],[5,1,4],[5,2,7],[5,3,6],[6,2,4],[6,5,3], > [6,7,1],[7,1,6],[7,4,3],[7,5,2]];; gap> C3:=[[1,2,4],[1,4,6],[1,6,2],[2,3,7],[2,4,3],[2,7,4],[3,1,6],[3,6,7], > [3,7,1],[4,3,6],[4,5,3],[4,6,5],[5,1,2],[5,2,3],[5,3,1],[6,2,7],[6,5,2], > [6,7,5],[7,1,4],[7,4,5],[7,5,1]];;
We can switch between this representation and n-dimensional matrices with the functions OrthogonalArrayToCube
(2.6-8) and CubeToOrthogonalArray
(2.6-7).
gap> C1c:=OrthogonalArrayToCube(C1); [ [ [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0, 0 ] ], [ [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0 ] ], [ [ 0, 1, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 1, 0, 0, 0 ] ], [ [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ] ], [ [ 0, 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 1, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ] ], [ [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0, 0 ] ], [ [ 0, 0, 0, 0, 0, 1, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ] ] ] gap> CubeProjectionTest(C1c); [ [ 7, 3, 1 ] ]
The function CubeProjectionTest
(2.7-3) checks if an n-dimensional matrix is a P^n(v,k,λ)-cube. The result should be [[v,k,lambda]]
. Anything else means it does not satisfy the requirements. There is a faster function OrthogonalArrayProjectionTest
(2.7-6) that works directly with the orthogonal array representation.
gap> OrthogonalArrayProjectionTest(C3); [ [ 7, 3, 1 ] ]
Functions CubeFilter
(2.6-16) and CubeAut
(2.6-15) also have versions that work with orthogonal arrays.
gap> Size(OrthogonalArrayFilter([C1,C3])); 2
This means that C_1 and C_3 are not equivalent (paratopic). They are distinguished by the size of the full autoparatopy group.
gap> Size(OrthogonalArrayAut(C1,rec(Paratopy:=true))); 63 gap> Size(OrthogonalArrayAut(C3,rec(Paratopy:=true))); 42
Projection cubes can be constructed from n-dimensional difference sets. The family of Paley difference sets extends naturally to higher dimensions.
gap> D4:=PaleyDifferenceSet(7); [ [ 0*Z(7), Z(7)^0, Z(7), Z(7)^2, Z(7)^3, Z(7)^4, Z(7)^5 ], [ 0*Z(7), Z(7)^2, Z(7)^3, Z(7)^4, Z(7)^5, Z(7)^0, Z(7) ], [ 0*Z(7), Z(7)^4, Z(7)^5, Z(7)^0, Z(7), Z(7)^2, Z(7)^3 ] ] gap> C4:=DifferenceSetToOrthogonalArray(D4); [ [ 1, 2, 3, 4, 5, 6, 7 ], [ 2, 4, 6, 3, 1, 7, 5 ], [ 3, 6, 5, 7, 4, 1, 2 ], [ 4, 3, 7, 6, 2, 5, 1 ], [ 5, 1, 4, 2, 7, 3, 6 ], [ 6, 7, 1, 5, 3, 2, 4 ], [ 7, 5, 2, 1, 6, 4, 3 ], [ 1, 4, 5, 6, 7, 2, 3 ], [ 2, 3, 1, 7, 5, 4, 6 ], [ 3, 7, 4, 1, 2, 6, 5 ], [ 4, 6, 2, 5, 1, 3, 7 ], [ 5, 2, 7, 3, 6, 1, 4 ], [ 6, 5, 3, 2, 4, 7, 1 ], [ 7, 1, 6, 4, 3, 5, 2 ], [ 1, 6, 7, 2, 3, 4, 5 ], [ 2, 7, 5, 4, 6, 3, 1 ], [ 3, 1, 2, 6, 5, 7, 4 ], [ 4, 5, 1, 3, 7, 6, 2 ], [ 5, 3, 6, 1, 4, 2, 7 ], [ 6, 2, 4, 7, 1, 5, 3 ], [ 7, 4, 3, 5, 2, 1, 6 ] ] gap> OrthogonalArrayProjectionTest(C4); [ [ 7, 3, 1 ] ]
This is a 7-dimensional analog of the Fano plane. The cubes C_1 and C_3 are its restrictions.
gap> AsSet(List(C4,x->x{[1,2,3]}))=C1; true gap> AsSet(List(C4,x->x{[1,2,4]}))=C3; true
The cyclotomic difference sets (4th and 8th powers in finite fields of appropriate order) and the twin prime power difference sets also have higher-dimensional versions.
gap> C5:=DifferenceSetToOrthogonalArray(PowerDifferenceSet(37,4));; gap> OrthogonalArrayProjectionTest(C5); [ [ 37, 9, 2 ] ] gap> C6:=DifferenceSetToOrthogonalArray(PowerDifferenceSet(73,8));; gap> OrthogonalArrayProjectionTest(C6); [ [ 73, 9, 1 ] ] gap> C7:=DifferenceSetToOrthogonalArray(TwinPrimePowerDifferenceSet(5));; gap> OrthogonalArrayProjectionTest(C7); [ [ 35, 17, 8 ] ]
These are projection cubes in P^37(37,9,2), P^73(73,9,1), and P^5(35,17,8). In the paper [KR24] the following 3-dimensional (16,6,2) difference set in Z_4× Z_4 is considered.
gap> D4:=[[[0,0],[0,0],[1,0]],[[0,0],[1,0],[0,0]],[[0,0],[0,1],[2,0]], > [[0,0],[2,0],[0,1]],[[0,0],[1,2],[0,3]],[[0,0],[2,3],[3,2]]];; gap> g:=SmallGroup(16,2); <pc group of size 16 with 4 generators> gap> StructureDescription(g); "C4 x C4"
We first convert D_4 to the DifSets package format.
gap> toel:=x->g.1^x[1]*g.2^x[2];; gap> D4a:=List(D4,x->List(x,toel)); [ [ <identity> of ..., <identity> of ..., f1 ], [ <identity> of ..., f1, <identity> of ... ], [ <identity> of ..., f2, f3 ], [ <identity> of ..., f3, f2 ], [ <identity> of ..., f1*f4, f2*f4 ], [ <identity> of ..., f2*f3*f4, f1*f3*f4 ] ] gap> e:=Elements(g); [ <identity> of ..., f1, f2, f3, f4, f1*f2, f1*f3, f1*f4, f2*f3, f2*f4, f3*f4, f1*f2*f3, f1*f2*f4, f1*f3*f4, f2*f3*f4, f1*f2*f3*f4 ] gap> D4b:=List(D4a,x->List(x,y->Position(e,y))); [ [ 1, 1, 2 ], [ 1, 2, 1 ], [ 1, 3, 4 ], [ 1, 4, 3 ], [ 1, 8, 10 ], [ 1, 15, 14 ] ]
The function DifferenceSetToOrthogonalArray
(2.7-7) takes either a group and an n-dimensional difference set in DifSets format, or an additive difference set containing finite field elements. The development of D_4 over G=Z_4× Z_4 is a projection cube in P^3(16,6,2) with full autoparatopy group isomorphic to G.
gap> C8:=DifferenceSetToOrthogonalArray(g,D4b);; gap> OrthogonalArrayProjectionTest(C8); [ [ 16, 6, 2 ] ] gap> IsomorphismGroups(g,OrthogonalArrayAut(C8,rec(Paratopy:=true))); [ f1, f2 ] -> [ (1,7,4,2)(3,12,9,6)(5,14,11,8)(10,16,15,13)(17,23,20,18)(19,28, 25,22)(21,30,27,24)(26,32,31,29)(33,39,36,34)(35,44,41,38)(37,46,43,40)(42, 48,47,45), (1,10,5,3)(2,13,8,6)(4,15,11,9)(7,16,14,12)(17,26,21,19)(18,29, 24,22)(20,31,27,25)(23,32,30,28)(33,42,37,35)(34,45,40,38)(36,47,43,41)(39, 48,46,44) ]
More examples of projection cubes are available on the following web page,
https://web.math.pmf.unizg.hr/~krcko/results/pcubes.html
including 102 cubes in P^3(16,6,2) that cannot be constructed from 3-dimensional difference sets. Four of these cubes are shown in Figure 2 of [KR24]. They have the interesting property that the projections are non-isomorphic (16,6,2) designs.
gap> Read("examples.oa"); gap> fig2:=[Crrg,Crgg,Crrb,Crbb];; gap> List(fig2,OrthogonalArrayProjectionTest); [ [ [ 16, 6, 2 ] ], [ [ 16, 6, 2 ] ], [ [ 16, 6, 2 ] ], [ [ 16, 6, 2 ] ] ] gap> p:=oa->List(OrthogonalArrayProjections(oa),x->Size(OrthogonalArrayAut(x)));; gap> List(fig2,p); [ [ 768, 11520, 11520 ], [ 768, 768, 11520 ], [ 384, 11520, 11520 ], [ 384, 384, 11520 ] ]
The four cubes are not equivalent with cubes constructed from difference sets because their autotopy groups act non-transitively on the indices.
gap> aut:=List(fig2,OrthogonalArrayAut); [ <permutation group with 3 generators>, <permutation group with 3 generators>, <permutation group with 3 generators>, <permutation group with 3 generators> ] gap> List(aut,x->List(Orbits(x),Size)); [ [ 12, 4, 12, 4, 12, 4 ], [ 12, 4, 12, 4, 12, 4 ], [ 8, 8, 8, 8, 8, 8 ], [ 8, 8, 8, 8, 8, 8 ] ]
Mosaics of combinatorial designs were introduced in [GGP18] and a contruction from resolvable designs was proved. This construction of mosaics is implemented in PAG for affine designs.
gap> ag123:=AffineMosaic(1,2,3); [ [ 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3 ], [ 2, 3, 1, 1, 2, 3, 2, 3, 1, 2, 3, 1 ], [ 3, 1, 2, 1, 2, 3, 3, 1, 2, 3, 1, 2 ], [ 1, 2, 3, 2, 3, 1, 3, 1, 2, 2, 3, 1 ], [ 2, 3, 1, 2, 3, 1, 1, 2, 3, 3, 1, 2 ], [ 3, 1, 2, 2, 3, 1, 2, 3, 1, 1, 2, 3 ], [ 1, 2, 3, 3, 1, 2, 2, 3, 1, 3, 1, 2 ], [ 2, 3, 1, 3, 1, 2, 3, 1, 2, 1, 2, 3 ], [ 3, 1, 2, 3, 1, 2, 1, 2, 3, 2, 3, 1 ] ] gap> MosaicParameters(ag123); "2-(9,3,1) + 2-(9,3,1) + 2-(9,3,1)" gap> ag232:=AffineMosaic(2,3,2); [ [ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 ], [ 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1 ], [ 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1 ], [ 2, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2 ], [ 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1 ], [ 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2 ], [ 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, 2 ], [ 2, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1 ] ] gap> MosaicParameters(ag232); "3-(8,4,1) + 3-(8,4,1)"
The command AffineMosaic
uses the FinInG package and is not loaded if the package is not present. Tilings of groups with difference sets [CKZ15] give rise to mosaics of symmetric designs. Here is an example of a (31,6,1) tiling and the corresponding mosaic.
gap> t:=[ [ 1, 5, 11, 24, 25, 27 ], > [ 2, 10, 17, 19, 22, 23 ], > [ 3, 4, 7, 13, 15, 20 ], > [ 6, 8, 9, 14, 26, 30 ], > [ 12, 16, 18, 21, 28, 29 ] ];; gap> m:=DifferenceMosaic(CyclicGroup(31), t);; gap> MosaicParameters(m); "2-(31,6,1) + 2-(31,6,1) + 2-(31,6,1) + 2-(31,6,1) + 2-(31,6,1)"
The paper [Krc24] gives some interesting small examples of mosaics. Files containing these examples are available on the web page
https://web.math.pmf.unizg.hr/~krcko/results/mosaics.html
gap> m:=ReadMat("13-346ex.txt")[1]; [ [ 1, 3, 3, 3, 2, 3, 2, 2, 3, 1, 3, 2, 1, 1, 3, 2, 2, 3, 3, 1, 3, 3, 3, 2, 1, 2 ], [ 1, 1, 3, 3, 3, 2, 3, 2, 2, 3, 1, 3, 2, 2, 1, 3, 2, 2, 3, 3, 1, 3, 3, 3, 2, 1 ], [ 2, 1, 1, 3, 3, 3, 2, 3, 2, 2, 3, 1, 3, 1, 2, 1, 3, 2, 2, 3, 3, 1, 3, 3, 3, 2 ], [ 3, 2, 1, 1, 3, 3, 3, 2, 3, 2, 2, 3, 1, 2, 1, 2, 1, 3, 2, 2, 3, 3, 1, 3, 3, 3 ], [ 1, 3, 2, 1, 1, 3, 3, 3, 2, 3, 2, 2, 3, 3, 2, 1, 2, 1, 3, 2, 2, 3, 3, 1, 3, 3 ], [ 3, 1, 3, 2, 1, 1, 3, 3, 3, 2, 3, 2, 2, 3, 3, 2, 1, 2, 1, 3, 2, 2, 3, 3, 1, 3 ], [ 2, 3, 1, 3, 2, 1, 1, 3, 3, 3, 2, 3, 2, 3, 3, 3, 2, 1, 2, 1, 3, 2, 2, 3, 3, 1 ], [ 2, 2, 3, 1, 3, 2, 1, 1, 3, 3, 3, 2, 3, 1, 3, 3, 3, 2, 1, 2, 1, 3, 2, 2, 3, 3 ], [ 3, 2, 2, 3, 1, 3, 2, 1, 1, 3, 3, 3, 2, 3, 1, 3, 3, 3, 2, 1, 2, 1, 3, 2, 2, 3 ], [ 2, 3, 2, 2, 3, 1, 3, 2, 1, 1, 3, 3, 3, 3, 3, 1, 3, 3, 3, 2, 1, 2, 1, 3, 2, 2 ], [ 3, 2, 3, 2, 2, 3, 1, 3, 2, 1, 1, 3, 3, 2, 3, 3, 1, 3, 3, 3, 2, 1, 2, 1, 3, 2 ], [ 3, 3, 2, 3, 2, 2, 3, 1, 3, 2, 1, 1, 3, 2, 2, 3, 3, 1, 3, 3, 3, 2, 1, 2, 1, 3 ], [ 3, 3, 3, 2, 3, 2, 2, 3, 1, 3, 2, 1, 1, 3, 2, 2, 3, 3, 1, 3, 3, 3, 2, 1, 2, 1 ] ] gap> MosaicParameters(m); "2-(13,3,1) + 2-(13,4,2) + 2-(13,6,5)"
This is the first example of an inhomogenous mosaic, containing designs with distinct parameters.
gap> m1:=ReadMat("9-3-2ex1.txt")[1]; [ [ 1, 2, 1, 1, 2, 1, 1, 3, 3, 1, 2, 3, 1, 3, 2, 1, 3, 3, 2, 2, 3, 2, 3, 2 ], [ 1, 1, 2, 1, 1, 2, 3, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 3, 3, 2, 2, 2, 2, 3 ], [ 2, 1, 1, 2, 1, 1, 3, 3, 1, 2, 3, 1, 3, 2, 1, 3, 3, 1, 2, 3, 2, 3, 2, 2 ], [ 1, 3, 2, 2, 3, 3, 1, 2, 1, 3, 3, 1, 2, 1, 2, 2, 2, 3, 1, 3, 1, 1, 3, 2 ], [ 2, 1, 3, 3, 2, 3, 1, 1, 2, 1, 3, 3, 2, 2, 1, 3, 2, 2, 1, 1, 3, 2, 1, 3 ], [ 3, 2, 1, 3, 3, 2, 2, 1, 1, 3, 1, 3, 1, 2, 2, 2, 3, 2, 3, 1, 1, 3, 2, 1 ], [ 2, 3, 3, 1, 3, 2, 3, 2, 2, 2, 2, 1, 1, 3, 3, 2, 1, 1, 1, 2, 3, 3, 1, 1 ], [ 3, 2, 3, 2, 1, 3, 2, 3, 2, 1, 2, 2, 3, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1 ], [ 3, 3, 2, 3, 2, 1, 2, 2, 3, 2, 1, 2, 3, 3, 1, 1, 1, 2, 2, 3, 1, 1, 1, 3 ] ] gap> MosaicParameters(m1); "2-(9,3,2) + 2-(9,3,2) + 2-(9,3,2)" gap> m2:=ReadMat("9-3-2ex2.txt")[1]; [ [ 1, 2, 1, 1, 2, 1, 1, 3, 3, 1, 3, 3, 1, 3, 2, 1, 2, 3, 3, 2, 2, 3, 2, 2 ], [ 1, 1, 2, 1, 1, 2, 3, 1, 3, 3, 1, 3, 2, 1, 3, 3, 1, 2, 2, 3, 2, 2, 3, 2 ], [ 2, 1, 1, 2, 1, 1, 3, 3, 1, 3, 3, 1, 3, 2, 1, 2, 3, 1, 2, 2, 3, 2, 2, 3 ], [ 1, 3, 2, 3, 3, 1, 2, 2, 1, 2, 1, 3, 3, 3, 2, 2, 3, 2, 1, 2, 1, 1, 3, 1 ], [ 2, 1, 3, 1, 3, 3, 1, 2, 2, 3, 2, 1, 2, 3, 3, 2, 2, 3, 1, 1, 2, 1, 1, 3 ], [ 3, 2, 1, 3, 1, 3, 2, 1, 2, 1, 3, 2, 3, 2, 3, 3, 2, 2, 2, 1, 1, 3, 1, 1 ], [ 2, 3, 3, 2, 3, 2, 2, 3, 1, 1, 2, 2, 1, 1, 2, 3, 1, 1, 1, 3, 3, 3, 1, 2 ], [ 3, 2, 3, 2, 2, 3, 1, 2, 3, 2, 1, 2, 2, 1, 1, 1, 3, 1, 3, 1, 3, 2, 3, 1 ], [ 3, 3, 2, 3, 2, 2, 3, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 3, 3, 3, 1, 1, 2, 3 ] ] gap> MosaicParameters(m2); "2-(9,3,2) + 2-(9,3,2) + 2-(9,3,2)"
These two mosaics cannot be obtained by the construction from [GGP18]. The first mosaic contains three isomorphic copies of a 2-(9,3,2) design that is not resolvable.
gap> d1:=BlockDesignFilter(MosaicToBlockDesigns(m1)); [ rec( blocks := [ [ 1, 2, 4 ], [ 1, 2, 7 ], [ 1, 3, 6 ], [ 1, 3, 9 ], [ 1, 4, 5 ], [ 1, 5, 8 ], [ 1, 6, 7 ], [ 1, 8, 9 ], [ 2, 3, 5 ], [ 2, 3, 8 ], [ 2, 4, 8 ], [ 2, 5, 6 ], [ 2, 6, 9 ], [ 2, 7, 9 ], [ 3, 4, 6 ], [ 3, 4, 7 ], [ 3, 5, 9 ], [ 3, 7, 8 ], [ 4, 5, 7 ], [ 4, 6, 9 ], [ 4, 8, 9 ], [ 5, 6, 8 ], [ 5, 7, 9 ], [ 6, 7, 8 ] ], isBlockDesign := true, v := 9 ) ] gap> MakeResolutionsComponent(d1[1]); gap> d1[1].resolutions.list; [ ]
The second mosaic contains three non-isomorphic designs, one resolvable and two not resolvable.
gap> d2:=BlockDesignFilter(MosaicToBlockDesigns(m2)); [ rec( blocks := [ [ 1, 2, 4 ], [ 1, 2, 5 ], [ 1, 3, 4 ], [ 1, 3, 6 ], [ 1, 5, 8 ], [ 1, 6, 7 ], [ 1, 7, 9 ], [ 1, 8, 9 ], [ 2, 3, 5 ], [ 2, 3, 6 ], [ 2, 4, 8 ], [ 2, 6, 9 ], [ 2, 7, 8 ], [ 2, 7, 9 ], [ 3, 4, 7 ], [ 3, 5, 9 ], [ 3, 7, 8 ], [ 3, 8, 9 ], [ 4, 5, 7 ], [ 4, 5, 9 ], [ 4, 6, 8 ], [ 4, 6, 9 ], [ 5, 6, 7 ], [ 5, 6, 8 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 2, 5 ], [ 1, 2, 7 ], [ 1, 3, 4 ], [ 1, 3, 9 ], [ 1, 4, 7 ], [ 1, 5, 6 ], [ 1, 6, 8 ], [ 1, 8, 9 ], [ 2, 3, 6 ], [ 2, 3, 8 ], [ 2, 4, 6 ], [ 2, 4, 9 ], [ 2, 5, 8 ], [ 2, 7, 9 ], [ 3, 4, 5 ], [ 3, 5, 7 ], [ 3, 6, 9 ], [ 3, 7, 8 ], [ 4, 5, 8 ], [ 4, 6, 7 ], [ 4, 8, 9 ], [ 5, 6, 9 ], [ 5, 7, 9 ], [ 6, 7, 8 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 2, 4 ], [ 1, 2, 8 ], [ 1, 3, 6 ], [ 1, 3, 7 ], [ 1, 4, 5 ], [ 1, 5, 9 ], [ 1, 6, 7 ], [ 1, 8, 9 ], [ 2, 3, 5 ], [ 2, 3, 9 ], [ 2, 4, 8 ], [ 2, 5, 6 ], [ 2, 6, 7 ], [ 2, 7, 9 ], [ 3, 4, 6 ], [ 3, 4, 8 ], [ 3, 5, 9 ], [ 3, 7, 8 ], [ 4, 5, 7 ], [ 4, 6, 9 ], [ 4, 7, 9 ], [ 5, 6, 8 ], [ 5, 7, 8 ], [ 6, 8, 9 ] ], isBlockDesign := true, v := 9 ) ] gap> MakeResolutionsComponent(d2[1]); gap> MakeResolutionsComponent(d2[2]); gap> MakeResolutionsComponent(d2[3]); gap> d2[1].resolutions.list; [ rec( autGroup := Group([ (1,5,8)(2,6,9)(3,4,7), (1,7,6)(2,8,4)(3,9,5), (1,2) (4,5)(7,9) ]), partition := [ rec( blocks := [ [ 1, 2, 4 ], [ 3, 8, 9 ], [ 5, 6, 7 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 2, 5 ], [ 3, 7, 8 ], [ 4, 6, 9 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 3, 4 ], [ 2, 7, 9 ], [ 5, 6, 8 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 3, 6 ], [ 2, 7, 8 ], [ 4, 5, 9 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 5, 8 ], [ 2, 6, 9 ], [ 3, 4, 7 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 6, 7 ], [ 2, 4, 8 ], [ 3, 5, 9 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 7, 9 ], [ 2, 3, 5 ], [ 4, 6, 8 ] ], isBlockDesign := true, v := 9 ), rec( blocks := [ [ 1, 8, 9 ], [ 2, 3, 6 ], [ 4, 5, 7 ] ], isBlockDesign := true, v := 9 ) ] ) ] gap> d2[2].resolutions.list; [ ] gap> d2[3].resolutions.list; [ ]
Finally, here is a mosaic of projective planes of order 3 from [Krc24].
gap> m:=ReadMat("13-4-1.txt")[1]; [ [ 0, 1, 2, 1, 3, 2, 3, 1, 1, 3, 3, 2, 2 ], [ 3, 0, 2, 3, 2, 1, 2, 1, 2, 3, 1, 1, 3 ], [ 3, 1, 0, 2, 1, 3, 3, 3, 2, 2, 1, 2, 1 ], [ 3, 3, 1, 0, 1, 1, 2, 2, 1, 2, 3, 3, 2 ], [ 2, 1, 1, 2, 0, 2, 2, 3, 3, 1, 3, 1, 3 ], [ 2, 3, 2, 3, 3, 0, 1, 3, 1, 2, 2, 1, 1 ], [ 1, 2, 2, 2, 3, 3, 0, 2, 1, 1, 1, 3, 3 ], [ 3, 2, 3, 1, 3, 1, 2, 0, 3, 1, 2, 2, 1 ], [ 1, 1, 3, 2, 2, 1, 1, 3, 0, 3, 2, 3, 2 ], [ 1, 3, 3, 1, 1, 2, 3, 2, 2, 0, 2, 1, 3 ], [ 1, 2, 1, 3, 2, 2, 3, 1, 3, 2, 0, 3, 1 ], [ 2, 2, 3, 3, 1, 3, 1, 1, 2, 1, 3, 0, 2 ], [ 2, 3, 1, 1, 2, 3, 1, 2, 3, 3, 1, 2, 0 ] ] gap> MosaicParameters(m); "2-(13,4,1) + 2-(13,4,1) + 2-(13,4,1)" gap> aut:=MatAut(m); Group([ (1,3,2)(4,6,5)(7,9,8)(10,12,11)(14,16,15)(17,19,18)(20,22,21) (23,25,24)(28,30,29) ]) gap> Size(aut); 3
The full automorphism group of this mosaic is of order 3, so it cannot be obtained by tiling groups with (13,4,1) difference sets.
generated by GAPDoc2HTML