Rudimentary support for left/right quasigroups.
This commit is contained in:
parent
7e8b3b5562
commit
722f25e51f
@ -12,8 +12,40 @@
|
|||||||
## GAP CATEGORIES AND REPRESENTATIONS
|
## GAP CATEGORIES AND REPRESENTATIONS
|
||||||
## -------------------------------------------------------------------------
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Categories convenient for defining quasigroups
|
||||||
|
|
||||||
|
## element which is an admissible argument for the right argument of /
|
||||||
|
DeclareCategory( "IsRightQuotientElement", IsExtLElement);
|
||||||
|
DeclareCategoryCollections("IsRightQuotientElement");
|
||||||
|
DeclareCategoryCollections("IsRightQuotientElementCollection");
|
||||||
|
|
||||||
|
## Every element with an inverse can form right quotients
|
||||||
|
## (in fact, in some sense it might be enough to have just a left inverse,
|
||||||
|
## but there doesn't seem to be any benefit to delving to that level of
|
||||||
|
## detail at this point.)
|
||||||
|
InstallTrueMethod(IsRightQuotientElement, IsMultiplicativeElementWithInverse);
|
||||||
|
|
||||||
|
## Now what we would like to do is re-declare
|
||||||
|
## DeclareOperation( "/", [IsExtRElement, IsRightQuotientElement] );
|
||||||
|
## 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
|
||||||
|
## to if we could declare "/" more generally.)
|
||||||
|
|
||||||
|
## Element which is admissible for the left argument of LeftQuotient()
|
||||||
|
DeclareCategory( "IsLeftQuotientElement", IsExtRElement);
|
||||||
|
DeclareCategoryCollections("IsLeftQuotientElement");
|
||||||
|
DeclareCategoryCollections("IsLeftQuotientElementCollection");
|
||||||
|
|
||||||
|
## Every element with an inverse can form left quotients
|
||||||
|
InstallTrueMethod(IsLeftQuotientElement, IsMultiplicativeElementWithInverse);
|
||||||
|
|
||||||
|
## Again, ideally (in some sense) we'd like to redeclare
|
||||||
|
## DeclareOperation("LeftQuotient", [IsLeftQuotientElement,IsExtLElement]);
|
||||||
|
|
||||||
## element of a quasigroup
|
## element of a quasigroup
|
||||||
DeclareCategory( "IsQuasigroupElement", IsMultiplicativeElement );
|
DeclareCategory( "IsQuasigroupElement",
|
||||||
|
IsLeftQuotientElement and IsRightQuotientElement );
|
||||||
DeclareRepresentation( "IsQuasigroupElmRep",
|
DeclareRepresentation( "IsQuasigroupElmRep",
|
||||||
IsPositionalObjectRep and IsMultiplicativeElement, [1] );
|
IsPositionalObjectRep and IsMultiplicativeElement, [1] );
|
||||||
|
|
||||||
@ -23,23 +55,39 @@ DeclareCategory( "IsLoopElement",
|
|||||||
DeclareRepresentation( "IsLoopElmRep",
|
DeclareRepresentation( "IsLoopElmRep",
|
||||||
IsPositionalObjectRep and IsMultiplicativeElementWithInverse, [1] );
|
IsPositionalObjectRep and IsMultiplicativeElementWithInverse, [1] );
|
||||||
|
|
||||||
|
## Right quasigroup
|
||||||
|
DeclareCategory("IsRightQuasigroup",
|
||||||
|
IsMagma and IsRightQuotientElementCollection);
|
||||||
|
|
||||||
|
## Left quasigroup
|
||||||
|
DeclareCategory("IsLeftQuasigroup",
|
||||||
|
IsMagma and IsLeftQuotientElementCollection);
|
||||||
|
|
||||||
|
|
||||||
## latin (auxiliary category for GAP to tell apart IsMagma and IsQuasigroup)
|
## latin (auxiliary category for GAP to tell apart IsMagma and IsQuasigroup)
|
||||||
DeclareCategory( "IsLatin", IsObject );
|
DeclareSynonym( "IsLatin",
|
||||||
|
IsRightQuotientElementCollection and
|
||||||
|
IsLeftQuotientElementCollection );
|
||||||
|
|
||||||
## quasigroup
|
## quasigroup
|
||||||
DeclareCategory( "IsQuasigroup", IsMagma and IsLatin );
|
DeclareCategory( "IsQuasigroup", IsMagma and IsLatin );
|
||||||
|
|
||||||
## loop
|
## loop
|
||||||
DeclareCategory( "IsLoop", IsQuasigroup and IsMultiplicativeElementWithInverseCollection);
|
DeclareCategory( "IsLoop", IsQuasigroup and IsMagmaWithOne and
|
||||||
|
IsMultiplicativeElementWithInverseCollection);
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## TESTING MULTIPLICATION TABLES
|
## TESTING MULTIPLICATION TABLES
|
||||||
## -------------------------------------------------------------------------
|
## -------------------------------------------------------------------------
|
||||||
|
|
||||||
DeclareOperation( "IsQuasigroupTable", [ IsMatrix ] );
|
DeclareProperty( "IsLeftQuasigroupTable", [ IsMatrix ]);
|
||||||
|
DeclareProperty( "IsRightQuasigroupTable", [ IsMatrix ]);
|
||||||
|
DeclareSynonym( "IsQuasigroupTable",
|
||||||
|
IsLeftQuasigroupTable and IsRightQuasigroupTable );
|
||||||
DeclareSynonym( "IsQuasigroupCayleyTable", IsQuasigroupTable );
|
DeclareSynonym( "IsQuasigroupCayleyTable", IsQuasigroupTable );
|
||||||
DeclareOperation( "IsLoopTable", [ IsMatrix ] );
|
DeclareProperty( "IsLoopTable", [ IsMatrix ] );
|
||||||
DeclareSynonym( "IsLoopCayleyTable", IsLoopTable );
|
DeclareSynonym( "IsLoopCayleyTable", IsLoopTable );
|
||||||
|
DeclareGlobalFunction("CanonicalCayleyTableOfLeftQuasigroupTable");
|
||||||
DeclareOperation( "CanonicalCayleyTable", [ IsMatrix ] );
|
DeclareOperation( "CanonicalCayleyTable", [ IsMatrix ] );
|
||||||
DeclareOperation( "NormalizedQuasigroupTable", [ IsMatrix ] );
|
DeclareOperation( "NormalizedQuasigroupTable", [ IsMatrix ] );
|
||||||
|
|
||||||
@ -52,7 +100,7 @@ DeclareOperation( "QuasigroupByCayleyTable", [ IsMatrix ] );
|
|||||||
DeclareOperation( "LoopByCayleyTable", [ IsMatrix ] );
|
DeclareOperation( "LoopByCayleyTable", [ IsMatrix ] );
|
||||||
DeclareOperation( "SetQuasigroupElmName", [ IsQuasigroup, IsString ] );
|
DeclareOperation( "SetQuasigroupElmName", [ IsQuasigroup, IsString ] );
|
||||||
DeclareSynonym( "SetLoopElmName", SetQuasigroupElmName );
|
DeclareSynonym( "SetLoopElmName", SetQuasigroupElmName );
|
||||||
DeclareOperation( "CanonicalCopy", [ IsQuasigroup ] );
|
DeclareOperation( "CanonicalCopy", [ IsMagma ] );
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## CREATING QUASIGROUPS AND LOOPS FROM A FILE
|
## CREATING QUASIGROUPS AND LOOPS FROM A FILE
|
||||||
|
@ -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 IsRighttQuasigroupTable( ls )
|
||||||
|
##
|
||||||
|
## Returns true if <ls> is an n by n matrix with n distinct
|
||||||
|
## integral entries, each occurring exactly once in each column
|
||||||
|
|
||||||
|
InstallMethod( IsRighttQuasigroupTable, "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 ) );
|
||||||
@ -136,7 +175,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
|
||||||
@ -173,7 +212,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
|
||||||
@ -695,27 +734,30 @@ function( list, dummy )
|
|||||||
return quasigroup_list[ 1 ];
|
return quasigroup_list[ 1 ];
|
||||||
fi;
|
fi;
|
||||||
# at least 2 quasigroups and loops; we will not use recursion
|
# at least 2 quasigroups and loops; we will not use recursion
|
||||||
# making all Cayley tables cannonical
|
# making all Cayley tables canonical
|
||||||
for s in [1..n] do
|
for s in [1..n] do
|
||||||
quasigroup_list[ s ] := QuasigroupByCayleyTable( CanonicalCayleyTable( CayleyTable( quasigroup_list[ s ] ) ) );
|
quasigroup_list[ s ] :=
|
||||||
|
CanonicalCayleyTableOfLeftQuasigroupTable(
|
||||||
|
CayleyTable( quasigroup_list[ s ] ) );
|
||||||
od;
|
od;
|
||||||
|
# At this point the entries in quasigroup_list are really just tables
|
||||||
for s in [2..n] do
|
for s in [2..n] do
|
||||||
nL := Size( quasigroup_list[ 1 ] );
|
nL := Length( quasigroup_list[ 1 ] );
|
||||||
nM := Size( quasigroup_list[ s ] );
|
nM := Length( quasigroup_list[ s ] );
|
||||||
TL := CayleyTable( quasigroup_list[ 1 ] );
|
TL := quasigroup_list[ 1 ];
|
||||||
TM := CayleyTable( quasigroup_list[ s ] );
|
TM := quasigroup_list[ s ];
|
||||||
T := List( [1..nL*nM], j->[] );
|
T := List( [1..nL*nM], j->[] );
|
||||||
|
|
||||||
# not efficient, but it does the job
|
# 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
|
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) );
|
Append( T[ (i-1)*nL + k ], TL[ k ] + nL*(TM[i][j]-1) );
|
||||||
od; od; od;
|
od; od; od;
|
||||||
quasigroup_list[ 1 ] := QuasigroupByCayleyTable( T );
|
quasigroup_list[ 1 ] := T;
|
||||||
od;
|
od;
|
||||||
if are_all_loops then
|
if are_all_loops then
|
||||||
return IntoLoop( quasigroup_list[1] );
|
return LoopByCayleyTable( quasigroup_list[1] );
|
||||||
fi;
|
fi;
|
||||||
return quasigroup_list[ 1 ];
|
return QuasigroupByCayleyTable( quasigroup_list[1] );
|
||||||
end );
|
end );
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
Loading…
Reference in New Issue
Block a user