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] 

3 Direct products, subalgebras and factor algebras
 3.1 Direct product of right quasigroups
 3.2 Opposite quasigroups
 3.3 Subalgebras
 3.4 Cosets and transversals
 3.5 Right quasigroups by generators
 3.6 Intersections and joins of right quasigroups
 3.7 Congruences
 3.8 Normality and simplicity
 3.9 Factor algebras
 3.10 An example of the factor construction: Paige loops

3 Direct products, subalgebras and factor algebras

In this chapter we describe methods of universal-algebraic flavor for right quasigroups.

3.1 Direct product of right quasigroups

DirectProduct(Q1,...,Qn) returns the direct product of right quasigroups Q1, ..., Qn. We allow groups to be among the arguments.

If all arguments are groups then the standard GAP method is called and a group is returned.

Otherwise, if all non-group arguments are loops then a loop is returned, else if all non-group arguments are quasigroups then a quasigroup is returned, else a right quasigroup is returned. The underlying set is the carthesian product of elements of Q1, ..., Qn. The restulting algebra is index based if and only if all non-group arguments are index based. An effort is made to inherit common properties of Q1, ...,. Qn.

gap> G := Group((1,2));;
gap> L := LoopByCayleyTable( [[1,2,3],[2,3,1],[3,1,2]] );;
gap> R := ProjectionRightQuasigroup( [1..3] );;
gap> D := DirectProduct( G, L );
<loop of size 6>
gap> D.1;
l[ (), l1 ]
gap> DirectProduct( G, L, R );
<right quasigroup of size 18>

3.2 Opposite quasigroups

Given a quasigroup (Q,\cdot), its opposite is the quasigroup (Q,\circ) with multiplication x\circ y = y\cdot x. If (Q,\cdot) is a loop, its opposite is also a loop. (Note that the opposite of a right quasigroup Q is a right quasigroup iff Q is a quasigroup. We therefore do not support the opposite construction for right quasigroups.)

3.2-1 Opposite quasigroups and loops
‣ OppositeQuasigroup( Q )( operation )
‣ OppositeLoop( Q )( operation )

Returns: the opposite quasigroup (loop) of the quasigroup (loop) Q. The resulting algebra is index based iff Q is index based. An effort is made to inherit dual properties from Q

gap> Q := QuasigroupByFunction( GF(3), \- );;
gap> OQ := OppositeQuasigroup( Q );
<quasigroup of size 3>
gap> Display( MultiplicationTable( Q ) );
[ [  1,  3,  2 ],
  [  2,  1,  3 ],
  [  3,  2,  1 ] ]
gap> Display( MultiplicationTable( OQ ) );
[ [  1,  2,  3 ],
  [  3,  1,  2 ],
  [  2,  3,  1 ] ]
gap> B := LeftBolLoop( 8, 1 );
LeftBolLoop( 8, 1 )
gap> OppositeLoop( B ); # dual properties inherited
<right Bol loop of size 8>

3.3 Subalgebras

A subset S of a right quasigroup Q is a subrightquasigroup of Q if it is closed under multiplication and right division. A subset S of a quasigroup (resp. loop) Q is a subquasigroup (resp. subloop) if it is closed under multiplication and both divisions. In all of the above cases, when Q is finite, S is a subalgebra if it is closed under multiplicaton.

In RightQuasigroups, if a subalgebra S is created from an algebra Q, the parent of S is set to the parent of Q, possibly Q itself, and the elements of S are inherited from the parent of Q, cf. Section 1.7. If A, B are two algebras then A is a subalgebra of B iff Parent( A ) = Parent( B ) and the elements of A form a subset of B.

3.3-1 Testing for subalgebras
‣ IsSubrightquasigroup( Q, S )( operation )
‣ IsSubquasigroup( Q, S )( operation )
‣ IsSubloop( Q, S )( operation )

Returns: true if a right quasigroup (quasigroup, loop) S is a subrightquasigroup (subquasigroup, subloop) of a right quasigroup (quasigroup, loop) Q, else returns false.

3.3-2 Constructing subalgebras
‣ Subrightquasigroup( Q, gens )( operation )
‣ Subquasigroup( Q, gens )( operation )
‣ Subloop( Q, gens )( operation )

