Goto Chapter: Top 1 2 3 4 5 6 7 8 9 10 11 12 Bib Ind
 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 

2 Constructors
 2.1 Optional arguments in constructors
 2.2 Converting betwen right quasigroups, quasigroups and loops
 2.3 *A two-step constructor
 2.4 Constructors by Cayley table
 2.5 Constructors by function
 2.6 Constructors by right section
 2.7 Constructors by right folder (transversal)
 2.8 Constructors for special types of right quasigroups
 2.9 Random right quasigroups, quasigroups and loops

2 Constructors

In this chapter we describe most constructor methods for right quasigroups.

2.1 Optional arguments in constructors

Almost all constructors in RightQuasigroups (exceptions will be noted) allow an optional argument constructorStyle, a record that determines if the constructed right quasigroup will be index based (cf. Section 1.8) and if the arguments of the constuctor will be checked.

The default value of this optional record is RQ_defaultConstructorStyle := rec( indexBased := true, checkArguments := false ). This means that all created right quasigroups will be index based and no arguments of the constructors will be checked, unless otherwise specified by the user.

The default constructor style for all constructors can be changed by calling SetDefaultConstructorStyle.

The constructor style can also be specified as an optional argument of a given constructor, either direcly, e.g., rec( indexBased := false, checkArguments := false ), or by inserting the record returned by ConstructorStyle. Furthermore, in the former case we allow the provided constructor style to be incomplete, that is, having only one (or none) of the components indexBased and checkArguments; the missing components are assumed to have default values then.

Note: As far as checking of arguments in right quasigroup constructors of RightQuasigroups is concerned, the optional component constructorStyle.checkArguments intends to replace the standard naming mechanism of GAP in which FunctionNC does not check its arguments while the corresponding Function does. The NC convention is kept outside of the constructors.

2.1-1 SetDefaultConstructorStyle
‣ SetDefaultConstructorStyle( indexBased, checkArguments )( operation )

Returns: true and changes the default constructor style according to the bool values indexBased and checkArguments.

2.1-2 ConstructorStyle
‣ ConstructorStyle( indexBased, checkArguments )( operation )

Returns: the record with elements named indexBased and checkArguments set to bool values indexBased and checkArguments, respectively. The returned record can then be used as an optional argument in constructors.

2.2 Converting betwen right quasigroups, quasigroups and loops

While GAP does not automatically recognize a right quasigroup as a quasigroup or a loop (if it happens to be one mathematically), it is possible to test these properties and convert the algebras up and down as desired.

2.2-1 IsRightQuasigroupMagma, IsLeftQuasigroupMagma, IsQuasigroupMagma and IsLoopMagma
‣ IsRightQuasigroupMagma( M )( property )
‣ IsLeftQuasigroupMagma( M )( property )
‣ IsQuasigroupMagma( M )( property )
‣ IsLoopMagma( M )( property )

Returns: true if the magma M is a right quasigroup (resp. left quasigroup, quasigroup, loop) mathematically, else returns false.

We also support IsLatinMagma as a synonym of IsQuasigroupMagma since the multiplication table of quasigroups are Latin squares.

Note that an explicit check will be carried out by each of IsRightQuasigroupMagma, IsLeftQuasigroupMagma, IsQuasigroupMagma and IsLoopMagma even if the underlying magma is declared to be a right quasigroup, quasigroup, loop, group, etc. To check only if a magma M contains a neutral element, it is also possible to call the GAP function MultiplicativeNeutralElement( M ), which returns a neutral element of M if one exists and fail otherwise.

2.2-2 AsRightQuasigroup, AsQuasigroup and AsLoop
‣ AsRightQuasigroup( M[, constructorStyle] )( operation )
‣ AsQuasigroup( M[, constructorStyle] )( operation )
‣ AsLoop( M[, constructorStyle] )( operation )

Returns: the right quasigroup, quasigroup or loop, respectively, corresponding to the magma or additive group M that is mathematically a right quasigroup, quasigroup or loop, else returns fail. If M is an additive group, the additive operation is used as multiplication. See Section 2.1 for the optional argument constructorStyle.

