[loops] 4 Creating quasigroups and loops

[Up] [Previous] [Next] [Index]

# 4 Creating quasigroups and loops

### Sections

1. About Cayley tables
2. Testing Cayley tables
3. Canonical and normalized Cayley tables
4. Creating quasigroups and loops manually
5. Creating quasigroups and loops from a file
6. Creating quasigroups and loops by sections
7. Creating quasigroups and loops by extensions
8. Random quasigroups and loops
9. Conversions
10. Products of loops
11. Opposite quasigroups and loops

In this chapter we describe several ways in which quasigroups and loops can be created in LOOPS.

## 4.1 About Cayley tables

Let X={x1,...,xn} be a set and · a binary operation on X. Then an n by n array with rows and columns bordered by x1, ..., xn, in this order, is a Cayley table, or a multiplication table of ·, if the entry in the row xi and column xj is xi·xj.

A Cayley table is a quasigroup table if it is a Latin square, i.e., if every entry xi appears in every column and every row exactly once.

An annoying feature of quasigroup tables in practice is that they are often not bordered, and it is up to the reader to figure out what is meant. Throughout this manual and in LOOPS, we therefore make the following assumption: All distinct entries in a quasigroup table must be integers, say x1 < x2 < … < xn, and if no border is specified, we assume that the table is bordered by x1, ..., xn, in this order. Note that we do not assume that the distinct entries x1, ..., xn form the interval 1, ..., n. The significance of this observation will become clear in Chapter Methods based on permutation groups.

Finally, we say that a quasigroup table is a loop table if the first row and the first column are the same, and if the entries in the first row are ordered in an ascending fashion.

## 4.2 Testing Cayley tables

A square array with integral entries is called a matrix in GAP. The following synonymous operations test if a matrix T is a quasigroup table, as defined above:

- `IsQuasigroupTable(` T`) O`
- `IsQuasigroupCayleyTable(` T`) O`

  The following synonymous operations test if a matrix T is a loop table:

- `IsLoopTable(` T`) O`
- `IsLoopCayleyTable(` T`) O`

  We would like to call attention to the fact that the package GUAVA also has some operations dealing with Latin squares. In particular, `IsLatinSquare` is declared in GUAVA.

  ## 4.3 Canonical and normalized Cayley tables

  Although we do not assume that a quasigroup table with distinct entries x1 < … < xn satisfies xi=i, it is often desirable to present quasigroup tables in the latter way. The rather general operation

- `CanonicalCayleyTable(` T`) O`

  takes any Cayley table T with distinct entries x1 < … < xn, and returns a Cayley table in which xi has been replaced by i.

  The operation

- `NormalizedQuasigroupTable(` T`) O`

  makes a quasigroup table T into a loop table by:

  - first calling `CanonicalCayleyTable` to rename the entries to 1, ..., n,
  - then permuting the columns of T so that the first row reads 1, ..., n,
  - and then permuting the rows of T so that the first column reads 1, ..., n.

  ## 4.4 Creating quasigroups and loops manually

  When T is a quasigroup table, the corresponding quasigroup is obtained by

- `QuasigroupByCayleyTable(` T`) O`

  Since `CanonicalCayleyTable` is called within the above operation, the resulting quasigroup will have a Cayley table with distinct entries 1, ..., n.

  Here is the analogous operation for a loop table T:

- `LoopByCayleyTable(` T`) O`

  And here is an example for methods concerning Cayley tables:

      gap> ct := CanonicalCayleyTable( [[5,3],[3,5]] );
      [ [ 2, 1 ], [ 1, 2 ] ]
      gap> NormalizedQuasigroupTable( ct );
      [ [ 1, 2 ], [ 2, 1 ] ]
      gap> LoopByCayleyTable( last );
      <loop of order 2>
      gap> [ IsQuasigroupTable( ct ), IsLoopTable( ct ) ];
      [ true, false ]

  ## 4.5 Creating quasigroups and loops from a file

  Typing a large multiplication table manually is tedious and error-prone. We have therefore included a universal algorithm in LOOPS that reads multiplication tables of quasigroups from a file.

  Instead of writing a separate algorithm for each common format, our algorithm relies on the user to provide a bit of information about the input file. Here is an outline of the algorithm, with file named F and a string D as arguments on the input:

  - read the entire content of F into a string S,
  - replace all end-of-line characters in S by spaces,
  - replace by spaces all characters of S that appear in D,
  - split S into maximal substrings without spaces, called chunks,
  - recognize distinct chunks (let n be the number of distinct chunks),
  - if the number of chunks is not n2, report error,
  - construct the multiplication table by assigning numerical values 1, ..., n to chunks, depending on their position among distinct chunks.

  The following examples clarify the algorithm and document its versatility. All examples are of the form F+D⇒ T, meaning that an input file containing F together with the string D produce multiplication table T.

  Example 1: Data does not have to be arranged into an array of any kind.

  0
  1
  2
  1
  2
  0
  2
  0
  1
  +
  ""
  ⇒
  1
  2
  3
  2
  3
  1
  3
  1
  2

  Example 2: Chunks can be any strings.

  red
  green
  green
  red
  +
  ""
  ⇒
  1
  2
  2
  1

  Example 3: A typical table produced by GAP is easily parsed by deleting brackets and commas.

  [ [0, 1], [1, 0] ]
  +
  "[,]"
  ⇒ |
  1
  2
  2
  1

  Example 4: A typical TeX table with rows separated by lines is also easily converted. Note that we have to use \\ to make sure that every occurrence of \ is deleted, since \\ represents the character \ in GAP.

  x& y& z\cr
  y& z& x\cr
  z& x& y
  | +
  "\\cr&"
  ⇒
  1
  2
  3
  2
  3
  1
  3
  1
  2

  And here are the needed \LOOPS commands:

- `QuasigroupFromFile(` F`,` D`) O`
- `LoopFromFile(` F`,` D`) O`

  ## 4.6 Creating quasigroups and loops by sections

  Let P be a set of n permutations of an n-element set X. If at most one permutation of P is the identity permutation, and if all other permutations of P move all points of X, the operation

- `CayleyTableByPerms(` P`) O`

  returns an n×n Cayley table C such that `C[i][j] = X[j]^P[i]`.

  In particular, if P is the left section of a quasigroup Q, the above operation returns the multiplication table of Q.

  If P is a set of permutations corresponding to the left translations of a quasigroup (or loop) Q, the operation

- `QuasigroupByLeftSection(` P`) O`
- `LoopByLeftSection(` P`) O`

  returns the corresponding quasigroup (or loop). The order of permutations in P is important in the quasigroup case, but it is disregarded in the loop case, since the order of rows in the corresponding multiplication table is determined by the presence of the neutral element.

  Analogously, we define

- `QuasigroupByRightSection(` P`) O`
- `LoopByRightSection(` P`) O`

  Here is an example:

      gap> S := Subloop( MoufangLoop( 12, 1 ), [ 3 ] );;
      gap> ls := LeftSection( S );
      [ (), (1,3,5), (1,5,3) ]
      gap> CayleyTableByPerms( ls );
      [ [ 1, 3, 5 ], [ 3, 5, 1 ], [ 5, 1, 3 ] ]
      gap> CayleyTable( LoopByLeftSection( ls ) );
      [ [ 1, 2, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ] ]

  Let G be a group, H a subgroup, and T a right transversal to H in G. Then the operation ° defined on the right cosets Q = {Ht; t ∈ T} by Ht°Ht′ = H(tt′) turns Q into a quasigroup if and only if T is a right transversal to all conjugates g−1Hg of H in G. In fact, every quasigroup Q can be obtained in this way (let G=Mlt(Q), H=RMlt(Q) and T={Rx; x ∈ Q}).

  The resulting quasigroup (or loop) is returned via