Returns: the subrightquasigoup (subquasigroup, subloop) of a right quasigroup (quasigroup, loop) Q generated by the list of elements gens. We allow gens to consist of elements of Q or of elements of the underlying set of Q. Note that there are no optional arguments in this constructor. The resulting subalgebra will be index based (cf. Section 1.8) iff Q is index based. For subloops, we allow gens to be an empty set, in which case the trivial subloop is returned.

An effort is made for the subalgebra to inherit properties from Q. For instance, if it is known that Q is commutative, the subalgebra will have an attribute that signifies it is commutative.

gap> Q := LoopByFunction([0..7],function(x,y) return (x+y) mod 8; end);;
gap> S := Subrightquasigroup( Q, [4] ); # inherits loop property from parent
<loop of size 2>
gap> [ IsSubrightquasigroup( Q, S ), IsSubquasigroup( Q, S ), IsSubloop( Q, S ) ];
[ true, true, true ]
gap> Elements( S ); # note indexing of elements here and below
[ l0, l4 ]
gap> Elements( S )[ 2 ]; # the 2nd element of S
l4
gap> S.2; # the 2nd element of Q, the parent of S
l1
gap> S[4]; # the element of parent Q corresponding to the given element of the underlying set
l4
gap> Display( CayleyTable( S ) );
[ [  0,  4 ],
  [  4,  0 ] ]
gap> RightTranslation( Q, Q[4] ); # a permutation of the index set of Q
(1,5)(2,6)(3,7)(4,8)
gap> RightTranslation( S, S[4] ); # a permutation of the index set of S
(1,5)
gap> Subquasigroup( Q, [4] );
<loop of size 2>
gap> Subloop( Q, [4] );
<loop of size 2>

3.3-3 All subalgebras
‣ AllSubrightquasigroups( Q )( operation )
‣ AllSubquasigroups( Q )( operation )
‣ AllSubloops( Q )( operation )

Returns: a list of all subrightquasigroups (subquasigroups, subloops) of a right quasigroup (quasigroup, loop) Q.

gap> AllSubloops( AsLoop( CyclicGroup( 3 ) ) );
[ <trivial group with 1 generator>, <associative loop of size 3> ]
gap> P := ProjectionRightQuasigroup( 2 );; 
gap> Length( AllSubrightquasigroups( P ) ); # every nonempty subset is a subrightquasigroup here
3

A subloop S of a loop Q is minimal if S is nontrivial and S contains no proper nontrivial subloops. A sub(right)quasigroup S of a (right) quasigroup Q is minimal if S contains no proper sub(right)quasigroups.

3.3-4 Testing minimal subalgebras
‣ IsMinimalSubrightquasigroup( [Q, ]S )( operation )
‣ IsMinimalSubquasigroup( [Q, ]S )( operation )
‣ IsMinimalSubloop( [Q, ]S )( operation )

Returns: true iff S is a minimal subrightquasigroup (subquasigroup, subloop), else returns false.

Note that it is not necessary to specify the enveloping right quasigroup (quasigroup, loop) since all needed information is contained already in S. In the version with two arguments Q, S, it is first checked that S is a subalgebra of Q.

3.3-5 All minimal subalgebras
‣ AllMinimalSubrightquasigroups( Q )( operation )
‣ AllMinimalSubquasigroups( Q )( operation )
‣ AllMinimalSubloops( Q )( operation )

Returns: a list of all minimal subrightquasigroups (subquasigroups, subloops) of a right quasigroup (quasigroup, loop) Q.

A surighquasigroup S of a right quasigroup Q is maximal if S is propertly contained in Q and if whenever S<A<Q then either A=S or A=Q.

3.3-6 Testing maximal subalgebras
‣ IsMaximalSubrightquasigroup( Q, S )( operation )
‣ IsMaximalSubquasigroup( Q, S )( operation )
‣ IsMaximalSubloop( Q, S )( operation )

Returns: true iff S is a maximal subrightquasigroup (subquasigroup, subloop) of the right quasigroup (quasigroup, loop) Q, else returns false.

3.3-7 All maximal subalgebras
‣ AllMaximalSubrightquasigroups( Q )( operation )
‣ AllMaximalSubquasigroups( Q )( operation )
‣ AllMaximalSubloops( Q )( operation )