gap> M := MagmaByMultiplicationTable( [ [1,1], [2,2] ] );;
gap> Elements( M );
[ m1, m2 ]
gap> IsRightQuasigroupMagma( M );
true
gap> R := AsRightQuasigroup( M );
<right quasigroup of size 2>
gap> Elements( R );
[ r<object>, r<object> ]
gap> IsQuasigroupMagma( R ); # synonym of IsLatinMagma
false
gap> AsQuasigroup( M ); # arguments of constructors are by default not checked!
<quasigroup of size 2>
gap> AsQuasigroup( M, rec( checkArguments := true ) ); # the optional argument will force a check
fail
gap> G := Group((1,2,3));; IsLoopMagma( G );
true
gap> L := AsLoop( G ); # multiplicative group
<associative loop of size 3>
gap> Elements( L );
[ l(), l(1,2,3), l(1,3,2) ]
gap> AsRightQuasigroup(GF(7)^2); # additive group
<associative right quasigroup of size 49>

2.3 *A two-step constructor

Most constructors of RightQuasigroups work in two steps. In the first step, a shell of an algebra is created, with the underlying set and elements stored but with no multiplication function assigned. In the second step, the multiplication function is added, depending on the data provided by the user in the constructor.

The reason for this approach, which is particularly useful for non-index based right quasigroups, is that the multiplication function might depend on data that needs to be stored in the right quasigroup and be accessible. The first step creates the desired GAP object so that the multiplication function added in the second step can point to the stored data.

2.3-1 RQ_AlgebraShell
‣ RQ_AlgebraShell( category, S[, constructorStyle] )( operation )

Returns: an algebra shell of the appropriate category on the underlying set S. The value of category must be IsRightQuasigroup, IsQuasigroup or IsLoop.

Note: The value of constructorStyle.checkArguments of the optional argument constructorStyle does not come into play and need not be specified.

2.3-2 RQ_AddDefaultOperations
‣ RQ_AddDefaultOperations( Q )( operation )

Returns: true

This method adds all required unary and binary operations to the right quasigroup shell Q. The implied right division is always added. The implied left division is added if Q is a declared quasigroup. The implied neutral element is added if Q is a declared loop. Let F = FamilyObj( Q.1 ). If Q is index based, it is assumed that F!.multTable is bound. If Q is not index based, it is assumed that F!.mult is bound.

The following simple examples illustrates the approach, first for non-index based algebras:

gap> Q := RQ_AlgebraShell( IsRightQuasigroup, GF(5), rec( indexBased := false ) );
<right quasigroup shell of size 5>
gap> F := FamilyObj( Q.1 );;
gap> F!.mult := function(x,y) return x+y; end;;
gap> Q; # still a shell since right division is not bound
<right quasigroup shell of size 5>
gap> Q.1*Q.1; # multiplication already works since Q is not index based and F!.mult is bound
r0*Z(5)
gap> RQ_AddDefaultOperations( Q );
true
gap> Q; # all needed operations for the right quasigroup are now bound
<right quasigroup of size 5>
gap> Q.1/Q.1;
r0*Z(5)

And now for index based algebras:

gap> Q := RQ_AlgebraShell( IsRightQuasigroup, GF(5) );
<right quasigroup shell of size 5>
gap> F := FamilyObj( Q.1 );;
gap> F!.multTable := List( GF(5), x-> List( GF(5), y -> Position( Elements(GF(5)), x+y ) ) );;
gap> Q; # still a shell since right division is not bound
<right quasigroup shell of size 5>
gap> Q.1*Q.1; # multiplication already works since Q is index based and F!.multTable is bound
r0*Z(5)
gap> RQ_AddDefaultOperations( Q );
true
gap> Q; # all needed operations for the right quasigroup are now bound
<right quasigroup of size 5>
gap> Q.1/Q.1;
r0*Z(5)

2.4 Constructors by Cayley table

2.4-1 Cayley tables versus multiplication tables

Given a right quasigroup Q of size n with underlying set S, the Cayley table of Q is the n\times n array with rows and columns implictly labeled by the elements of (the sorted list) S such that the cell in row x and column y contains the element xy\in S.

In accordance with GAP conventions, given a magma M of size n with m_i denoting the ith element of M, the multiplication table of Q is the n\times n array with rows and columns implicitly labeled by [1..n] such that the cell in row i and column j contains k if m_im_j=m_k.

Analogous conventions apply to right division and left division.

