Compare commits
37 Commits
Loops3.4.0
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
d7f394f957 | ||
|
1cf79a02c3 | ||
|
03d80d9acb | ||
|
69a866d5db | ||
|
b3b9e3817b | ||
|
aaaf1a04a9 | ||
|
8f7f6891ec | ||
|
4c2817b04f | ||
|
2dcde99549 | ||
|
143e51b801 | ||
|
4254b760c9 | ||
|
8c5670ef3f | ||
|
2696cd6ff2 | ||
|
a69dcd05d3 | ||
|
244492a7ed | ||
|
91ba2744c1 | ||
|
fb39c9e02e | ||
|
71672eeb9c | ||
|
df74177abb | ||
|
1493a9c480 | ||
|
68390c3869 | ||
|
2521a38635 | ||
|
54c503e356 | ||
|
6d095fe0d3 | ||
|
7c3f421a20 | ||
|
1ec279ab0b | ||
|
a4d79ff66e | ||
|
87e7b01333 | ||
|
88533fd7de | ||
|
9d8dfdb9e2 | ||
|
c848f29524 | ||
|
1ac424c524 | ||
|
cf2bc14423 | ||
|
66b00d7d34 | ||
|
75fe6fa0e3 | ||
|
e05b2a6deb | ||
|
722f25e51f |
@ -1,8 +1,8 @@
|
|||||||
SetPackageInfo( rec(
|
SetPackageInfo( rec(
|
||||||
PackageName := "loops",
|
PackageName := "loops",
|
||||||
Subtitle := "Computing with quasigroups and loops in GAP",
|
Subtitle := "Computing with quasigroups and loops in GAP",
|
||||||
Version := "3.4.0",
|
Version := "3.4.1",
|
||||||
Date := "27/10/2017",
|
Date := "29/10/2017",
|
||||||
ArchiveURL := "http://www.math.du.edu/loops/loops-3.4.0",
|
ArchiveURL := "http://www.math.du.edu/loops/loops-3.4.0",
|
||||||
ArchiveFormats := "-win.zip .tar.gz",
|
ArchiveFormats := "-win.zip .tar.gz",
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
## -------------------------------------------------------------------------
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
DeclareProperty( "IsAssociative", IsLoop );
|
DeclareProperty( "IsAssociative", IsLoop );
|
||||||
DeclareProperty( "IsCommutative", IsQuasigroup );
|
#DeclareProperty( "IsCommutative", IsQuasigroup ); # Already covered by GAP
|
||||||
DeclareProperty( "IsPowerAssociative", IsQuasigroup );
|
DeclareProperty( "IsPowerAssociative", IsQuasigroup );
|
||||||
DeclareProperty( "IsDiassociative", IsQuasigroup );
|
DeclareProperty( "IsDiassociative", IsQuasigroup );
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ InstallTrueMethod( IsExtraLoop, IsAssociative and IsLoop );
|
|||||||
##
|
##
|
||||||
## Returns true if <Q> is commutative.
|
## Returns true if <Q> is commutative.
|
||||||
|
|
||||||
InstallOtherMethod( IsCommutative, "for quasigroup",
|
InstallMethod( IsCommutative, "for quasigroup",
|
||||||
[ IsQuasigroup ],
|
[ IsQuasigroup ], 20, # Need to beat GAP's library methods
|
||||||
function( Q )
|
function( Q )
|
||||||
return LeftSection( Q ) = RightSection( Q );
|
return LeftSection( Q ) = RightSection( Q );
|
||||||
end );
|
end );
|
||||||
|
@ -12,34 +12,34 @@
|
|||||||
## DISPLAYING AND COMPARING ELEMENTS
|
## DISPLAYING AND COMPARING ELEMENTS
|
||||||
## -------------------------------------------------------------------------
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
InstallMethod( PrintObj, "for a quasigroup element",
|
InstallMethod( PrintObj, "for a default quasigroup element",
|
||||||
[ IsQuasigroupElement ],
|
[ IsQuasigroupElmRep ],
|
||||||
function( obj )
|
function( obj )
|
||||||
local F;
|
local F;
|
||||||
F := FamilyObj( obj );
|
F := FamilyObj( obj );
|
||||||
Print( F!.names, obj![ 1 ] );
|
Print( F!.elmNamePrefix, obj![ 1 ] );
|
||||||
end );
|
end );
|
||||||
|
|
||||||
InstallMethod( PrintObj, "for a loop element",
|
InstallMethod( PrintObj, "for a loop element",
|
||||||
[ IsLoopElement ],
|
[ IsLoopElmRep ],
|
||||||
function( obj )
|
function( obj )
|
||||||
local F;
|
local F;
|
||||||
F := FamilyObj( obj );
|
F := FamilyObj( obj );
|
||||||
Print( F!.names, obj![ 1 ] );
|
Print( F!.elmNamePrefix, obj![ 1 ] );
|
||||||
end );
|
end );
|
||||||
|
|
||||||
InstallMethod( \=, "for two elements of a quasigroup",
|
InstallMethod( \=, "for two elements of a quasigroup",
|
||||||
IsIdenticalObj,
|
IsIdenticalObj,
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
function( x, y )
|
function( x, y )
|
||||||
return FamilyObj( x ) = FamilyObj( y ) and x![ 1 ] = y![ 1 ];
|
return x![ 1 ] = y![ 1 ];
|
||||||
end );
|
end );
|
||||||
|
|
||||||
InstallMethod( \<, "for two elements of a quasigroup",
|
InstallMethod( \<, "for two elements of a quasigroup",
|
||||||
IsIdenticalObj,
|
IsIdenticalObj,
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
function( x, y )
|
function( x, y )
|
||||||
return FamilyObj( x ) = FamilyObj( y ) and x![ 1 ] < y![ 1 ];
|
return x![ 1 ] < y![ 1 ];
|
||||||
end );
|
end );
|
||||||
|
|
||||||
InstallMethod( \., "for quasigroup and positive integer",
|
InstallMethod( \., "for quasigroup and positive integer",
|
||||||
@ -57,7 +57,7 @@ end );
|
|||||||
## i.e., a*b*c=(a*b)*c. Powers use binary decomposition.
|
## i.e., a*b*c=(a*b)*c. Powers use binary decomposition.
|
||||||
InstallMethod( \*, "for two quasigroup elements",
|
InstallMethod( \*, "for two quasigroup elements",
|
||||||
IsIdenticalObj,
|
IsIdenticalObj,
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
function( x, y )
|
function( x, y )
|
||||||
local F;
|
local F;
|
||||||
F := FamilyObj( x );
|
F := FamilyObj( x );
|
||||||
@ -65,13 +65,13 @@ function( x, y )
|
|||||||
end );
|
end );
|
||||||
|
|
||||||
InstallOtherMethod( \*, "for a QuasigroupElement and a list",
|
InstallOtherMethod( \*, "for a QuasigroupElement and a list",
|
||||||
[ IsQuasigroupElement , IsList ],
|
[ IsQuasigroupElmRep , IsList ],
|
||||||
function( x, ly )
|
function( x, ly )
|
||||||
return List( ly, y -> x*y );
|
return List( ly, y -> x*y );
|
||||||
end );
|
end );
|
||||||
|
|
||||||
InstallOtherMethod( \*, "for a list and a QuasigroupElement",
|
InstallOtherMethod( \*, "for a list and a QuasigroupElement",
|
||||||
[ IsList, IsQuasigroupElement ],
|
[ IsList, IsQuasigroupElmRep ],
|
||||||
function( lx, y )
|
function( lx, y )
|
||||||
return List( lx, x -> x*y );
|
return List( lx, x -> x*y );
|
||||||
end );
|
end );
|
||||||
@ -83,7 +83,7 @@ end );
|
|||||||
## z=x/y means zy=x
|
## z=x/y means zy=x
|
||||||
InstallMethod( RightDivision, "for two quasigroup elements",
|
InstallMethod( RightDivision, "for two quasigroup elements",
|
||||||
IsIdenticalObj,
|
IsIdenticalObj,
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
function( x, y )
|
function( x, y )
|
||||||
local F, ycol;
|
local F, ycol;
|
||||||
F := FamilyObj( x );
|
F := FamilyObj( x );
|
||||||
@ -93,7 +93,7 @@ end );
|
|||||||
|
|
||||||
InstallOtherMethod( RightDivision,
|
InstallOtherMethod( RightDivision,
|
||||||
"for a list and a quasigroup element",
|
"for a list and a quasigroup element",
|
||||||
[ IsList, IsQuasigroupElement ],
|
[ IsList, IsQuasigroupElmRep ],
|
||||||
0,
|
0,
|
||||||
function( lx, y )
|
function( lx, y )
|
||||||
return List( lx, x -> RightDivision(x, y) );
|
return List( lx, x -> RightDivision(x, y) );
|
||||||
@ -101,7 +101,7 @@ end );
|
|||||||
|
|
||||||
InstallOtherMethod( RightDivision,
|
InstallOtherMethod( RightDivision,
|
||||||
"for a quasigroup element and a list",
|
"for a quasigroup element and a list",
|
||||||
[ IsQuasigroupElement, IsList ],
|
[ IsQuasigroupElmRep, IsList ],
|
||||||
0,
|
0,
|
||||||
function( x, ly )
|
function( x, ly )
|
||||||
return List( ly, y -> RightDivision(x, y) );
|
return List( ly, y -> RightDivision(x, y) );
|
||||||
@ -110,7 +110,7 @@ end );
|
|||||||
InstallOtherMethod( \/,
|
InstallOtherMethod( \/,
|
||||||
"for two elements of a quasigroup",
|
"for two elements of a quasigroup",
|
||||||
IsIdenticalObj,
|
IsIdenticalObj,
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
0,
|
0,
|
||||||
function( x, y )
|
function( x, y )
|
||||||
return RightDivision( x, y );
|
return RightDivision( x, y );
|
||||||
@ -118,7 +118,7 @@ end );
|
|||||||
|
|
||||||
InstallOtherMethod( \/,
|
InstallOtherMethod( \/,
|
||||||
"for a list and a quasigroup element",
|
"for a list and a quasigroup element",
|
||||||
[ IsList, IsQuasigroupElement ],
|
[ IsList, IsQuasigroupElmRep ],
|
||||||
0,
|
0,
|
||||||
function( lx, y )
|
function( lx, y )
|
||||||
return List( lx, x -> RightDivision(x, y) );
|
return List( lx, x -> RightDivision(x, y) );
|
||||||
@ -126,7 +126,7 @@ end );
|
|||||||
|
|
||||||
InstallOtherMethod( \/,
|
InstallOtherMethod( \/,
|
||||||
"for a quasigroup element and a list",
|
"for a quasigroup element and a list",
|
||||||
[ IsQuasigroupElement, IsList ],
|
[ IsQuasigroupElmRep, IsList ],
|
||||||
0,
|
0,
|
||||||
function( x, ly )
|
function( x, ly )
|
||||||
return List( ly, y -> RightDivision(x, y) );
|
return List( ly, y -> RightDivision(x, y) );
|
||||||
@ -135,7 +135,7 @@ end );
|
|||||||
## z = x\y means xz=y
|
## z = x\y means xz=y
|
||||||
InstallMethod( LeftDivision, "for two quasigroup elements",
|
InstallMethod( LeftDivision, "for two quasigroup elements",
|
||||||
IsIdenticalObj,
|
IsIdenticalObj,
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
function( x, y )
|
function( x, y )
|
||||||
local F;
|
local F;
|
||||||
F := FamilyObj( x );
|
F := FamilyObj( x );
|
||||||
@ -144,7 +144,7 @@ end );
|
|||||||
|
|
||||||
InstallOtherMethod( LeftDivision,
|
InstallOtherMethod( LeftDivision,
|
||||||
"for a list and a quasigroup element",
|
"for a list and a quasigroup element",
|
||||||
[ IsList, IsQuasigroupElement ],
|
[ IsList, IsQuasigroupElmRep ],
|
||||||
0,
|
0,
|
||||||
function( lx, y )
|
function( lx, y )
|
||||||
return List( lx, x -> LeftDivision(x, y) );
|
return List( lx, x -> LeftDivision(x, y) );
|
||||||
@ -152,7 +152,7 @@ end );
|
|||||||
|
|
||||||
InstallOtherMethod( LeftDivision,
|
InstallOtherMethod( LeftDivision,
|
||||||
"for a quasigroup element and a list",
|
"for a quasigroup element and a list",
|
||||||
[ IsQuasigroupElement, IsList ],
|
[ IsQuasigroupElmRep, IsList ],
|
||||||
0,
|
0,
|
||||||
function( x, ly )
|
function( x, ly )
|
||||||
return List( ly, y -> LeftDivision(x, y) );
|
return List( ly, y -> LeftDivision(x, y) );
|
||||||
@ -215,7 +215,7 @@ end );
|
|||||||
## -------------------------------------------------------------------------
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
InstallMethod( \^, "for a quasigroup element and a permutation",
|
InstallMethod( \^, "for a quasigroup element and a permutation",
|
||||||
[ IsQuasigroupElement, IsPerm ],
|
[ IsQuasigroupElmRep, IsPerm ],
|
||||||
function( x, p )
|
function( x, p )
|
||||||
local F;
|
local F;
|
||||||
F := FamilyObj( x );
|
F := FamilyObj( x );
|
||||||
@ -223,7 +223,7 @@ function( x, p )
|
|||||||
end );
|
end );
|
||||||
|
|
||||||
InstallMethod( OneOp, "for loop elements",
|
InstallMethod( OneOp, "for loop elements",
|
||||||
[ IsLoopElement ],
|
[ IsLoopElmRep ],
|
||||||
function( x )
|
function( x )
|
||||||
local F;
|
local F;
|
||||||
F := FamilyObj( x );
|
F := FamilyObj( x );
|
||||||
@ -237,7 +237,7 @@ end );
|
|||||||
## If <x> is a loop element, returns the left inverse of <x>
|
## If <x> is a loop element, returns the left inverse of <x>
|
||||||
|
|
||||||
InstallMethod( LeftInverse, "for loop elements",
|
InstallMethod( LeftInverse, "for loop elements",
|
||||||
[ IsLoopElement ],
|
[ IsLoopElmRep ],
|
||||||
x -> RightDivision( One( x ), x )
|
x -> RightDivision( One( x ), x )
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -248,12 +248,12 @@ InstallMethod( LeftInverse, "for loop elements",
|
|||||||
## If <x> is a loop element, returns the left inverse of <x>
|
## If <x> is a loop element, returns the left inverse of <x>
|
||||||
|
|
||||||
InstallMethod( RightInverse, "for loop elements",
|
InstallMethod( RightInverse, "for loop elements",
|
||||||
[ IsLoopElement ],
|
[ IsLoopElmRep ],
|
||||||
x -> LeftDivision( x, One( x ) )
|
x -> LeftDivision( x, One( x ) )
|
||||||
);
|
);
|
||||||
|
|
||||||
InstallMethod( InverseOp, "for loop elements",
|
InstallMethod( InverseOp, "for loop elements",
|
||||||
[ IsLoopElement ],
|
[ IsLoopElmRep ],
|
||||||
function( x )
|
function( x )
|
||||||
local y;
|
local y;
|
||||||
y := RightInverse( x );
|
y := RightInverse( x );
|
||||||
@ -274,7 +274,7 @@ end );
|
|||||||
## (xy)z = (x(yz))u.
|
## (xy)z = (x(yz))u.
|
||||||
|
|
||||||
InstallMethod( Associator, "for three quasigroup elements",
|
InstallMethod( Associator, "for three quasigroup elements",
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
function( x, y, z )
|
function( x, y, z )
|
||||||
return LeftDivision( x*(y*z), (x*y)*z );
|
return LeftDivision( x*(y*z), (x*y)*z );
|
||||||
end);
|
end);
|
||||||
@ -288,7 +288,7 @@ end);
|
|||||||
## (xy) = (yx)u.
|
## (xy) = (yx)u.
|
||||||
|
|
||||||
InstallMethod( Commutator, "for two quasigroup elements",
|
InstallMethod( Commutator, "for two quasigroup elements",
|
||||||
[ IsQuasigroupElement, IsQuasigroupElement ],
|
[ IsQuasigroupElmRep, IsQuasigroupElmRep ],
|
||||||
function( x, y )
|
function( x, y )
|
||||||
return LeftDivision( y*x, x*y );
|
return LeftDivision( y*x, x*y );
|
||||||
end);
|
end);
|
||||||
|
@ -1,104 +1,173 @@
|
|||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#W quasigroups.gd Representing, creating and displaying quasigroups [loops]
|
#W quasigroups.gd Representing, creating and displaying quasigroups [loops]
|
||||||
##
|
##
|
||||||
#H @(#)$Id: quasigroups.gd, v 3.4.0 2017/10/17 gap Exp $
|
#H @(#)$Id: quasigroups.gd, v 3.4.0 2017/10/17 gap Exp $
|
||||||
##
|
##
|
||||||
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
|
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
|
||||||
#Y P. Vojtechovsky (University of Denver, USA)
|
#Y P. Vojtechovsky (University of Denver, USA)
|
||||||
##
|
##
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## GAP CATEGORIES AND REPRESENTATIONS
|
## GAP CATEGORIES AND REPRESENTATIONS
|
||||||
## -------------------------------------------------------------------------
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
## element of a quasigroup
|
## Categories convenient for defining quasigroups
|
||||||
DeclareCategory( "IsQuasigroupElement", IsMultiplicativeElement );
|
|
||||||
DeclareRepresentation( "IsQuasigroupElmRep",
|
## element which is an admissible argument for the right argument of /
|
||||||
IsPositionalObjectRep and IsMultiplicativeElement, [1] );
|
DeclareCategory( "IsRightQuotientElement", IsExtLElement);
|
||||||
|
DeclareCategoryCollections("IsRightQuotientElement");
|
||||||
## element of a loop
|
DeclareCategoryCollections("IsRightQuotientElementCollection");
|
||||||
DeclareCategory( "IsLoopElement",
|
|
||||||
IsQuasigroupElement and IsMultiplicativeElementWithInverse );
|
## Every associative element with an inverse can form right quotients
|
||||||
DeclareRepresentation( "IsLoopElmRep",
|
## (in fact, in some sense it might be enough to have just a left inverse,
|
||||||
IsPositionalObjectRep and IsMultiplicativeElementWithInverse, [1] );
|
## but there doesn't seem to be any benefit to delving to that level of
|
||||||
|
## detail at this point.)
|
||||||
## latin (auxiliary category for GAP to tell apart IsMagma and IsQuasigroup)
|
## By noting this property, we can create a RightQuasigroup from, e.g., group
|
||||||
DeclareCategory( "IsLatinMagma", IsObject );
|
## elements
|
||||||
|
InstallTrueMethod(IsRightQuotientElement,
|
||||||
## quasigroup
|
IsMultiplicativeElementWithInverse and IsAssociativeElement);
|
||||||
DeclareCategory( "IsQuasigroup", IsMagma and IsLatinMagma );
|
|
||||||
|
## Now what we would like to do is re-declare
|
||||||
## loop
|
## DeclareOperation( "/", [IsExtRElement, IsRightQuotientElement] );
|
||||||
DeclareCategory( "IsLoop", IsQuasigroup and IsMultiplicativeElementWithInverseCollection);
|
## but we can't since "/" is in the kernel, so we will have to content
|
||||||
|
## ourselves with InstallOtherMethod() calls on /. (I am not actually sure what
|
||||||
#############################################################################
|
## the practical upshot of that is, i.e. if it has any shortcomings as compared
|
||||||
## TESTING MULTIPLICATION TABLES
|
## to if we could declare "/" more generally.)
|
||||||
## -------------------------------------------------------------------------
|
|
||||||
|
## Element which is admissible for the left argument of LeftQuotient()
|
||||||
DeclareOperation( "IsQuasigroupTable", [ IsMatrix ] );
|
DeclareCategory( "IsLeftQuotientElement", IsExtRElement);
|
||||||
DeclareSynonym( "IsQuasigroupCayleyTable", IsQuasigroupTable );
|
DeclareCategoryCollections("IsLeftQuotientElement");
|
||||||
DeclareOperation( "IsLoopTable", [ IsMatrix ] );
|
DeclareCategoryCollections("IsLeftQuotientElementCollection");
|
||||||
DeclareSynonym( "IsLoopCayleyTable", IsLoopTable );
|
|
||||||
DeclareOperation( "CanonicalCayleyTable", [ IsMatrix ] );
|
## Every associative element with an inverse can form left quotients
|
||||||
DeclareOperation( "NormalizedQuasigroupTable", [ IsMatrix ] );
|
InstallTrueMethod(IsLeftQuotientElement,
|
||||||
|
IsMultiplicativeElementWithInverse and IsAssociativeElement);
|
||||||
#############################################################################
|
|
||||||
## CREATING QUASIGROUPS AND LOOPS MANUALLY
|
## Again, ideally (in some sense) we'd like to redeclare
|
||||||
## -------------------------------------------------------------------------
|
## DeclareOperation("LeftQuotient", [IsLeftQuotientElement,IsExtLElement]);
|
||||||
|
|
||||||
DeclareAttribute( "CayleyTable", IsQuasigroup );
|
## element of a quasigroup
|
||||||
DeclareOperation( "QuasigroupByCayleyTable", [ IsMatrix ] );
|
DeclareSynonym( "IsQuasigroupElement",
|
||||||
DeclareOperation( "LoopByCayleyTable", [ IsMatrix ] );
|
IsMultiplicativeElement and
|
||||||
DeclareOperation( "SetQuasigroupElmName", [ IsQuasigroup, IsString ] );
|
IsLeftQuotientElement and IsRightQuotientElement );
|
||||||
DeclareSynonym( "SetLoopElmName", SetQuasigroupElmName );
|
DeclareRepresentation( "IsQuasigroupElmRep",
|
||||||
DeclareOperation( "CanonicalCopy", [ IsQuasigroup ] );
|
IsPositionalObjectRep and IsQuasigroupElement, [1] );
|
||||||
|
|
||||||
#############################################################################
|
## element of a loop
|
||||||
## CREATING QUASIGROUPS AND LOOPS FROM A FILE
|
DeclareSynonym( "IsLoopElement",
|
||||||
## -------------------------------------------------------------------------
|
IsQuasigroupElement and IsMultiplicativeElementWithInverse );
|
||||||
|
DeclareRepresentation( "IsLoopElmRep",
|
||||||
DeclareOperation( "QuasigroupFromFile", [ IsString, IsString ] );
|
IsQuasigroupElmRep and IsMultiplicativeElementWithInverse, [1] );
|
||||||
DeclareOperation( "LoopFromFile", [ IsString, IsString ] );
|
|
||||||
|
## Right quasigroup
|
||||||
#############################################################################
|
DeclareCategory("IsRightQuasigroup",
|
||||||
## CREATING QUASIGROUPS AND LOOPS BY SECTIONS
|
IsMagma and IsRightQuotientElementCollection);
|
||||||
## -------------------------------------------------------------------------
|
|
||||||
|
## Although the following assertion is mathematically correct, unfortunately
|
||||||
DeclareOperation( "CayleyTableByPerms", [ IsPermCollection ] );
|
## it interferes with method selection for standard group operations
|
||||||
DeclareOperation( "QuasigroupByLeftSection", [ IsPermCollection ] );
|
## in GAP. As an example, if it is uncommented, it will no longer be possible
|
||||||
DeclareOperation( "LoopByLeftSection", [ IsPermCollection ] );
|
## to construct a CyclicGroup; trying to do so eventually dies in
|
||||||
DeclareOperation( "QuasigroupByRightSection", [ IsPermCollection ] );
|
## GeneratorsOfRightQuasigroup. Those errors could conceivably be corrected by
|
||||||
DeclareOperation( "LoopByRightSection", [ IsPermCollection ] );
|
## delving further into GAP's method selection mechanism and adjusting the
|
||||||
DeclareOperation( "QuasigroupByRightFolder", [ IsGroup, IsGroup, IsMultiplicativeElementCollection ] );
|
## declarations of various quasigroup operations, but it doesn't seem worth
|
||||||
DeclareOperation( "LoopByRightFolder", [ IsGroup, IsGroup, IsMultiplicativeElementCollection ] );
|
## the effort as there is unlikely to be much call to consider a group as a
|
||||||
|
## quasigroup. If it is desirable to do so in a particular case, it should be
|
||||||
#############################################################################
|
## possible to use the elements of the group to form a quasigroup, since they
|
||||||
## CONVERSIONS
|
## will all satisfy IsRightQuotientElement by a TrueMethod installed above.
|
||||||
## -------------------------------------------------------------------------
|
|
||||||
|
## InstallTrueMethod(IsRightQuasigroup, IsGroup);
|
||||||
DeclareOperation( "IntoQuasigroup", [ IsMagma ] );
|
|
||||||
DeclareOperation( "PrincipalLoopIsotope",
|
## Left quasigroup
|
||||||
[ IsQuasigroup, IsQuasigroupElement, IsQuasigroupElement ] );
|
DeclareCategory("IsLeftQuasigroup",
|
||||||
DeclareOperation( "IntoLoop", [ IsMagma ] );
|
IsMagma and IsLeftQuotientElementCollection);
|
||||||
DeclareOperation( "IntoGroup", [ IsMagma ] );
|
|
||||||
|
## We forego the following for the reasons outlined above for right quasigroups.
|
||||||
#############################################################################
|
|
||||||
## PRODUCTS OF QUASIGROUPS AND LOOPS
|
## InstallTrueMethod(IsLeftQuasigroup, IsGroup);
|
||||||
## --------------------------------------------------------------------------
|
|
||||||
|
## quasigroup
|
||||||
#DirectProduct already declared for groups.
|
DeclareSynonym( "IsQuasigroup", IsRightQuasigroup and IsLeftQuasigroup );
|
||||||
|
|
||||||
#############################################################################
|
## loop
|
||||||
## OPPOSITE QUASIGROUPS AND LOOPS
|
DeclareSynonym( "IsLoop", IsQuasigroup and IsMagmaWithOne and
|
||||||
## --------------------------------------------------------------------------
|
IsMultiplicativeElementWithInverseCollection);
|
||||||
|
|
||||||
DeclareOperation( "OppositeQuasigroup", [ IsQuasigroup ] );
|
#############################################################################
|
||||||
DeclareOperation( "OppositeLoop", [ IsLoop ] );
|
## TESTING MULTIPLICATION TABLES
|
||||||
DeclareAttribute( "Opposite", IsQuasigroup );
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
#############################################################################
|
DeclareProperty( "IsLeftQuasigroupTable", IsMatrix );
|
||||||
## AUXILIARY
|
DeclareProperty( "IsRightQuasigroupTable", IsMatrix );
|
||||||
## --------------------------------------------------------------------------
|
DeclareSynonym( "IsQuasigroupTable",
|
||||||
DeclareGlobalFunction( "LOOPS_ReadCayleyTableFromFile" );
|
IsLeftQuasigroupTable and IsRightQuasigroupTable );
|
||||||
DeclareGlobalFunction( "LOOPS_CayleyTableByRightFolder" );
|
DeclareSynonym( "IsQuasigroupCayleyTable", IsQuasigroupTable );
|
||||||
|
DeclareProperty( "IsLoopTable", IsMatrix );
|
||||||
|
DeclareSynonym( "IsLoopCayleyTable", IsLoopTable );
|
||||||
|
DeclareGlobalFunction("CanonicalCayleyTableOfLeftQuasigroupTable");
|
||||||
|
DeclareOperation( "CanonicalCayleyTable", [ IsMatrix ] );
|
||||||
|
DeclareOperation( "NormalizedQuasigroupTable", [ IsMatrix ] );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## CREATING QUASIGROUPS AND LOOPS MANUALLY
|
||||||
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DeclareAttribute( "CayleyTable", IsMagma );
|
||||||
|
DeclareOperation( "QuasigroupByCayleyTable", [ IsMatrix ] );
|
||||||
|
DeclareOperation( "LoopByCayleyTable", [ IsMatrix ] );
|
||||||
|
DeclareOperation( "SpecifyElmNamePrefix", [ IsCollection, IsString ] );
|
||||||
|
DeclareSynonym( "SetQuasigroupElmName", SpecifyElmNamePrefix );
|
||||||
|
DeclareSynonym( "SetLoopElmName", SpecifyElmNamePrefix );
|
||||||
|
DeclareOperation( "BindElmNames", [ IsMagma ] );
|
||||||
|
DeclareAttribute( "ConstructorFromTable", IsMagma );
|
||||||
|
DeclareOperation( "CanonicalCopy", [ IsMagma ] );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## CREATING QUASIGROUPS AND LOOPS FROM A FILE
|
||||||
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DeclareOperation( "QuasigroupFromFile", [ IsString, IsString ] );
|
||||||
|
DeclareOperation( "LoopFromFile", [ IsString, IsString ] );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## CREATING QUASIGROUPS AND LOOPS BY SECTIONS
|
||||||
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DeclareGlobalFunction("CayleyTableByPerms");
|
||||||
|
DeclareOperation( "QuasigroupByLeftSection", [ IsPermCollection ] );
|
||||||
|
DeclareOperation( "LoopByLeftSection", [ IsPermCollection ] );
|
||||||
|
DeclareOperation( "QuasigroupByRightSection", [ IsPermCollection ] );
|
||||||
|
DeclareOperation( "LoopByRightSection", [ IsPermCollection ] );
|
||||||
|
DeclareOperation( "QuasigroupByRightFolder", [ IsGroup, IsGroup, IsMultiplicativeElementCollection ] );
|
||||||
|
DeclareOperation( "LoopByRightFolder", [ IsGroup, IsGroup, IsMultiplicativeElementCollection ] );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## CONVERSIONS
|
||||||
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DeclareOperation( "IntoQuasigroup", [ IsMagma ] );
|
||||||
|
DeclareOperation( "PrincipalLoopIsotope",
|
||||||
|
[ IsQuasigroup, IsQuasigroupElement, IsQuasigroupElement ] );
|
||||||
|
DeclareOperation( "IntoLoop", [ IsMagma ] );
|
||||||
|
DeclareOperation( "IntoGroup", [ IsMagma ] );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## PRODUCTS OF QUASIGROUPS AND LOOPS
|
||||||
|
## --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DeclareGlobalFunction("ProductTableOfCanonicalCayleyTables");
|
||||||
|
#DirectProduct already declared for groups.
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## OPPOSITE QUASIGROUPS AND LOOPS
|
||||||
|
## --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DeclareGlobalFunction( "OppositeQuasigroup");
|
||||||
|
DeclareGlobalFunction( "OppositeLoop");
|
||||||
|
DeclareAttribute( "Opposite", IsMagma );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## AUXILIARY
|
||||||
|
## --------------------------------------------------------------------------
|
||||||
|
DeclareGlobalFunction( "LOOPS_ReadCayleyTableFromFile" );
|
||||||
|
DeclareGlobalFunction( "LOOPS_CayleyTableByRightFolder" );
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#O IsQuasigroupTable( ls )
|
#O IsLeftQuasigroupTable( ls )
|
||||||
##
|
##
|
||||||
## Returns true if <ls> is an n by n latin square with n distinct
|
## Returns true if <ls> is an n by n matrix with n distinct
|
||||||
## integral entries.
|
## integral entries, each occurring exactly once in each row
|
||||||
|
|
||||||
InstallMethod( IsQuasigroupTable, "for matrix",
|
InstallMethod( IsLeftQuasigroupTable, "for matrix",
|
||||||
[ IsMatrix ],
|
[ IsMatrix ],
|
||||||
function( ls )
|
function( ls )
|
||||||
local first_row;
|
local first_row;
|
||||||
@ -27,14 +27,21 @@ function( ls )
|
|||||||
first_row := Set( ls[ 1 ] );
|
first_row := Set( ls[ 1 ] );
|
||||||
if not Length( first_row ) = Length( ls[ 1 ] ) then return false; fi;
|
if not Length( first_row ) = Length( ls[ 1 ] ) then return false; fi;
|
||||||
if ForAll( ls, row -> Set( row ) = first_row ) = false then return false; fi;
|
if ForAll( ls, row -> Set( row ) = first_row ) = false then return false; fi;
|
||||||
# checking columns
|
|
||||||
ls := TransposedMat( ls );
|
|
||||||
first_row := Set( ls[ 1 ] );
|
|
||||||
if not Length( first_row ) = Length( ls[ 1 ] ) then return false; fi;
|
|
||||||
if ForAll( ls, row -> Set( row ) = first_row ) = false then return false; fi;
|
|
||||||
return true;
|
return true;
|
||||||
end );
|
end );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
##
|
||||||
|
#O IsRightQuasigroupTable( ls )
|
||||||
|
##
|
||||||
|
## Returns true if <ls> is an n by n matrix with n distinct
|
||||||
|
## integral entries, each occurring exactly once in each column
|
||||||
|
|
||||||
|
InstallMethod( IsRightQuasigroupTable, "for matrix",
|
||||||
|
[ IsMatrix ],
|
||||||
|
mat -> IsLeftQuasigroupTable(TransposedMat(mat))
|
||||||
|
);
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#O IsLoopTable( ls )
|
#O IsLoopTable( ls )
|
||||||
@ -51,6 +58,36 @@ function( ls )
|
|||||||
and ls[ 1 ] = List( [1..Length(ls)], i -> ls[ i ][ 1 ] );
|
and ls[ 1 ] = List( [1..Length(ls)], i -> ls[ i ][ 1 ] );
|
||||||
end );
|
end );
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
##
|
||||||
|
#O CanonicalCayleyTableOfLeftQuasigroupTable( ls )
|
||||||
|
##
|
||||||
|
## Returns a Cayley table isomorphic to <ls>, which must already be known
|
||||||
|
## to be a left quasigroup table, in which the entries of ls
|
||||||
|
## have been replaced by numerical values 1, ..., n in the following way:
|
||||||
|
## Let e_1 < ... < e_n be all distinct entries of ls. Then e_i is renamed
|
||||||
|
## to i. In particular, when {e_1,...e_n} = {1,...,n}, the operation
|
||||||
|
## does nothing.
|
||||||
|
|
||||||
|
InstallGlobalFunction( CanonicalCayleyTableOfLeftQuasigroupTable,
|
||||||
|
function( ls )
|
||||||
|
local n, entries, i, j, T;
|
||||||
|
n := Length( ls );
|
||||||
|
# finding all distinct entries in the table
|
||||||
|
entries := [];
|
||||||
|
for i in ls[1] do
|
||||||
|
AddSet( entries, i );
|
||||||
|
od;
|
||||||
|
if entries = [1..n] then return List(ls, l -> ShallowCopy(l));
|
||||||
|
fi;
|
||||||
|
# renaming the entries and making a mutable copy, too
|
||||||
|
T := List( [1..n], i -> [1..n] );
|
||||||
|
for i in [1..n] do for j in [1..n] do
|
||||||
|
T[ i ][ j ] := Position( entries, ls[ i ][ j ] );
|
||||||
|
od; od;
|
||||||
|
return T;
|
||||||
|
end );
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#O CanonicalCayleyTable( ls )
|
#O CanonicalCayleyTable( ls )
|
||||||
@ -71,13 +108,15 @@ function( ls )
|
|||||||
for i in [1..n] do for j in [1..n] do
|
for i in [1..n] do for j in [1..n] do
|
||||||
AddSet( entries, ls[ i ][ j ] );
|
AddSet( entries, ls[ i ][ j ] );
|
||||||
od; od;
|
od; od;
|
||||||
|
if entries = [1..n] then return List(ls, l -> ShallowCopy(l));
|
||||||
|
fi;
|
||||||
# renaming the entries and making a mutable copy, too
|
# renaming the entries and making a mutable copy, too
|
||||||
T := List( [1..n], i -> [1..n] );
|
T := List( [1..n], i -> [1..n] );
|
||||||
for i in [1..n] do for j in [1..n] do
|
for i in [1..n] do for j in [1..n] do
|
||||||
T[ i ][ j ] := Position( entries, ls[ i ][ j ] );
|
T[ i ][ j ] := Position( entries, ls[ i ][ j ] );
|
||||||
od; od;
|
od; od;
|
||||||
return T;
|
return T;
|
||||||
end );
|
end);
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
@ -94,7 +133,7 @@ function( ls )
|
|||||||
Error( "LOOPS: <1> must be a latin square." );
|
Error( "LOOPS: <1> must be a latin square." );
|
||||||
fi;
|
fi;
|
||||||
# renaming the entries to be 1, ..., n
|
# renaming the entries to be 1, ..., n
|
||||||
T := CanonicalCayleyTable( ls );
|
T := CanonicalCayleyTableOfLeftQuasigroupTable( ls );
|
||||||
# permuting the columns so that the first row reads 1, ..., n
|
# permuting the columns so that the first row reads 1, ..., n
|
||||||
perm := PermList( T[ 1 ] );
|
perm := PermList( T[ 1 ] );
|
||||||
T := List( T, row -> Permuted( row, perm ) );
|
T := List( T, row -> Permuted( row, perm ) );
|
||||||
@ -110,10 +149,12 @@ end );
|
|||||||
##
|
##
|
||||||
#A CayleyTable( Q )
|
#A CayleyTable( Q )
|
||||||
##
|
##
|
||||||
## Returns the Cayley table of the quasigroup <Q>
|
## Returns the Cayley table of the magma <Q>. This is just like
|
||||||
|
## its multiplication table, except in case Q is a submagma of P, in which
|
||||||
|
## case the entries used are the indices in P rather than in Q.
|
||||||
|
|
||||||
InstallMethod( CayleyTable, "for quasigroup",
|
InstallMethod( CayleyTable, "for magma",
|
||||||
[ IsQuasigroup ],
|
[ IsMagma ],
|
||||||
function( Q )
|
function( Q )
|
||||||
local elms, parent_elms;
|
local elms, parent_elms;
|
||||||
elms := Elements( Q );
|
elms := Elements( Q );
|
||||||
@ -136,7 +177,7 @@ function( ct )
|
|||||||
Error( "LOOPS: <1> must be a latin square." );
|
Error( "LOOPS: <1> must be a latin square." );
|
||||||
fi;
|
fi;
|
||||||
# Making sure that entries are 1, ..., n
|
# Making sure that entries are 1, ..., n
|
||||||
ct := CanonicalCayleyTable( ct );
|
ct := CanonicalCayleyTableOfLeftQuasigroupTable( ct );
|
||||||
# constructing the family
|
# constructing the family
|
||||||
F := NewFamily( "QuasigroupByCayleyTableFam", IsQuasigroupElement );
|
F := NewFamily( "QuasigroupByCayleyTableFam", IsQuasigroupElement );
|
||||||
# installing data for the family
|
# installing data for the family
|
||||||
@ -146,7 +187,7 @@ function( ct )
|
|||||||
NewType( F, IsQuasigroupElement and IsQuasigroupElmRep), [ i ] ) ) );
|
NewType( F, IsQuasigroupElement and IsQuasigroupElmRep), [ i ] ) ) );
|
||||||
F!.set := elms;
|
F!.set := elms;
|
||||||
F!.cayleyTable := ct;
|
F!.cayleyTable := ct;
|
||||||
F!.names := "q";
|
F!.elmNamePrefix := "q";
|
||||||
# creating the quasigroup
|
# creating the quasigroup
|
||||||
Q := Objectify( NewType( FamilyObj( elms ),
|
Q := Objectify( NewType( FamilyObj( elms ),
|
||||||
IsQuasigroup and IsAttributeStoringRep ), rec() );
|
IsQuasigroup and IsAttributeStoringRep ), rec() );
|
||||||
@ -155,6 +196,7 @@ function( ct )
|
|||||||
SetAsSSortedList( Q, elms );
|
SetAsSSortedList( Q, elms );
|
||||||
SetParent( Q, Q );
|
SetParent( Q, Q );
|
||||||
SetCayleyTable( Q, ct );
|
SetCayleyTable( Q, ct );
|
||||||
|
SetConstructorFromTable(Q, QuasigroupByCayleyTable);
|
||||||
return Q;
|
return Q;
|
||||||
end );
|
end );
|
||||||
|
|
||||||
@ -173,7 +215,7 @@ function( ct )
|
|||||||
fi;
|
fi;
|
||||||
# Making sure that the entries are 1, ..., n.
|
# Making sure that the entries are 1, ..., n.
|
||||||
# The table will remain normalized.
|
# The table will remain normalized.
|
||||||
ct := CanonicalCayleyTable( ct );
|
ct := CanonicalCayleyTableOfLeftQuasigroupTable( ct );
|
||||||
# constructing the family
|
# constructing the family
|
||||||
F := NewFamily( "LoopByCayleyTableFam", IsLoopElement );
|
F := NewFamily( "LoopByCayleyTableFam", IsLoopElement );
|
||||||
# installing the data for the family
|
# installing the data for the family
|
||||||
@ -183,7 +225,7 @@ function( ct )
|
|||||||
NewType( F, IsLoopElement and IsLoopElmRep), [ i ] ) ) );
|
NewType( F, IsLoopElement and IsLoopElmRep), [ i ] ) ) );
|
||||||
F!.set := elms;
|
F!.set := elms;
|
||||||
F!.cayleyTable := ct;
|
F!.cayleyTable := ct;
|
||||||
F!.names := "l";
|
F!.elmNamePrefix := "l";
|
||||||
# creating the loop
|
# creating the loop
|
||||||
L := Objectify( NewType( FamilyObj( elms ),
|
L := Objectify( NewType( FamilyObj( elms ),
|
||||||
IsLoop and IsAttributeStoringRep ), rec() );
|
IsLoop and IsAttributeStoringRep ), rec() );
|
||||||
@ -193,39 +235,88 @@ function( ct )
|
|||||||
SetParent( L, L );
|
SetParent( L, L );
|
||||||
SetCayleyTable( L, ct );
|
SetCayleyTable( L, ct );
|
||||||
SetOne( L, elms[ 1 ] );
|
SetOne( L, elms[ 1 ] );
|
||||||
|
SetConstructorFromTable(L, LoopByCayleyTable);
|
||||||
return L;
|
return L;
|
||||||
end );
|
end );
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#O SetQuasigroupElmName( Q, name )
|
#O SpecifyElmNamePrefix( C, name )
|
||||||
##
|
##
|
||||||
## Changes the name of elements of quasigroup or loop <Q> to <name>
|
## Sets the elmNamePrefix property on the family of a Representative of
|
||||||
|
## collection <C>. For quasigroups, loops, and possibly related structures
|
||||||
|
## this changes the prefix with which the elements of that family are printed.
|
||||||
|
|
||||||
InstallMethod( SetQuasigroupElmName, "for quasigroup and string",
|
InstallMethod( SpecifyElmNamePrefix, "for collection and string",
|
||||||
[ IsQuasigroup, IsString ],
|
[ IsCollection, IsString ],
|
||||||
function( Q, name )
|
function( Q, name )
|
||||||
local F;
|
local F;
|
||||||
F := FamilyObj( Elements( Q )[ 1 ] );
|
F := FamilyObj( Representative( Q ) );
|
||||||
F!.names := name;
|
F!.elmNamePrefix := name;
|
||||||
|
end);
|
||||||
|
#############################################################################
|
||||||
|
##
|
||||||
|
#O BindElmNames( M )
|
||||||
|
##
|
||||||
|
## For each element e of the magma <M>, binds the identifier named String(e)
|
||||||
|
## to e.
|
||||||
|
|
||||||
|
InstallMethod( BindElmNames, "for a magma",
|
||||||
|
[ IsMagma ],
|
||||||
|
function( M )
|
||||||
|
local e, nm;
|
||||||
|
for e in Elements(M) do
|
||||||
|
nm := String(e);
|
||||||
|
BindGlobal(nm, e);
|
||||||
|
MakeReadWriteGlobal(nm);
|
||||||
|
od;
|
||||||
|
return;
|
||||||
end);
|
end);
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
##
|
||||||
|
#O ConstructorFromTable( M )
|
||||||
|
##
|
||||||
|
## Given a magma <M>, returns a function which will create a domain of the
|
||||||
|
## same structure as M from from an operation table. This implementation of
|
||||||
|
## the method is to backfill the constructors for library domains that do
|
||||||
|
## not set the attribute directly at construction time. New domains that wish
|
||||||
|
## to use facilities like CanonicalCopy or Opposite should call
|
||||||
|
## SetConstructorFromTable at creation time.
|
||||||
|
|
||||||
|
InstallMethod( ConstructorFromTable, "for other magmas",
|
||||||
|
[ IsMagma ],
|
||||||
|
function ( M )
|
||||||
|
# Go in reverse order of refinement of structure
|
||||||
|
if IsGroup(M) then
|
||||||
|
return GroupByMultiplicationTable;
|
||||||
|
elif IsMagmaWithInverses(M) then
|
||||||
|
return MagmaWithInversesByMultiplicationTable;
|
||||||
|
elif IsMonoid(M) then
|
||||||
|
return MonoidByMultiplicationTable;
|
||||||
|
elif IsMagmaWithOne(M) then
|
||||||
|
return MagmaWithOneByMultiplicationTable;
|
||||||
|
elif IsSemigroup(M) then
|
||||||
|
return SemigroupByMultiplicationTable;
|
||||||
|
fi;
|
||||||
|
return MagmaByMultiplicationTable;
|
||||||
|
end);
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#O CanonicalCopy( Q )
|
#O CanonicalCopy( Q )
|
||||||
##
|
##
|
||||||
## Returns a canonical copy of <Q>, that is, an isomorphic object <O> with
|
## Returns a canonical copy of <Q>, that is, an isomorphic object <O> with
|
||||||
## canonical multiplication table and Parent( <O> ) = <O>.
|
## canonical multiplication table and no parent set. Note that this is
|
||||||
|
## guaranteed to be a new object, not satisfying IsIdenticalObj with any
|
||||||
|
## previously existing structure. THEREFORE:
|
||||||
## (PROG) Properties and attributes are lost!
|
## (PROG) Properties and attributes are lost!
|
||||||
|
|
||||||
InstallMethod( CanonicalCopy, "for quasigroup or loop",
|
InstallMethod( CanonicalCopy, "for magma",
|
||||||
[ IsQuasigroup ],
|
[ IsMagma ],
|
||||||
function( Q )
|
M -> ConstructorFromTable(M)(MultiplicationTable(M))
|
||||||
if IsLoop( Q ) then
|
);
|
||||||
return LoopByCayleyTable( CayleyTable( Q ) );
|
|
||||||
fi;
|
|
||||||
return QuasigroupByCayleyTable( CayleyTable( Q ) );
|
|
||||||
end);
|
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -347,30 +438,44 @@ end );
|
|||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#O CayleyTableByPerms( perms )
|
#O CayleyTableByPerms( perms, [X] )
|
||||||
##
|
##
|
||||||
## Given a set <perms> of n permutations of an n-element set X, returns
|
## Given a set <perms> of n permutations of an n-element set <X> of natural
|
||||||
## n by n Cayley table ct such that ct[i][j] = X[j]^perms[i].
|
## numbers, returns an n by n Cayley table ct such that
|
||||||
## The operation is safe only if at most one permutation of <perms> is
|
## ct[i][j] = X[j]^perms[i].
|
||||||
## the identity permutation, and all other permutations of <perms>
|
##
|
||||||
## move all points of X.
|
## Note that the argument <X> is optional, and if omitted, the function will
|
||||||
|
## assume that at most one permutation of <perms> is the identity
|
||||||
|
## permutation, and that all other permutations of <perms>
|
||||||
|
## move all points of <X>.
|
||||||
|
|
||||||
InstallMethod( CayleyTableByPerms,
|
InstallGlobalFunction( CayleyTableByPerms,
|
||||||
"for a list of permutations",
|
function( perms, rest... )
|
||||||
[ IsPermCollection ],
|
|
||||||
function( perms )
|
|
||||||
local n, pts, max;
|
local n, pts, max;
|
||||||
n := Length( perms );
|
n := Length( perms );
|
||||||
if n=1 then
|
if n=1 then
|
||||||
return [ [ 1 ] ];
|
return [ [ 1 ] ];
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
# one of perms[ 1 ], perms[ 2 ] must move all points
|
# one of perms[ 1 ], perms[ 2 ] must move all points
|
||||||
pts := MovedPoints( perms[ 2 ] );
|
if Length(rest) > 0 then
|
||||||
if pts = [] then
|
pts := rest[1];
|
||||||
|
else
|
||||||
|
pts := MovedPoints( perms[ 2 ] );
|
||||||
|
if pts = [] then
|
||||||
pts := MovedPoints( perms[ 1 ] );
|
pts := MovedPoints( perms[ 1 ] );
|
||||||
|
fi;
|
||||||
|
fi;
|
||||||
|
if Length(pts) <> n then
|
||||||
|
Error("perms for cayley table of size ", n, " cannot act on ",
|
||||||
|
Length(pts), " points.");
|
||||||
fi;
|
fi;
|
||||||
max := Maximum( pts );
|
max := Maximum( pts );
|
||||||
# we permute the whole interval [1..max] and then keep only those coordinates corresponding to pts
|
if max = n then
|
||||||
|
# Common case, we are permuting [1..n]
|
||||||
|
return List( perms, x -> ListPerm(x, n));
|
||||||
|
fi;
|
||||||
|
# Otherwise we permute the whole interval [1..max] and then keep only those coordinates corresponding to pts
|
||||||
return List( perms, p -> Permuted( [1..max], p^(-1) ){ pts } );
|
return List( perms, p -> Permuted( [1..max], p^(-1) ){ pts } );
|
||||||
end);
|
end);
|
||||||
|
|
||||||
@ -627,95 +732,104 @@ end);
|
|||||||
# groups in GAP. The idea is as follows:
|
# groups in GAP. The idea is as follows:
|
||||||
# We want to calculate direct product of quasigroups, loops and groups.
|
# We want to calculate direct product of quasigroups, loops and groups.
|
||||||
# If only groups are on the list, standard GAP DirectProduct will take care
|
# If only groups are on the list, standard GAP DirectProduct will take care
|
||||||
# of it. If there are also some quasigroups or loops on the list,
|
# of it. If there are also some quasigroups or loops on the list (but nothing
|
||||||
# we must take care of it.
|
# that is not a quasigroup), we must take care of it.
|
||||||
# However, we do not know if such a list will be processed with
|
# However, we do not know if such a list will be processed with
|
||||||
# DirectProductOp( <IsList>, <IsGroup> ), or
|
# DirectProductOp( <IsList>, <IsGroup> ), or
|
||||||
# DirectProductOp( <IsList>, <IsQuasigroup> ),
|
# DirectProductOp( <IsList>, <IsQuasigroup> ),
|
||||||
# since this depends on which algebra is listed first.
|
# since this depends on which algebra is listed first.
|
||||||
# We therefore take care of both situations.
|
# Call the item in the second argument of DirectProductOp the "distinguished"
|
||||||
|
# item. To produce the correct result whichever of the two above cases for
|
||||||
|
# DirectProductOp ends up being called, we add a method in the first case
|
||||||
|
# which repeats the product call with the first non-group it encounters (if
|
||||||
|
# any) as the distinguished item. Further, the method for the
|
||||||
|
# latter case must itself repeat the call with a similar reordering if it
|
||||||
|
# finds anyitem that is not a quasigroup.
|
||||||
|
|
||||||
InstallOtherMethod( DirectProductOp, "for DirectProduct( <IsList>, <IsGroup> )",
|
InstallMethod( DirectProductOp, "for DirectProduct( <IsList>, <IsGroup> )",
|
||||||
[ IsList, IsGroup],
|
[ IsList, IsGroup],
|
||||||
function( list, first )
|
function( list, first )
|
||||||
local L, p;
|
local L, p;
|
||||||
|
|
||||||
# Check the arguments.
|
# Check the arguments.
|
||||||
if IsEmpty( list ) then Error( "LOOPS: <1> must be nonempty." ); fi;
|
if IsEmpty( list ) then
|
||||||
if not ForAny( list, IsQuasigroup ) then
|
Error( "LOOPS: <1> must be nonempty." );
|
||||||
# there are no quasigroups or loops on the list
|
elif Length(list) = 1 then
|
||||||
TryNextMethod();
|
return list[1];
|
||||||
fi;
|
fi;
|
||||||
if ForAny( list, G -> (not IsGroup( G )) and (not IsQuasigroup( G ) ) ) then
|
for p in [1..Length(list)] do
|
||||||
# there are other objects beside groups, loops and quasigroups on the list
|
if not IsGroup(list[p]) then
|
||||||
TryNextMethod();
|
return DirectProductOp(Permuted(list, (1,p)), list[p]);
|
||||||
fi;
|
|
||||||
|
|
||||||
# all arguments are groups, quasigroups or loops, and there is at least one loop
|
|
||||||
# making sure that a loop is listed first so that this method is not called again
|
|
||||||
for L in list do
|
|
||||||
if not IsGroup( L ) then
|
|
||||||
p := Position( list, L );
|
|
||||||
list[ 1 ] := L;
|
|
||||||
list[ p ] := first;
|
|
||||||
break;
|
|
||||||
fi;
|
fi;
|
||||||
od;
|
od;
|
||||||
|
# OK, everything is a group, so let the rest of GAP do the work.
|
||||||
|
TryNextMethod();
|
||||||
|
end);
|
||||||
|
|
||||||
return DirectProductOp( list, list[ 1 ] );
|
InstallGlobalFunction(ProductTableOfCanonicalCayleyTables,
|
||||||
|
function(tablist)
|
||||||
|
local i, nL, nM, TL, TM, T, j, k, s;
|
||||||
|
TL := tablist[1];
|
||||||
|
for s in [2..Length(tablist)] do
|
||||||
|
TM := tablist[ s ];
|
||||||
|
nL := Length( TL); nM := Length( TM );
|
||||||
|
T := List( [1..nL*nM], j->[] );
|
||||||
|
# not efficient, but it does the job
|
||||||
|
for i in [1..nM] do for j in [1..nM] do for k in [1..nL] do
|
||||||
|
Append( T[ (i-1)*nL + k ], TL[ k ] + nL*(TM[i][j]-1) );
|
||||||
|
od; od; od;
|
||||||
|
TL := T;
|
||||||
|
od;
|
||||||
|
return TL;
|
||||||
end);
|
end);
|
||||||
|
|
||||||
InstallOtherMethod( DirectProductOp, "for DirectProduct( <IsList>, <IsQuasigroup> )",
|
InstallOtherMethod( DirectProductOp, "for DirectProduct( <IsList>, <IsQuasigroup> )",
|
||||||
[ IsList, IsQuasigroup ],
|
[ IsList, IsQuasigroup ],
|
||||||
function( list, dummy )
|
function( list, dummy )
|
||||||
|
|
||||||
local group_list, quasigroup_list, group_product, are_all_loops,
|
local group_list, quasigroup_list, group_product, are_all_loops, n, i, T;
|
||||||
n, i, nL, nM, TL, TM, T, j, k, s;
|
|
||||||
|
|
||||||
# check the arguments
|
# check the arguments
|
||||||
if IsEmpty( list ) then
|
if IsEmpty( list ) then
|
||||||
Error( "LOOPS: <1> must be nonempty." );
|
Error( "LOOPS: <1> must be nonempty." );
|
||||||
elif ForAny( list, G -> (not IsGroup( G )) and (not IsQuasigroup( G ) ) ) then
|
elif Length(list) = 1 then
|
||||||
TryNextMethod();
|
return list[1];
|
||||||
fi;
|
fi;
|
||||||
|
group_list := [];
|
||||||
|
quasigroup_list := list{[1]};
|
||||||
|
are_all_loops := IsLoop(list[1]);
|
||||||
|
for i in [2..Length(list)] do
|
||||||
|
if IsGroup(list[i]) then
|
||||||
|
Add(group_list, list[i]);
|
||||||
|
elif IsQuasigroup(list[i]) then
|
||||||
|
Add(quasigroup_list, list[i]);
|
||||||
|
if are_all_loops and not IsLoop(list[i]) then
|
||||||
|
are_all_loops := false;
|
||||||
|
fi;
|
||||||
|
else # Oops, something that's neither a group or quasigroup
|
||||||
|
return DirectProductOp(Permuted(list,(1.i)), list[i]);
|
||||||
|
fi;
|
||||||
|
od;
|
||||||
|
|
||||||
# only groups, quasigroups and loops are on the list, with at least one non-group
|
# only groups, quasigroups and loops are on the list, with at least one
|
||||||
group_list := Filtered( list, G -> IsGroup( G ) );
|
# non-group; moreover, we have partitioned the list into groups and
|
||||||
quasigroup_list := Filtered( list, G -> IsQuasigroup( G ) );
|
# non-groups and checked whether all quasigroups are really loops.
|
||||||
if not IsEmpty( group_list ) then # some groups are on the list
|
if not IsEmpty( group_list ) then # some groups are on the list
|
||||||
group_product := DirectProductOp( group_list, group_list[ 1 ] );
|
group_product := DirectProductOp( group_list, group_list[ 1 ] );
|
||||||
Add( quasigroup_list, IntoLoop( group_product ) );
|
Add( quasigroup_list, IntoLoop( group_product ) );
|
||||||
fi;
|
fi;
|
||||||
# keeping track of whether all algebras are in fact loops
|
|
||||||
are_all_loops := ForAll( quasigroup_list, IsLoop );
|
|
||||||
|
|
||||||
# now only quasigroups and loops are on the list
|
# now only quasigroups and loops are on the list, with at least 2 of them
|
||||||
n := Length( quasigroup_list );
|
n := Length( quasigroup_list );
|
||||||
if n=1 then
|
# We will not use recursion; start by making all Cayley tables canonical
|
||||||
return quasigroup_list[ 1 ];
|
Apply(quasigroup_list,
|
||||||
fi;
|
Q -> CanonicalCayleyTableOfLeftQuasigroupTable( CayleyTable( Q ) ) );
|
||||||
# at least 2 quasigroups and loops; we will not use recursion
|
T := ProductTableOfCanonicalCayleyTables( quasigroup_list );
|
||||||
# making all Cayley tables cannonical
|
|
||||||
for s in [1..n] do
|
|
||||||
quasigroup_list[ s ] := QuasigroupByCayleyTable( CanonicalCayleyTable( CayleyTable( quasigroup_list[ s ] ) ) );
|
|
||||||
od;
|
|
||||||
for s in [2..n] do
|
|
||||||
nL := Size( quasigroup_list[ 1 ] );
|
|
||||||
nM := Size( quasigroup_list[ s ] );
|
|
||||||
TL := CayleyTable( quasigroup_list[ 1 ] );
|
|
||||||
TM := CayleyTable( quasigroup_list[ s ] );
|
|
||||||
T := List( [1..nL*nM], j->[] );
|
|
||||||
|
|
||||||
# not efficient, but it does the job
|
|
||||||
for i in [1..nM] do for j in [1..nM] do for k in [1..nL] do
|
|
||||||
Append( T[ (i-1)*nL + k ], TL[ k ] + nL*(TM[i][j]-1) );
|
|
||||||
od; od; od;
|
|
||||||
quasigroup_list[ 1 ] := QuasigroupByCayleyTable( T );
|
|
||||||
od;
|
|
||||||
if are_all_loops then
|
if are_all_loops then
|
||||||
return IntoLoop( quasigroup_list[1] );
|
return LoopByCayleyTable( T );
|
||||||
fi;
|
fi;
|
||||||
return quasigroup_list[ 1 ];
|
return QuasigroupByCayleyTable( T );
|
||||||
end );
|
end );
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -726,41 +840,36 @@ function( list, dummy )
|
|||||||
##
|
##
|
||||||
#O OppositeQuasigroup( Q )
|
#O OppositeQuasigroup( Q )
|
||||||
##
|
##
|
||||||
## Returns the quasigroup opposite to the quasigroup <Q>.
|
## Identical to Opposite, except forces its return to be a quasigroup if
|
||||||
|
## possible
|
||||||
|
|
||||||
InstallMethod( OppositeQuasigroup, "for quasigroup",
|
InstallGlobalFunction( OppositeQuasigroup,
|
||||||
[ IsQuasigroup ],
|
Q -> IntoQuasigroup( Opposite( Q ) ) );
|
||||||
function( Q )
|
|
||||||
return QuasigroupByCayleyTable( TransposedMat( CayleyTable( Q ) ) );
|
|
||||||
end );
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#O OppositeLoop( Q )
|
#O OppositeLoop( Q )
|
||||||
##
|
##
|
||||||
## Returns the loop opposite to the loop <Q>.
|
## Identical to Opposite, except forces its return to be a loop if possible
|
||||||
|
|
||||||
InstallMethod( OppositeLoop, "for loop",
|
InstallGlobalFunction( OppositeLoop, L -> IntoLoop( Opposite( L ) ) );
|
||||||
[ IsLoop ],
|
|
||||||
function( Q )
|
|
||||||
return LoopByCayleyTable( TransposedMat( CayleyTable( Q ) ) );
|
|
||||||
end );
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
##
|
##
|
||||||
#A Opposite( Q )
|
#A Opposite( M )
|
||||||
##
|
##
|
||||||
## Returns the quasigroup opposite to the quasigroup <Q>. When
|
## Returns the magma opposite to the magma <M>, with as much structure
|
||||||
## <Q> is a loop, a loop is returned.
|
## as can be preserved.
|
||||||
|
|
||||||
|
InstallMethod( Opposite, "for magma",
|
||||||
|
[ IsMagma and HasMultiplicationTable],
|
||||||
|
M -> ConstructorFromTable(M)( TransposedMat( MultiplicationTable( M ) ) )
|
||||||
|
);
|
||||||
|
|
||||||
InstallMethod( Opposite, "for quasigroup",
|
InstallMethod( Opposite, "for quasigroup",
|
||||||
[ IsQuasigroup ],
|
[ IsQuasigroup ], # Might not have a multiplication table
|
||||||
function( Q )
|
M -> ConstructorFromTable(M)( TransposedMat( CayleyTable( M ) ) )
|
||||||
if IsLoop( Q ) then
|
);
|
||||||
return LoopByCayleyTable( TransposedMat( CayleyTable( Q ) ) );
|
|
||||||
fi;
|
|
||||||
return QuasigroupByCayleyTable( TransposedMat( CayleyTable( Q ) ) );
|
|
||||||
end );
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## DISPLAYING QUASIGROUPS AND LOOPS
|
## DISPLAYING QUASIGROUPS AND LOOPS
|
||||||
|
Loading…
Reference in New Issue
Block a user