Returns: a list of all maximal subrightquasigroups (subquasigroups, subloops) of the right quasigroup (quasigroup, loop) Q.

gap> Q := MoufangLoop(12,1);;
gap> S := Subloop(Q,[Q.2]);;
gap> IsMinimalSubloop(S);
true
gap> AllMinimalSubloops(Q);
[ <Moufang loop of size 2>, <Moufang loop of size 2>, 
  <Moufang loop of size 3>, <Moufang loop of size 2>, 
  <Moufang loop of size 2>, <Moufang loop of size 2>, 
  <Moufang loop of size 2>, <Moufang loop of size 2>, 
  <Moufang loop of size 2>, <Moufang loop of size 2> ]
gap> IsMaximalSubloop(Q,S);
false
gap> AllMaximalSubloops(Q);
[ <Moufang loop of size 6>, <Moufang loop of size 4>, 
  <Moufang loop of size 4>, <Moufang loop of size 4>, 
  <Moufang loop of size 6>, <Moufang loop of size 6>, 
  <Moufang loop of size 4>, <Moufang loop of size 4>, 
  <Moufang loop of size 4>, <Moufang loop of size 4>, 
  <Moufang loop of size 4>, <Moufang loop of size 4> ]

3.4 Cosets and transversals

If S is a subrightquasigroup of a right quasigroup Q, the right cosets are subsets of Q of the form Sx=\{sx:s\in S\}, where x\in Q. All right cosets of a subrightquasigroup S of a right quasigroup Q have the same cardinality, but they need not cover Q and they can intersect in nontrivial ways. In quasigroups and loops, the right cosest cover Q.

A right transversal to S in Q is then a list of elements of Q containing one element from each right coset of S in Q.

In RightQuasigroups, the right cosets and right transversals are mere lists, not special GAP objects.

The function RightCosets( Q, S ) checks that S is a subrightquasigroup of Q and then returns a list of all right cosets of S in Q.

3.4-1 RightTransversal
‣ RightTransversal( Q, S )( operation )

Returns: a right transversal to S in Q.

gap> P := ProjectionRightQuasigroup( 3 );;
gap> Display( MultiplicationTable( P ) );
[ [  1,  1,  1 ],
  [  2,  2,  2 ],
  [  3,  3,  3 ] ]
gap> S := Subrightquasigroup( P, [1,2] );;
gap> RightCosets( P, S ); # there is a single right coset of S in P
[ [ r1, r2 ] ]
gap> RightTransversal( P, S );
[ r1 ]

Left cosets xS and left transversals are defined dually to right cosets and right transversals. In right quasigroups, the left cosets of S need not have the same cardinality and can intersect in nontrivial ways, but they cover Q. In quasigroups and loops, all left cosets of S have the same cardinality.

The function LeftCosets( Q, S ) checks that S is a subrightquasigroup of Q and then returns a list of all left cosets of S in Q.

3.4-2 LeftTransversal
‣ LeftTransversal( Q, S )( operation )

Returns: a left transversal to S in Q.

3.5 Right quasigroups by generators

In analogy with the Group function in GAP, we provide methods for generating right quasigroups (quasigroups, loops) from a list of right quasigroup (quasigroup, loop) elements.

3.5-1 RightQuasigroup, Quasigroup and Loop
‣ RightQuasigroup( gens... )( function )
‣ Quasigroup( gens... )( function )
‣ Loop( gens... )( function )

Returns: the right quasigroup (quasigroup, loop) generated by the given right quasigroup (quasigroup, loop) elements. The generators can be given as gen1, gen2, ..., or as a single argument [ gen1, gen2, ...]. The generators must belong to the same parent algebra. The attribute GeneratorsOfMagma (see Section 1.9) is not set to coincide with the given list of generators. The resulting algebra is index based iff the parent algebra is index based.

3.5-2 RightQuasigroupByGenerators, QuasigroupByGenerators and LoopByGenerators
‣ RightQuasigroupByGenerators( gens... )( function )
‣ QuasigroupByGenerators( gens... )( function )
‣ LoopByGenerators( gens... )( function )

Returns: the right quasigroup (quasigroup, loop) generated by the given right quasigroup (quasigroup, loop) elements. This is just like RightQuasigroup (Quasigroup, Loop).