Note: It is also possible to form an n\times n array with rows and columns implicitly labeled by GAP elements of Q so that the cell in row x and column y contains the GAP element x*y. Such a table can be quickly constructed from the Cayley table ct of Q by List( ct, row -> List( row, x -> Q[x] ) ), for instance. We do not introduce terminology for such tables, nor do we provide any methods for dealing with them.

2.4-2 Cayley tables and multiplication tables of right quasigroups
‣ MultiplicationTable( Q )( attribute )
‣ CayleyTable( Q )( operation )
‣ RightDivisionTable( Q )( attribute )
‣ RightDivisionCayleyTable( Q )( operation )
‣ LeftDivisionTable( Q )( attribute )
‣ LeftDivisionCayleyTable( Q )( operation )

Returns: the multiplication table, Cayley table, right division table, right division Cayley table, left division table and left division Cayley table of right quasigroup Q, respectively. For the left divisions, Q must be a declared quasigroup.

Note that the Cayley tables are not stored as attributes since they are cheap to calculate and they are affected by a possible change of the underlying set of Q.

2.4-3 Constructing division tables from multiplication tables
‣ RightDivisionTableFromMultiplicationTable( Q )( operation )
‣ LeftDivisionTableFromMultiplicationTable( Q )( operation )

It is possible to construct a right division table from the multiplication table of a right quasigroup Q of size n in O(n^2), rather than naively in O(n^3). The fast algorithm is used in the above two methods which return the right division table and the left division table of a right quasigroup Q, respectively. For the left division, Q must be a declared quasigroup.

2.4-4 Testing Cayley tables
‣ IsRightQuasigroupCayleyTable( ct )( operation )
‣ IsQuasigroupCayleyTable( ct )( operation )
‣ IsLoopCayleyTable( ct )( operation )

Returns: true if ct is a Cayley table of a right quasigroup, quasigroup or loop, respectively, otherwise returns false. The underlying set it understood to be the ordered set of elements contained in the first column of ct. This is a logical choice for right quasigroups.

2.4-5 Normalizing Cayley tables
‣ NormalizedRightQuasigroupCayleyTable( ct )( operation )
‣ NormalizedQuasigroupCayleyTable( ct )( operation )

Returns: a normalized version of the (right) quasigroup Cayley table ct.

A right quasigroup Cayley table is normalized if the entries in the first column are sorted. Every right quasigroup Cayley table can be normalized by permuting its rows.

A quasigroup Cayley table is normalized if the entires in the first column and the entries in the first row are sorted. Every right quasigroup Cayley table can be normalized by permuting its rows and columns.

gap> ct := [[1,1],[0,0]];;
gap> NormalizedRightQuasigroupCayleyTable( ct );
[ [ 0, 0 ], [ 1, 1 ] ]
gap> ct := [["b","a"],["a","b"]];;
gap> NormalizedQuasigroupCayleyTable( ct );
[ [ "a", "b" ], [ "b", "a" ] ]

2.4-6 Creating right quasigroups by Cayley table
‣ RightQuasigroupByCayleyTable( ct[, constructorStyle] )( operation )
‣ QuasigroupByCayleyTable( ct[, constructorStyle] )( operation )
‣ LoopByCayleyTable( ct[, constructorStyle] )( operation )

Returns: the right quasigroup, quasigroup or loop with Cayley table ct, respectively. See Section 2.1 for the optional argument constructorStyle.

gap> ct := [ [ "red", "white", "white" ], [ "blue", "blue", "red" ], [ "white", "red", "blue" ] ];;
gap> IsRightQuasigroupCayleyTable( ct );
true
gap> Q := RightQuasigroupByCayleyTable( ct );
<right quasigroup of size 3>
gap> Elements( Q ); # note the ordering of the elements induced by "blue" < "red" < "white"
[ rblue, rred, rwhite ]
gap> PrintArray( CayleyTable( Q ) ); # rows and column are implicitly labeled "blue", "red", "white"
[ [    red,  white,  white ],
  [   blue,   blue,    red ],
  [  white,    red,   blue ] ]
gap> Display( MultiplicationTable( Q ) ); # rows and columns are implicitly labeled 1, 2, 3
[ [  2,  3,  3 ],
  [  1,  1,  2 ],
  [  3,  2,  1 ] ]