- `QuasigroupByRightSection(` G`,` H`,` T`) O`
- `LoopByRightSection(` G`,` H`,` T`) O`

  We do not support the dual operations for left sections since, by default, actions in GAP act on the right.

  To demonstrate `LoopByRightSection`, let us recall a construction due to Nagy Na:

  Let X be a simple group with subgroups Y0, Y1 such that Y0∩Y1=1 and X=Y0Y1. Let G=X×X and H=Y0×Y1. Then T = {(x,x−1); x ∈ X} is a right transversal of H in G, and the corresponding loop is a simple (right) Bol loop.

  The next example illustrates this construction with X=A5, Y0=A4, and Y1 = 〈(1,2,3,4,5)〉.

      gap> Shift := function( p ) # shifts permutation "up" by 5
      >       local ls;
      >       ls := ListPerm( p );
      >       ls := Concatenation( [1,2,3,4,5], List( ls, x -> x + 5 ) );
      >       return PermList( ls );
      > end;
      function( p ) ... end
      gap> A := AlternatingGroup( 5 );;
      gap> G := DirectProduct( A, A );;
      gap> H := Subgroup( G, [ (1,2,3), (2,3,4), (6,7,8,9,10) ] );;
      gap> T := List( A, x -> x * Shift(x)^(-1) );;
      gap> L := LoopByRightSection( G, H, T );
      <loop of order 60>
      gap> [ IsRightBolLoop( L ), IsSimple( L ), IsMoufangLoop( L ) ];
      [ true, true, false ]

  ## 4.7 Creating quasigroups and loops by extensions

  If Q is a loop and K an abelian subgroup of N(Q) then

- `NuclearExtension(` Q`,` K`) O`

  returns [K0, F, ϕ, θ], where K0 ≅ K, F ≅ Q/K, ϕ:F→AutK is a homomorphism, θ:F×F→ K is a cocycle, and Q is isomorphic to K0×F with multiplication (a,x)(b,y) = (aϕx(b)θ(x,y),xy).

  If n=|F| and m=|K|, the cocycle θ is returned as an n×n array with entries in {1,...,m}, and ϕ is returned as a list of length n of permutations of {1,...,m}.

  Conversely, given K, F, f = ϕ, and t = θ as above,

- `LoopByExtension(` K`,` F`,` f`,` t`) O`

  returns the extension of K by F using the action f and cocycle t.

      gap> F := IntoLoop( Group( (1,2) ) );
      <loop of order 2>
      gap> K := DirectProduct( F, F );;
      gap> phi := [ (), (2,3) ];;
      gap> theta := [ [ 1, 1 ], [ 1, 3 ] ];;
      gap> LoopByExtension( K, F, phi, theta );
      <loop of order 8>
      gap> IsAssociative( last );
      false

  ## 4.8 Random quasigroups and loops

  We say that an algorithm selects a latin square of order n at random if every latin square of order n is returned by the algorithm with the same probability. Selecting a latin square at random is a nontrivial problem.

  In JaMa, Jacobson and Matthews defined a random walk on the space of latin squares and so-called improper latin squares that visits every latin square with the same probability. The diameter of the space is no more than 4(n−1)3, that is, no more than 4(n−1)3 steps are needed to travel from one latin square of order n to another.

  The Jacobson-Matthews algorithm can be used to generate random quasigroups as follows: (i) select any latin square of order n, for instance the canonical multiplication table of the cyclic group of order n, (ii) perform sufficiently many steps of the random walk, stopping at a proper or improper latin square, (iii) if necessary, perform a few more steps to end up with a proper latin square. Upon normalizing the resulting latin square, we obtain a random loop of order n.

  By the above result, it suffices to use about n3 steps to arrive at any latin square of order n from the initial latin square. In fact, a much smaller number of steps is probably sufficient.

- `RandomLoop(` n`) O`

  returns a random loop of order n, using the Jacobson-Matthews algorithm with n3 steps. Every loop of order n is potentially returned, but the method is slow for n > 50, say. You can control the trade-off between randomness and speed with

- `RandomLoop(` n`,` iter`) O`

  returns a random loop of order n, using the Jacobson-Matthews algorithm with iter many steps. When iter is small, the returned loop will be close to the canonical Cayley table of the cyclic group of order n.

  The corresponding commands for random quasigroups are