3.5-3 RightQuasigroupWithGenerators, QuasigroupWithGenerators and LoopWithGenerators
‣ RightQuasigroupWithGenerators( gens... )( function )
‣ QuasigroupWithGenerators( gens... )( function )
‣ LoopWithGenerators( gens... )( function )

Returns: the right quasigroup (quasigroup, loop) generated by the given right quasigroup (quasigroup, loop) elements. This is just like RightQuasigroup (Quasigroup, Loop) except that it is guaranteed that the value of GeneratorsOfMagma will be set to coincide with the given list of generators.

3.6 Intersections and joins of right quasigroups

Given a list algebras of at least two right quasigroups (quasigroups, loops) with the same parent algebra, Intersection( algebras ) returns their intersection subalgebra. We also support Intersection( algebra1, algebra2, ... ).

Passing of arguments for Intersection is handled in the standard GAP way. Therefore the only method implemented in RightQuasigroups is Intersection2 for the intersection of two right quasigroups.

Given a list algebras of right quasigroups (quasigroups, loops) with the same parent algebra, Join( algebras ) returns the smallest subalgebra containing all algebras in the list. We also support Join( algebra1, algebra2, ... ).

The function Join does not seem to be implemented in GAP. In RightQuasigroups, Join and Join2 are implemented in a way analogous to Intersection and Intersection2, except that we also allow a single algebra as the argument, in which case that algebra is returned.

gap> P := ProjectionRightQuasigroup( 10 );;
gap> A := Subrightquasigroup( P, [1..4] );;
gap> B := Subrightquasigroup( P, [3..7] );;
gap> Intersection( A, B );
<associative quandle of size 2>
gap> Elements( last );
[ r3, r4 ]
gap> Join( A, B );
<associative quandle of size 7>
gap> Elements( last );
[ r1, r2, r3, r4, r5, r6, r7 ]

3.7 Congruences

Let A be an algebra in a variety V. Then \sim is a congruence on A if it is an equivalence relation on A such that for every operation f of arrity m in the signature of V, we have f(x_1,\dots,x_m)\sim f(y_1,\dots,y_m) whenever x_1,\dots,x_m,y_1,\dots,y_m\in A satisfy x_1\sim y_1, \dots, x_m\sim y_m. If V is the variety of all right quasigroups (resp. quasigroups, loops), we speak of a right quasigroup congruence (resp. quasigroup congruence, loop congruence).

It turns out that an equivalence relation \sim on a finite right quasigroup (resp. quasigroup, loop) is a right quasigroup (resp. quasigroup, loop) congruence iff for every x,y,u\in Q with x\sim y we have xu\sim yu and ux\sim uy. Therefore, an equivalence relation \sim on a finite loop (quasigroup, right quasigroup) is a loop (quasigroup, right quasigroup) congruence iff it is a groupoid congruence.

In GAP, equivalence relations on A are represented as functions f:A\to A, where a,b\in A are related iff f(a)=b. Since equivalence relations are in one-to-one correspondence with partitions, the GAP function EquivalenceRelationByPartition is particularly convenient, as illustrated by the following example:

gap> G := SymmetricGroup( 3 );;
gap> C := EquivalenceRelationByPartition( G, [[(),(1,2,3),(1,3,2)],[(1,2),(1,3),(2,3)]] );
<equivalence relation on SymmetricGroup( [ 1 .. 3 ] ) >
gap> Source( C );
Sym( [ 1 .. 3 ] )
gap> EquivalenceClasses( C );
[ {()}, {(1,2)} ]
gap> Elements( last[1] );
[ (), (1,2,3), (1,3,2) ]

3.7-1 Checking right quasigroup congruences
‣ IsRightQuasigroupCongruence( C )( operation )
‣ IsQuasigroupCongruence( C )( operation )
‣ IsLoopCongruence( C )( operation )

Returns: true if C is a right quasigroup (resp. quasigroup, loop) congruence on the right quasigroup (resp. quasigroup, loop) Source( C ), else returns false. Note that false is returned when a stronger algebra congruence is tested on a weaker algebra, for instance, if IsLoopCongruence( C ) is tested with Source( C ) that is not a declared loop.