gap> IsQuasigroupCayleyTable( ct );
false
gap> t := [ [0,1], [1,0] ];;
gap> [ IsQuasigroupCayleyTable( t ), IsLoopCayleyTable( t ) ];
[ true, true ]
gap> QuasigroupByCayleyTable( t );
<quasigroup of size 2>
gap> LoopByCayleyTable( t );
<loop of size 2>
gap> One( last );
l0

2.5 Constructors by function

In this section we describe how to construct right quasigroups, quasigroups and loops by functions.

To fix terminology, we say that a function f:S\times S\to S is a right quasigroup function if for every x\in S the function R_x:S\to S defined by R_x(y) = f(y,x) is a permutation of S. A right quasigroup function f:S\times S\to S is a quasigroup function if for every x\in S the function L_x:S\to S defined by L_x(y) = f(x,y) is a permutation of S. Finally, a quasigroup function f:S\times S\to S is a loop function if there is e\in S such that f(e,x)=x=f(x,e) for every x\in S.

2.5-1 Arguments used in constructors by function

When constructing right quasigroups, quasigroups and loops by function(s), RightQuasigroups assumes that the arguments are given as follows:

If the optional right division function is not given, it will be automatically inferred from the multiplication function. In case of quasigroups an loops, if the optional left division function is not given, it will be automatically inferred from the multiplication function. Likewise, in case of loops, if the optional neutral element is not given, it will be automatically inferred from the multiplication function.

Note that providing the division functions as arguments of non-index based algebras will typically make the division operations faster than by relying on the inferred divisions. For instance, if f(x,y)=x+y is the multiplication function and the user also provides the right division function g(x,y) = x-y, the right division will be performed faster than the default right division that searches for the first element z such that x=f(z,y).

Similar conventions hold for the methods that check whether given function(s) constitute right quasigroup, quasigroup or loop function(s), except that the constructor style is void and the missing operations are not automatically inferred from the multiplication.

2.5-2 IsRightQuasigroupFunction
‣ IsRightQuasigroupFunction( S, mult[, rdiv] )( function )

Returns: true if mult is a right quasigroup function on S, else returns false. (See Subsection 2.5-1 for how the optional arguments are treated.) If rdiv is given, it is checked that it is the right division on S corresponding to the multiplication mult.

2.5-3 IsQuasigroupFunction
‣ IsQuasigroupFunction( S, mult[, rdiv, ldiv] )( function )

Returns: true if mult is a quasigroup function on S, else returns false. (See Subsection 2.5-1 for how the optional arguments are treated.) If rdiv is given, it is checked that it is the right division on S corresponding to the multiplication mult. If ldiv is given, it is checked that it is the left division on S corresponding to the multiplication mult.

gap> mult := function( x, y ) return (x+2*y) mod 4; end;
function( x, y ) ... end
gap> IsRightQuasigroupFunction( [0..3], mult );
true
gap> IsQuasigroupFunction( [0..3], mult );
false

2.5-4 IsLoopFunction
‣ IsLoopFunction( S, mult[, rdiv, ldiv, one] )( function )

Returns: true if mult is a loop function on S, else returns false. (See Subsection 2.5-1 for how the optional arguments are treated.) If rdiv is given, it is checked that it is the right division on S corresponding to the multiplication mult. If ldiv is given, it is checked that it is the left division on S corresponding to the multiplication mult. If one is given, it is checked that it is is the neutral element with respect to mult.

gap> mult := \+;;
gap> rdiv := \-;;
gap> ldiv := function( x,y ) return -x+y; end;;
gap> one := Zero( GF(5) );;
gap> IsLoopFunction( GF(5), mult ); 
true
gap> IsLoopFunction( GF(5), mult, rdiv );
true
gap> IsLoopFunction( GF(5), mult, rdiv, ldiv );
true
gap> IsLoopFunction( GF(5), mult, one );
true
gap> IsLoopFunction( GF(5), mult, rdiv, one );
true
gap> IsLoopFunction( GF(5), mult, rdiv, ldiv, one );
true
gap> IsLoopFunction( GF(5), mult, ldiv ); # returns false because right division is expected before left division
false

2.5-5 Multiplication, right division and left division functions
‣ MultiplicationFunction( Q )( operation )
‣ RightDivisionFunction( Q )( operation )
‣ LeftDivisionFunction( Q )( operation )

