In this chapter we describe methods of universal-algebraic flavor for 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>
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.)
‣ 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>
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
.
‣ 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
.
‣ 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>
‣ 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.
‣ 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.
‣ 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\).
‣ 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.
‣ 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> ]
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
.
‣ 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
.
‣ LeftTransversal ( Q, S ) | ( operation ) |
Returns: a left transversal to S in Q.
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.
‣ 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.
‣ 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
).
‣ 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.
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 ]
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) ]
‣ 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
‣ 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 ]
‣ 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 ] ]
‣ 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.
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
.
‣ 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).
‣ 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
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.
‣ 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:
the enveloping algebra Q
must always be given,
the optional argument constructorStyle
cannot be given,
the resulting algebra will be index based iff Q
is index based.
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.
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>
generated by GAPDoc2HTML