gap> Q := QuasigroupByFunction( [0..3], function(x,y) return (x-y) mod 4; end );;
gap> C := EquivalenceRelationByPartition( Q, [ [Q[0],Q[2]], [Q[1],Q[3]] ] );
<equivalence relation on <quasigroup of size 4 on 0, 1, 2, 3> >
gap> IsQuasigroupCongruence( C );
true
gap> D := EquivalenceRelationByPartition( Q, [ [Q[0],Q[1],Q[2]], [Q[3]] ] );;
gap> IsQuasigroupCongruence( D );
false

3.7-2 Congruences generated by partition
‣ RightQuasigroupCongruenceByPartition( Q, partition )( operation )
‣ QuasigroupCongruenceByPartition( Q, partition )( operation )
‣ LoopCongruenceByPartition( Q, partition )( operation )

Returns: the right quasigroup (quasigroup, loop) congruence of the right quasigroup (quasigroup, loop) Q generated by partition, that is, the smallest congruence C such that every element of partition is a subset of an equivalence class of C. Here, partition must be a list of disjoint subsets of Q (whose union is not necessarily all of Q).

gap> Q := QuasigroupByFunction( GF(27), \- );;
gap> C := QuasigroupCongruenceByPartition( Q, [ [ Q.1, Q.2, Q.3 ], [ Q.4, Q.5 ] ] );; # merge Q.1, Q.2, Q.3 and also Q.4, Q.5
gap> List( EquivalenceClasses( C ), Size );
[ 9, 9, 9 ]
gap> G := AsLoop( SymmetricGroup( 5 ) );;
gap> C := LoopCongruenceByPartition( G, [ [ G[()], G[(1,2,3)] ] ] );; # merge (), (1,2,3)
gap> List( EquivalenceClasses( C ), Size );
[ 60, 60 ]

3.7-3 Congruences generated by pairs
‣ RightQuasigroupCongruenceByPairs( Q, pairs )( operation )
‣ QuasigroupCongruenceByPairs( Q, pairs )( operation )
‣ LoopCongruenceByPairs( Q, pairs )( operation )

Returns: the right quasigroup (quasigroup, loop) congruence of the right quasigroup (quasigroup, loop) Q generated by pairs, that is, the smallest congruence that contains pairs as a subset. Here, pairs must be a list of pairs of elements of Q.

gap> Q := RightQuasigroupByFunction([0..7], function(x,y) return (x+2*y) mod 8; end );;
gap> C := RightQuasigroupCongruenceByPairs( Q, [ [ Q[0],Q[2] ] ] );; # merge 0, 2
gap> List( EquivalenceClasses( C ), Elements );
[ [ r0, r2, r4, r6 ], [ r1, r5 ], [ r3, r7 ] ]
gap> C := RightQuasigroupCongruenceByPairs( Q, [ [ Q[0],Q[2] ], [ Q[0], Q[1] ] ] );; # merge 0, 2 and also 0, 1
gap> List( EquivalenceClasses( C ), Elements );
[ [ r0, r1, r2, r3, r4, r5, r6, r7 ] ]

3.7-4 All congruences
‣ AllRightQuasigroupCongruences( Q )( operation )
‣ AllQuasigroupCongruences( Q )( operation )
‣ AllLoopCongruences( Q )( operation )

Returns: a list of all right quasigroup (quasigroup, loop) congruences of a right quasigroup (quasigroup, loop) Q. The congruences are returned as GAP objects suitable as arguments of FactorRightQuasigroup (FactorQuasigroup, FactorLoop).

Note: For a right quasigroup Q, there is no method yet for the case when RightMultiplicationGroup( Q ) does not act transitively on Q.

3.8 Normality and simplicity

A subloop S of a loop Q is normal in Q if Sx=xS, S(xy)=(Sx)y and (xy)S = x(yS) for every x,y\in Q. It can be shown that a subset S of Q is a normal subloop of Q iff there is a loop congruence \sim on Q such that S is the congruence class of \sim containing the neutral element of Q.

If S is a subloop of a loop Q, the function IsNormal( Q, S ) returns true if S is normal in Q, else it returns false.

If S is a subset or a subloop of a loop Q, NormalClosure( Q, S ) returns the normal closure of S in Q, that is, the smallest normal subloop of Q containing S.