Returns, respectively, the multiplication function, right division function and left division function of right quasigroup Q as a GAP function. For the left division, Q must be a declared quasigroup. If the requested function is not bound, returns fail. See Section 1.8 for more details on multiplication and division functions in index based and non-index based right quasigroups.

2.5-6 RightQuasigroupByFunction
‣ RightQuasigroupByFunction( S, mult[, rdiv][, constructorStyle] )( function )

Returns: a right quasigroup with underlying set S and multiplication function mult. If rdiv is given, it becomes the right division function, else the right division function is automatically inferred from mult. See Subsection 2.5-1 for the optional argument constructorStyle.

2.5-7 QuasigroupByFunction
‣ QuasigroupByFunction( S, mult[, rdiv, ldiv][, constructorStyle] )( function )

Returns: a quasigroup with underlying set S and multiplication function mult. If rdiv (resp. ldiv) is given, it is set as the right (resp. left) division function, else the right (resp. left) division function is automatically inferred from mult. See Subsection 2.5-1 for the optional argument constructorStyle.

gap> S := GF(5);;
gap> mult := function( x, y ) return x+2*y; end;;
gap> IsQuasigroupFunction( S, mult );
true
gap> QuasigroupByFunction( S, mult ); # it is not necessary to provide right division and left division
<quasigroup of size 5>
gap> rdiv := function( x, y ) return x-2*y; end;;
gap> ldiv := function( x, y ) return (y-x)/2; end;;
gap> IsQuasigroupFunction( S, mult, rdiv, ldiv ); 
true
gap> QuasigroupByFunction( S, mult, rdiv, ldiv ); # but calculations will be faster if the divisions are provided
<quasigroup of size 5>

2.5-8 LoopByFunction
‣ LoopByFunction( S, mult[, rdiv, ldiv, one][, constructorStyle] )( function )

Returns: a loop with underlying set S and multiplication function mult. If rdiv (resp. ldiv) is given, it is set as the right (resp. left) division function, else the right (resp. left) division function is automatically inferred from mult. If one is given, it is set as the neutral element, else it is automatically inferred from mult. See Subsection 2.5-1 for the optional argument constructorStyle.

The following constructor produces a loop of size just over 1 million near instantaneously since nothing is checked.

gap> p := 1000003;;
gap> S := Difference( GF(p), [ Zero( GF( p ) ) ] );; # nonzero elements of GF(p)
gap> Q := LoopByFunction( S, \*, ConstructorStyle( false, false ) ); # not index based, no arguments checked
<loop of size 1000002>
gap> One( Q );
lZmodpZObj(1,1000003)
gap> Q.10*Q.100;
lZmodpZObj(1000,1000003)
gap> Q.100/Q.10;
lZmodpZObj(10,1000003)
gap> Inverse( Q.10 );
lZmodpZObj(300001,1000003)

2.6 Constructors by right section

For a right quasigroup (Q,\cdot), the right section is the ordered tuple R_Q = (R_x:x\in Q) of right translations of Q. Since xy = R_y(x), the multiplication in (Q,\cdot) can be fully reconstructed from its right section.

A right section (Q,R_Q) is a quasigroup right section (resp. loop right section) if the corresponding right quasigroup is a quasigroup (resp. loop).

In RightQuasigroups, a right section consists of the underlying set S of size n and an ordered collection of n group elements that act on S. Implicit right sections are also allowed, that is, a set S of size n and an ordered collection of permutations on [1..n], in which case x^f=y if and only if x is the ith element of S, i^f=j and y is the jth element of S.

2.6-1 Testing right sections
‣ IsRightSection( [S, ]section )( operation )
‣ IsQuasigroupRightSection( [S, ]section )( operation )
‣ IsLoopRightSection( [S, ]section )( operation )

Returns: true if section is a right section (resp. quasigroup right section, loop right section) on S, else returns false. If S is omitted, section must be a list of permutations; the underlying set is then understood to be [1..Length(section)].

2.6-2 Constructing right quasigroups, quasigroups and loops by right section
‣ RightQuasigroupByRightSection( [S, ]section[, constructorStyle] )( operation )
‣ QuasigroupByRightSection( [S, ]section[, constructorStyle] )( operation )
‣ LoopByRightSection( [S, ]section[, constructorStyle] )( operation )

Returns: a right quasigroup, quasigroup or loop on S with right section section, respectively. If S is omitted, section must be a list of permutations; the underlying set is then understood to be [1..Length(section)]. See Section 2.1 for the optional argument constructorStyle.