- `RandomQuasigroup(` n`) O`
- `RandomQuasigroup(` n`,` iter`) O`

  Finally,

- `RandomNilpotentLoop(` lst`) O`

  returns a random nilpotent loop as follows (see Section Nilpotency and central series for more on nilpotency):

  lst must be a list of positive integers and/or finite abelian groups. If lst = [a1] and a1 is an integer, a random abelian group of order a1 is returned, else a1 is an abelian group and `AsLoop(` a1 `)` is returned. If lst =[a1,...,am], a random central extension of `RandomNilpotentLoop(` [a1] `)` by `RandomNilpotentLoop(` [a2,...,am] `)` is returned.

  To determine the nilpotency class c of the resulting loop, assume that lst has length at least 2, contains only integers bigger than 1, and let m be the last entry of lst. If m > 2 then c= `Length(`lst`)`, else c= `Length(`lst`)`−1.

  ## 4.9 Conversions

  As we have already mentioned, LOOPS contains methods that convert between magmas, quasigroups, loops and groups, provided such conversions are possible.

  If M is a declared magma that happens to be a quasigroup, the corresponding quasigroup is returned via

- `IntoQuasigroup(` M`) O`

  Note that if M is already declared as a quasigroup, `IntoQuasigroup(` M`)` merely returns M.

  Given a quasigroup M and two of its elements f, g, the principal loop isotope x°y = Rg−1(x)·Lf−1(y) turns (M,°) into a loop with neutral element f·g (see Section Homomorphisms and homotopisms). Since loops in LOOPS have to have neutral element labeled as 1, the function

- `PrincipalLoopIsotope(` M`,` f`,` g`)`

  returns an isomorphic copy of the principal isotope (M,°) via the transposition (1,f·g).

  If M is a declared magma that happens to be a quasigroup (not necessarily a loop!), the operation

- `IntoLoop(` M`) O`

  returns a loop L as follows:

  - if M is already declared as a loop, L=M, else
  - if M possesses a neutral element e and f is the first element of M, then L is an isomorphic copy of M via the transposition (e,f), else
  - if M does not posses a neutral element, L is returned as `PrincipalLoopIsotope(` M`,` M.1`,` M.1`)`

  One could obtain a loop from M in yet another way, by normalizing the Cayley table of M. These three approaches can result in nonisomorphic loops in general.

  Finally, when M is a declared magma that happens to be a group, the corresponding group is returned by

- `IntoGroup(` M`) O`

  as follows:

  - if M is already declared as a group, M is returned, else
  - `RightMultiplciationGroup( IntoLoop(` M`) )` is returned, i.e., a permutation group isomorphic to M.

  All three conversion methods return `fail` if the requested conversion is not possible.

  Up to version 2.0.0, we have supported `AsQuasigroup`, `AsLoop` and `AsGroup` in place of `IntoQuasigroup`, `IntoLoop` and `IntoGroup`, respectively. We have changed the terminology starting with version 2.1.0 in order to comply with GAP naming rules for `AsSomething`, as explained in Chapter How the package works. Finally, the method `AsGroup` is built into the core of GAP and it returns an fp group if its argument is an associative loop.

  ## 4.10 Products of loops

  noindentLet L1, ..., Ln be a list consisting of loops and groups, where n ≥ 1. Then

- `DirectProduct(` L1`, ...,` Ln`) O`

  returns the direct product of L1, ..., Ln.

  If there are only groups among L1, ..., Ln, a group is returned. Otherwise a loop is returned. If n=1, L1 is returned.

  ## 4.11 Opposite quasigroups and loops

  When Q is a quasigroup with multiplication ·, the opposite quasigroup of Q is a quasigroup with the same underlying set as Q and with multiplication * defined by x*y=y·x.

  Since the quasigroup-theoretical concepts are often chiral (cf. left Bol loops versus right Bol loops), it is useful to have access to the opposite quasigroup of Q:

- `Opposite(` Q`) O`

  [Up] [Previous] [Next] [Index]