3.8-1 AllNormalSubloops
‣ AllNormalSubloops( Q )( operation )

Returns: a list of all normal subloops of a loop Q. Normal subloops correspond to blocks of the multiplication group of Q that contain the neutral element.

A right quasigroup Q is simple if the only congruences on Q are the diagonal congruence \{(x,x):x\in Q\} and the full congruence Q\times Q. It is well known that a quasigroup (loop) Q is simple iff its multiplication group \mathrm{Mlt}(Q)=\langle R_x,L_x:x\in Q\rangle acts primitively on Q (see Section 5.2).

Note that in the finite case, which is the only case supported by RightQuasigroups, a loop Q is simple as a loop (no nontrivial loop congruences) iff it is simple as a quasigroup (no nontrivial quasigroup congruences) iff it is simple as a right quasigroup (no nontrivial right quasigroup congruences) iff it is simple as a groupoid (no nontrivial groupoid congruences).

3.8-2 Testing right quasigroups for simplicity
‣ IsSimpleRightQuasigroup( Q )( operation )
‣ IsSimpleQuasigroup( Q )( operation )
‣ IsSimpleLoop( Q )( operation )

Returns: true if Q is a simple right quasigroup (quasigroup, loop), else returns false. The non-qualified function IsSimple is also supported.

gap> # right quasigroup example
gap> R := RightQuasigroupByCayleyTable( [[2,2,1,1],[3,1,2,2],[4,3,3,3],[1,4,4,4]] );; 
gap> RMlt := RightMultiplicationGroup( R );
Group([ (1,2,3,4), (1,2) ])
gap> AllRightQuasigroupCongruences( R );
[ <equivalence relation on <right quasigroup of size 4 on 1, 2, 3, 4> >, 
  <equivalence relation on <right quasigroup of size 4 on 1, 2, 3, 4> > ]
gap> IsSimpleRightQuasigroup( R ); # IsSimple( R ) is also supported
true
gap> # quasigroup example
gap> Q := QuasigroupByFunction( [0..3], function(x,y) return (x-y) mod 4; end );;
gap> congruences := AllQuasigroupCongruences( Q );;
gap> List( congruences, EquivalenceClasses );
[ [ {q0}, {q1}, {q2}, {q3} ], [ {q0}, {q1} ], [ {q0} ] ]
gap> List( EquivalenceClasses( congruences[ 2 ] ), Elements );
[ [ q0, q2 ], [ q1, q3 ] ]
gap> IsSimpleQuasigroup( Q ); # IsSimple( Q ) is also supported
false
gap> # loop example
gap> L := AsLoop( Group((1,2,3,4)) );;
gap> AllNormalSubloops( L );
[ <trivial group with 1 generator>, <associative loop of size 2>, 
  <associative loop of size 4> ]
gap> IsSimpleLoop( L ); # IsSimple( L ) is also supported
false
gap> S := Subloop(  L, [ (1,3)(2,4) ] );;
gap> IsNormal( L, S );
true

3.9 Factor algebras

When \sim is a congruence on A, then the factor algebra A/\sim is well defined on the equivalence classes [x] of \sim by setting f([x_1],\dots,[x_m]) = [f(x_1,\dots,x_m)] for every operation f of arity m in the signature of the enveloping variety V and every x_1,\dots,x_m\in A.

In case of right quasigroups and quasigroups, the factor construction based on congruences is the standard way of defining factor alegbras. In case of loops, the equivalence classes of \sim are precisely the cosets of the normal subloop S, the equivalence class of the identity element. The congruence-based factor algebra construction is then equivalent to the standard coset-based construction Sx\cdot Sy = S(xy) from group theory.

3.9-1 Constructing factor algebras
‣ FactorRightQuasigroup( C[, constructorStyle] )( operation )
‣ FactorQuasigroup( C[, constructorStyle] )( operation )
‣ FactorLoop( C[, constructorStyle] )( operation )

Returns: the factor algebra of Source( C ) modulo the right quasigroup (resp. quasigroup, loop) congruence C. In case of loops we also allow arguments Q and N instead of C, where Q is a loop and N is a normal subloop of Q. See Section 2.1 for the optional argument constructorStyle.

An effort is made for the factor algebra to inherit properties from the enveloping algebra. For instance, if it is known that the enveloping algebra is commutative, the factor algebra will have an attribute that signifies it is commutative.

