Dear Arsene Galstyan, Dear GAP-Forum, For positive integers n and k, the DESIGN package function call SemiLatinSquareDuals(n,k) returns a list of the duals of a complete list of isomorphism class representatives of the (n x n)/k semi-Latin squares, such that two such squares are considered to be isomorphic if one can be obtained from the other by a combination of renaming symbols, row permutations, column permutations, and transposing. Thus, the isomorphism class of a semi-Latin square S (with symbol set [1..n*k]) whose dual is obtained from a call to SemiLatinSquareDuals(n,k) is the orbit of S under the group generated by symbol permutations, row permutations, column permutations, and transposing.
I've done this as shown in the appended log-file, obtaining the correct numbers of Latin squares of orders 3, 4, and 5. There are, however, much more efficient ways to find the *number* of Latin squares of order n if you are just interested in the number rather than all the Latin squares themselves. By the way, for a block design B in the DESIGN package, the component B.autSubgroup, if bound, is guaranteed to be a subgroup of the (full) automorphism group of B. Best wishes, Leonard --------------------------------------------------------------- gap> gap> LoadPackage("design"); ----------------------------------------------------------------------------- Loading GRAPE 4.7 (GRaph Algorithms using PErmutation groups) by Leonard H. Soicher (http://www.maths.qmul.ac.uk/~leonard/). Homepage: http://www.maths.qmul.ac.uk/~leonard/grape/ ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- Loading DESIGN 1.6 (The Design Package for GAP) by Leonard H. Soicher (http://www.maths.qmul.ac.uk/~leonard/). Homepage: http://www.designtheory.org/software/gap_design/ ----------------------------------------------------------------------------- true gap> gap> SemiLatinSquareFromDual := function(D) > local n,S,names,i,pt; > n:=Length(D.blocks[1]); > S:=List([1..n],x->List([1..n],y->[])); > names:=D.pointNames; > for i in [1..Length(D.blocks)] do > for pt in D.blocks[i] do > Add(S[names[pt][1]][names[pt][2]],i); > od; > od; > return S; > end; function( D ) ... end gap> gap> OnSemiLatinSquares := function(S,g) > # Returns the image T of the (n x n)/k semi-Latin square S under g, > # where g acts by permuting the symbols [1..n*k], the rows > # (labelled [n*k+1..n*k+n]) and the columns (labelled [n*k+n+1..n*k+2*n]), > # and then possibly transposing the semi-Latin square. > local n,k,i,j,newposition,T; > n:=Length(S[1]); > k:=Length(S[1][1]); > T:=List([1..n],i->[]); > for i in [1..n] do > for j in [1..n] do > newposition:=OnSets([i+n*k,j+n*k+n],g); > T[newposition[1]-n*k][newposition[2]-n*k-n]:=OnSets(S[i][j],g); > od; > od; > return T; > end; function( S, g ) ... end gap> gap> SemiLatinSquareIsomorphismClass := function(S) > # Returns the full (weak) isomorphism class of the (n x n)/k > # semi-Latin square S. > local n,k,transposer,g_symbols,g_rows,g_columns,G,i; > n:=Length(S[1]); > k:=Length(S[1][1]); > transposer:=Product(List([n*k+1..n*k+n],i->(i,i+n))); > g_symbols:=GeneratorsOfGroup(SymmetricGroup([1..n*k])); > g_rows:=GeneratorsOfGroup(SymmetricGroup([n*k+1..n*k+n])); > g_columns:=GeneratorsOfGroup(SymmetricGroup([n*k+n+1..n*k+2*n])); > G:=Group(Concatenation(g_symbols,g_rows,g_columns,[transposer])); > return Set(Orbit(G,S,OnSemiLatinSquares)); > end; function( S ) ... end gap> gap> n:=3; 3 gap> duals:=SemiLatinSquareDuals(n,1);; gap> squares:=List(duals,SemiLatinSquareFromDual); [ [ [ [ 1 ], [ 2 ], [ 3 ] ], [ [ 3 ], [ 1 ], [ 2 ] ], [ [ 2 ], [ 3 ], [ 1 ] ] ] ] gap> classes:=List(squares,SemiLatinSquareIsomorphismClass);; gap> L:=List(classes,Length); [ 12 ] gap> Sum(L); 12 gap> gap> n:=4; 4 gap> duals:=SemiLatinSquareDuals(n,1);; gap> squares:=List(duals,SemiLatinSquareFromDual); [ [ [ [ 1 ], [ 2 ], [ 3 ], [ 4 ] ], [ [ 4 ], [ 1 ], [ 2 ], [ 3 ] ], [ [ 3 ], [ 4 ], [ 1 ], [ 2 ] ], [ [ 2 ], [ 3 ], [ 4 ], [ 1 ] ] ], [ [ [ 1 ], [ 2 ], [ 3 ], [ 4 ] ], [ [ 2 ], [ 1 ], [ 4 ], [ 3 ] ], [ [ 3 ], [ 4 ], [ 1 ], [ 2 ] ], [ [ 4 ], [ 3 ], [ 2 ], [ 1 ] ] ] ] gap> classes:=List(squares,SemiLatinSquareIsomorphismClass);; gap> L:=List(classes,Length); [ 432, 144 ] gap> Sum(L); 576 gap> gap> n:=5; 5 gap> duals:=SemiLatinSquareDuals(n,1);; gap> squares:=List(duals,SemiLatinSquareFromDual); [ [ [ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ] ], [ [ 5 ], [ 1 ], [ 2 ], [ 3 ], [ 4 ] ], [ [ 4 ], [ 5 ], [ 1 ], [ 2 ], [ 3 ] ], [ [ 3 ], [ 4 ], [ 5 ], [ 1 ], [ 2 ] ], [ [ 2 ], [ 3 ], [ 4 ], [ 5 ], [ 1 ] ] ], [ [ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ] ], [ [ 3 ], [ 1 ], [ 5 ], [ 2 ], [ 4 ] ], [ [ 5 ], [ 4 ], [ 1 ], [ 3 ], [ 2 ] ], [ [ 2 ], [ 5 ], [ 4 ], [ 1 ], [ 3 ] ], [ [ 4 ], [ 3 ], [ 2 ], [ 5 ], [ 1 ] ] ] ] gap> classes:=List(squares,SemiLatinSquareIsomorphismClass);; gap> L:=List(classes,Length); [ 17280, 144000 ] gap> Sum(L); 161280 gap> On Fri, Jul 22, 2016 at 12:56:41PM +0300, Arsene Galstyan wrote: > > > Dear GAP forum, > > I'm interested in function SemiLatinSquareDuals(n,k) that is included in > the package "DESIGN". I would like to know it is possible to use this > function that to find the number of Latin squares of a given order. > As it is written in manual, this function " can classify semi-Latin squares > with certain given properties, and return a list of their duals as block > designs". Note that (nxn)/1 semi-Latin square (that is, for k = 1) is the > same thing as a Latin square of order n. > Thus, for k=1, function breaks set of Latin square of order n on the set > non-isomorphic classes. Each record resulting list corresponds exactly to one > of his class. For n=3, it returns the following: > > gap> SemiLatinSquareDuals(3,1); > [ rec( autSubgroup := Group([ (2,4)(3,7)(6,8), (2,3)(4,7)(5,9)(6,8), (1,5,9) > (2,6,7)(3,4,8), (1,4,7)(2,5,8)(3,6,9) ]), blockNumbers := [ 3 ], > blockSizes := [ 3 ], blocks := [ [ 1, 5, 9 ], [ 2, 6, 7 ], [ 3, 4, 8 ] ] > , isBinary := true, isBlockDesign := true, isSimple := true, > pointNames := [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 2, 2 ], > [ 2, 3 ], [ 3, 1 ], [ 3, 2 ], [ 3, 3 ] ], r := 1, > tSubsetStructure := rec( lambdas := [ 1 ], t := 1 ), v := 9 ) ] > > That is, as I understand it, exist only one isomorphic class, i.e. the set of > all Latin square of order 3 is one class. In other words, all Latin square of > order 3 are pairwise isomorphic. That is, one can be obtained from the other > by using composite of permutations of rows, columns and transposition > operations. > If I understand correctly, field "autSubgroup" is permutation subgroup > which is a group of automorphisms of a class of Latin squares corresponding > to this record. That is, each element of this group carries permutations of > rows, or(and) columns, or(and) transposition of Latin square. > In this way, as I think, you can act on one element of this class by all > elements of the group of automorphisms of this class in course and get all > the elements of the class, i.e., all Latin squares of order 3. > Field "blocks" is binary block design, which dual of Latin square (with the > first row is ordered), which belongs to the class of Latin squares > corresponding to this record. As I understand, the square can be recovered > from the block design in the following way. i-th block of block design > corresponding i-th symbol of Latin square and each point of block design > represents number of cells of Latin square. > In this way, it is possible to write a function that transforms a block > design of each record in the Latin square, corresponding to it, and then acts > on each obtained square of all permutations of automorphism group that > corresponds to him. > > This is text of function "ConclusionSquares": > > Print("Load 'ConclusionSquares(n)'","\n"); > ConclusionSquares:= function(n) > local i, j, k, NumberClasses, SLSD, SubsidiaryArray, ListLatinSquares, > LenList, SZ, permut, NumberRepetition, NumberRepetitionForEach, AutomSquare, > AutomSquareForEach, NumberLatinSquareForEach; > SLSD:= SemiLatinSquareDuals(n,1); > NumberClasses:= Length(SLSD); > ListLatinSquares:= [ ]; > #conclusion Latin square that corresponding of records > for i in [1..NumberClasses] do > ListLatinSquares[i]:= [ ]; > for j in [1..n] do > for k in [1..n] do > ListLatinSquares[i][SLSD[i].blocks[j][k]]:= j; > od; > od; > SubsidiaryArray:= [ ]; > for j in [1..n] do > SubsidiaryArray[j]:= [ ]; > for k in [1..n] do > SubsidiaryArray[j][k]:= ListLatinSquares[i][n*(j-1) + k]; > od; > od; > Print(" ",i,")","\n"); > Display(SubsidiaryArray); > Print("\n"); > od; > #count of Latin squares > LenList:= NumberClasses; > NumberRepetition:= 0; > AutomSquare:= 0; > for i in [1..NumberClasses] do > permut:= Difference(AsList(SLSD[i].autSubgroup),[()]); > SZ:= Size(permut); > NumberLatinSquareForEach:= 1; > NumberRepetitionForEach:= 0; > AutomSquareForEach:= 0; > for j in [1..SZ] do > SubsidiaryArray:= [ ]; > for k in [1..n*n] do > SubsidiaryArray[k^permut[j]]:= ListLatinSquares[i][k]; > od; > if (SubsidiaryArray in ListLatinSquares) then > NumberRepetitionForEach:= NumberRepetitionForEach + 1; #number > repetitions for each record > if (SubsidiaryArray = ListLatinSquares[i]) then > AutomSquareForEach:= AutomSquareForEach + 1; #number of > permutetions which not change Latin square > fi; > else > NumberLatinSquareForEach:= NumberLatinSquareForEach + 1; #number > different Latin square for each record > LenList:= LenList + 1; > ListLatinSquares[LenList]:= [ ]; > ListLatinSquares[LenList]:= SubsidiaryArray; > fi; > od; > Print ("[rec #",i,": Number elements in autSubgroup = ",SZ+1,"; Number > Latin Squares = ",NumberLatinSquareForEach,"; Number repetition = > ",NumberRepetitionForEach,"; Number automorfisms = > ",AutomSquareForEach,"]","\n","\n"); > NumberRepetition:= NumberRepetition + NumberRepetitionForEach; > AutomSquare:= AutomSquare + AutomSquareForEach; > od; > #conclusion list of Latin square > for i in [NumberClasses+1..LenList] do > SubsidiaryArray:= [ ]; > for j in [1..n] do > SubsidiaryArray[j]:= [ ]; > for k in [1..n] do > SubsidiaryArray[j][k]:= ListLatinSquares[i][n*(j-1) + k]; > od; > od; > Print(" ",i,")","\n"); > Display(SubsidiaryArray); > od; > return ["Length(ListLatinSquares)=",Length(ListLatinSquares)," > NumberRepetition=",NumberRepetition," AutomSquare=",AutomSquare]; > > end; > Function result for n=3: > > gap> ConclusionSquares(3); > 1) > [ [ 1, 2, 3 ], > [ 3, 1, 2 ], > [ 2, 3, 1 ] ] > > [rec #1: Number elements in autSubgroup = 36; Number Latin Squares = 6; > Number repetition = > 30; Number automorfisms = 5] > > 2) > [ [ 1, 3, 2 ], > [ 2, 1, 3 ], > [ 3, 2, 1 ] ] > 3) > [ [ 2, 1, 3 ], > [ 3, 2, 1 ], > [ 1, 3, 2 ] ] > 4) > [ [ 3, 1, 2 ], > [ 2, 3, 1 ], > [ 1, 2, 3 ] ] > 5) > [ [ 2, 3, 1 ], > [ 1, 2, 3 ], > [ 3, 1, 2 ] ] > 6) > [ [ 3, 2, 1 ], > [ 1, 3, 2 ], > [ 2, 1, 3 ] ] > > [ "Length(ListLatinSquares)=", 6, " NumberRepetition=", 30, " AutomSquare=", > 5 ] > > So, we got exactly 6 different squares. But the number of Latin squares of > order 3 is 12 pieces. Due to the fact that all first rows are different and > the number is 3 !, there is an idea to mix all the rows from the second to > last together. That is , multiplied by 2 !. Just get 3 ! * 2 ! = 12 . But > this idea is crumbling at n=4: > > gap> ConclusionSquares(4); > 1) > [ [ 1, 2, 3, 4 ], > [ 4, 1, 2, 3 ], > [ 3, 4, 1, 2 ], > [ 2, 3, 4, 1 ] ] > > 2) > [ [ 1, 2, 3, 4 ], > [ 2, 1, 4, 3 ], > [ 3, 4, 1, 2 ], > [ 4, 3, 2, 1 ] ] > > [rec #1: Number elements in autSubgroup = 64; Number Latin Squares = 8; > Number repetition = > 56; Number automorfisms = 7] > > [rec #2: Number elements in autSubgroup = 192; Number Latin Squares = > 24; Number repetition = 168; Number automorfisms = 7] > > [ "Length(ListLatinSquares)=", 32, " NumberRepetition=", 224, " > AutomSquare=", 14 ] > > > Latin squares of order 4 exactly 576, but 32*3!=192. In this situation , of > course, you can still guess as from 32 to receive 576 , because 576 divided > by 32. But if n=5, then > > gap> ConclusionSquares(5); > 1) > [ [ 1, 2, 3, 4, 5 ], > [ 5, 1, 2, 3, 4 ], > [ 4, 5, 1, 2, 3 ], > [ 3, 4, 5, 1, 2 ], > [ 2, 3, 4, 5, 1 ] ] > > 2) > [ [ 1, 2, 3, 4, 5 ], > [ 3, 1, 5, 2, 4 ], > [ 5, 4, 1, 3, 2 ], > [ 2, 5, 4, 1, 3 ], > [ 4, 3, 2, 5, 1 ] ] > > [rec #1: Number elements in autSubgroup = 200; Number Latin Squares = > 20; Number repetition = 180; Number automorfisms = 9] > > [rec #2: Number elements in autSubgroup = 24; Number Latin Squares = 24; > Number repetition = > 0; Number automorfisms = 0] > > [ "Length(ListLatinSquares)=", 44, " NumberRepetition=", 180, " > AutomSquare=", 9 ] > > Latin squares of order 5 exactly 161280 and 161280 is not divisible by 44. > Therefore , from the number of Latin squares , so that you can get , it is > impossible to find all the squares of a given order . That is, function > SemiLatinSquareDuals does not answer the question about the number of Latin > squares . > The following questions . Am I right? Did I everything right and > reasoned? If so, then the function SemiLatinskuare ( n , k) is not working > properly or I did not understand then what it does . > By the way, this function has a few optional parameters: > SemiLatinSquareDuals(n,k,maxmult,blockintsize, isolevel). A ll these > parameters in this case, for k=1, are not interesting , because we consider > only Latin squares . > > Thank you very much! > > Best regards, > > Arsene Galstyan > ares.1...@mail.ru > _______________________________________________ > Forum mailing list > Forum@mail.gap-system.org > http://mail.gap-system.org/mailman/listinfo/forum _______________________________________________ Forum mailing list Forum@mail.gap-system.org http://mail.gap-system.org/mailman/listinfo/forum