Here is an example of a right quasigroup constructed by a right section consisting of permutations.

gap> section := [ (), (1,2,3,4), (), (1,3)(2,4) ];;
gap> IsRightSection( [1..4], section );
true
gap> IsRightSection( section ); # the underlying set can be omitted
true
gap> IsRightSection( "abcd", section ); # implicit permutation action on the set ['a','b','c','d']
true
gap> IsQuasigroupRightSection( [1..4], section );
false
gap> Q := RightQuasigroupByRightSection( section ); # the underlying set can be omitted
<right quasigroup of size 4>
gap> Q[3]*Q[2];
r4
gap> RightQuasigroupByRightSection( "abcd", section );
<right quasigroup of size 4>
gap> Elements( last );
[ r'a', r'b', r'c', r'd' ]

Here is an example of a right quasigroup constructed by a right section consisting of group elements acting on the underlying set, in this case of matrices acting on GF(2)^2.

gap> i := Z(2)*[[1,0],[0,1]];;
gap> m := Z(2)*[[1,1],[0,1]];;
gap> section := [m,m,i,i];;
gap> IsRightSection( GF(2)^2, section );
true
gap> Q := RightQuasigroupByRightSection( GF(2)^2, section );
<right quasigroup of size 4>
gap> Q.1;
r[ 0*Z(2), 0*Z(2) ]

We conclude with an example of a loop constructed by a right section. Note that the neutral element is not the first element of the underlying set.

gap> section := [(1,2),()];;
gap> IsQuasigroupRightSection( [1,2], section );
true
gap> QuasigroupByRightSection( [1,2], section );
<quasigroup of size 2>
gap> IsLoopRightSection( [1,2], section );
true
gap> LoopByRightSection( [1,2], section );
<loop of size 2>
gap> One( last );
l2

2.7 Constructors by right folder (transversal)

The triple (G,H,T) is a right folder if G is a group, H is a subgroup of G and T is a right transversal to H in G.

Given a right folder (G,H,T), we can define a magma (T,\circ) by setting x\circ y = z iff xy\in Hz, for x,y,z\in T. Then (T,\circ) is always a right quasigroup. Not every right quasigroup is obtained in this way.

The right folder (G,H,T) is a quasigroup right folder (resp. loop right folder) if (T,\circ) is a quasigroup (resp. loop). Group-theoretically, (G,H,T) is a quasigroup right folder iff T is a right transversal to every conjugate H^g of H in G. Furthermore, a quasigroup right folder (G,H,T) is a loop right folder iff T intersects the core of H in G, i.e., the normal subgroup \bigcap_{g\in G}H^g.

Up to isomorphism, every quasigroup (resp. loop) is obtained as (T,\circ) for some quasigroup (resp. loop) folder (G,H,T).

In functions that require right folders, we allow two types of arguments:

The reason for the second option is that while GAP calculates a right transversal to H in G via RightTransversal( G, H ), it might not be the desired right transversal required for the construction of a particular right quasigroup, quasigroup or loop.

2.7-1 Checking right folders
‣ IsRightFolder( arg )( operation )
‣ IsQuasigroupRightFolder( arg )( operation )
‣ IsLoopRightFolder( arg )( operation )

Returns: true if the argument is a right folder (resp. quasigroup right folder, loop right folder). See above for the two possible formats of the argument arg, that is, T or G,H,T.

2.7-2 Creating right quasigroups, quasigroups and loops by right folders
‣ RightQuasigroupByRightFolder( arg[, constructorStyle] )( operation )
‣ QuasigroupByRightFolder( arg[, constructorStyle] )( operation )
‣ LoopByRightFolder( arg[, constructorStyle] )( operation )

Returns: a right quasigroup (resp. quasigroup or loop) from the given right folder (resp. quasigroup right folder, loop right folder). See above for the two possible formats of the argument arg, that is, T or G,H,T. See Section 2.1 for the optional argument constructorStyle.

Here is an example of a right quasigroup constructed from a right folder.