We also support infix notation for factor algebras, that is, Q/C or Q/N. In that version:

gap> Q := ProjectionRightQuasigroup( 6 );;
gap> C := EquivalenceRelationByPartition( Q, [[Q.1,Q.2],[Q.3,Q.4,Q.5],[Q.6]] );;
gap> [ IsRightQuasigroupCongruence( C ), IsQuasigroupCongruence( C ), IsLoopCongruence( C ) ];
[ true, false, false ]
gap> F := Q/C;
<associative quandle of size 3>
gap> Elements( F ); # the inner "r" comes from Q, the outer "r" from F.
[ r<object>, r<object>, r<object> ]
gap> H := FactorRightQuasigroup( C, ConstructorStyle( false, false ) ); # non-index based version is supported (but not for /)
<associative quandle of size 3>
gap> HasMultiplicationTable( H );
false
gap> H.1*H.2;
r<object>
gap> CayleyTable( H );   
[ [ {r1}, {r1}, {r1} ], [ {r3}, {r3}, {r3} ], [ {r6}, {r6}, {r6} ] ]

See Section 8.1 for natural projections onto factor algebras.

3.10 An example of the factor construction: Paige loops

We conclude with a larger example, the construction of finite simple Moufang loops, so-called Paige loops. These are obtained as the factor of the multiplicative set S of elements of norm one in the Zorn vector matrix algebra modulo the center of S.

gap> # auxiliary functions
gap> DotProduct := function( x, y ) return Sum( [1..Length(x)], i -> x[i]*y[i] ); end;;
gap> CrossProduct := function( x, y ) return [ x[2]*y[3]-x[3]*y[2], x[3]*y[1]-x[1]*y[3], x[1]*y[2]-x[2]*y[1] ]; end;;
gap> PaigeNorm := function( x ) return x[1]*x[8] - DotProduct( x{[2,3,4]},x{[5,6,7]} ); end;;
gap> PaigeMult := function( x, y )
>   local a, b, c, d;
>   a := x[1]*y[1] + DotProduct(x{[2,3,4]},y{[5,6,7]});
>   b := x[1]*y{[2,3,4]} + x{[2,3,4]}*y[8] - CrossProduct(x{[5,6,7]},y{[5,6,7]});
>   c := x{[5,6,7]}*y[1] + x[8]*y{[5,6,7]} + CrossProduct(x{[2,3,4]},y{[2,3,4]});
>   d := DotProduct(x{[5,6,7]},y{[2,3,4]})+x[8]*y[8];
>   return Concatenation( [a], b, c, [d] );
>   end;;
gap> # Paige loop over GF(2) (index based approach in characteristic 2)
gap> F := GF(2);;
gap> S := Filtered( F^8, x -> PaigeNorm( x ) = One( F ) );;
gap> P := LoopByFunction( S, PaigeMult, ConstructorStyle( true, true ) ); 
<loop of size 120>
gap> # general approach (not index based, any characteristic, using congruences)
gap> n := 3;; # any prime power works but it will be very slow
gap> F := GF(n);;
gap> S := Filtered( F^8, x -> PaigeNorm( x ) = One( F ) );;
gap> M := LoopByFunction( S, PaigeMult, ConstructorStyle( false, false ) );;
gap> C := EquivalenceRelationByPartition( M, Set( S, x -> Set( [ M[x], M[-x] ] ) ) );; # factoring out +/- one
gap> P := FactorLoop( C, ConstructorStyle( false, false ) ); # 2000 ms
<loop of size 1080>
gap> # another approach using normal subloop
gap> n := 3;; F := GF(n);; S := Filtered( F^8, x -> PaigeNorm( x ) = One( F ) );;
gap> M := LoopByFunction( S, PaigeMult, ConstructorStyle( false, false ) );;
gap> one := [ Z(n)^0, 0*Z(n), 0*Z(n), 0*Z(n), 0*Z(n), 0*Z(n), 0*Z(n), Z(n)^0 ];;
gap> N := Subloop( M, [-one] );;
gap> P := FactorLoop( M, N, ConstructorStyle( false, false ) ); # 2000 ms, it takes a while to find the neutral element
<loop of size 1080>
 [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