gap> G := SymmetricGroup( 5 );;
gap> H := Subgroup( G, [ (1,2),(1,3) ] );;
gap> T := RightTransversal( G, H );;
gap> [ IsRightFolder( T ), IsRightFolder( G, H, T ) ];
[ true, true ]
gap> Q1 := RightQuasigroupByRightFolder( T );
<right quasigroup of size 20>
gap> Q2 := RightQuasigroupByRightFolder( G, H, T );
<right quasigroup of size 20>
gap> Q3 := RightQuasigroupByRightFolder( G, H, Elements( T ) );
<right quasigroup of size 20>
gap> AsCanonicalPerm( IsomorphismRightQuasigroups( Q1, Q2 ) );
()
gap> UnderlyingSet( Q1 ) = Elements( T );
true
gap> IsQuasigroupRightFolder( T );
false

And here is an example of a loop constructed from a (trivial) right folder.

gap> G := SymmetricGroup( 2 );;
gap> H := Subgroup( G, [()] );;
gap> T := RightTransversal( G, H );;
gap> IsQuasigroupRightFolder( T );
true
gap> IsLoopRightFolder( T );
true
gap> QuasigroupByRightFolder( T );
<quasigroup of size 2>
gap> LoopByRightFolder( T );
<loop of size 2>
gap> Elements( last );
[ l(), l(1,2) ]

2.8 Constructors for special types of right quasigroups

Here we collect a few constructors for special types of right quasigroups.

2.8-1 ProjectionRightQuasigroup
‣ ProjectionRightQuasigroup( S[, constructorStyle] )( operation )

Returns: the projection right quasigroup on the set S that is, a magma on S with mutliplication x*y=x. We also allow S to be a positive integer n, in which case the underlying set will be [1..n].

Note: The value of constructorStyle.checkArguments of the optional argument constructorStyle does not come into play and need not be specified.

gap> ProjectionRightQuasigroup( [1..1000], rec( indexBased := false ) );; # 16 ms to construct, 
gap> Q := ProjectionRightQuasigroup( [1..1000] );; # 375 ms to construct
gap> Q.123*Q.456;
r123

2.9 Random right quasigroups, quasigroups and loops

Random right quasigroups are easy to construct since the right translations of individual elements are independent from each other. It therefore suffices to construct their right section (R_x:x\in Q) as a random tuple of permutations of Q.

Random quasigroups and loops are harder to construct. The Jacobson and Matthews random walk method for random latin squares is implemented in RightQuasigroups with some ad hoc mixing parameters. We always start with the multiplication table of the cyclic group of order n and perform certain random local changes in the multiplication table. It is proved by Jacobson and Matthews that the resulting random walk visits all latin squares uniformly. If a loop is desired, we normalize the random latin square in the last step.

2.9-1 RandomRightQuasigroup
‣ RandomRightQuasigroup( S[, constructorStyle] )( operation )

Returns: a random right quasigroup on the underlying set S. We also allow S to be a positive integer n, in which case the underlying set will be [1..n].

Note: The value of constructorStyle.checkArguments of the optional argument constructorStyle does not come into play and need not be specified.

2.9-2 Random quasigroups and loops
‣ RandomQuasigroup( S[, iter] )( operation )
‣ RandomLoop( S[, iter] )( operation )

Returns: a random quasigroup (loop) on the underlying set S, using iter number of random steps to move into an initial position in the Jacobson and Matthews algorithm. We also allow S to be a positive integer n, in which case the underlying set will be [1..n]. If the optional argument iter is not given, its value will be set to n^3. The resulting quasigroup or loop will be always index based (since the algorithm constructs a multiplication table anyway).

gap> RandomRightQuasigroup( 4 );
<right quasigroup of size 4>
gap> Elements( RandomQuasigroup( ["a","b","c"] ) );
[ qa, qb, qc ]
gap> RandomLoop( ["a","b","c"] );
<loop of size 3>

2.9-3 RandomNilpotentLoop
‣ RandomNilpotentLoop( lst )( operation )

Returns: a random nilpotent loop. lst must be a list of positive integers and/or finite abelian groups. If lst = [a1,..,am] and a1 is an integer, returns a central extension of a random abelian group of order a1 by RandomNilpotentLoop( [a2,...,am] ). If lst = [a1,..,am] and a1 is an abelian group, returns a central extension of a1 by RandomNilpotentLoop( [a2,...,am] ).

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

 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 
Goto Chapter: Top 1 2 3 4 5 6 7 8 9 10 11 12 Bib Ind

generated by GAPDoc2HTML