Rudimentary support for left/right quasigroups.
This commit is contained in:
parent
7e8b3b5562
commit
722f25e51f
@ -12,8 +12,40 @@
|
||||
## 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
|
||||
DeclareCategory( "IsQuasigroupElement", IsMultiplicativeElement );
|
||||
DeclareCategory( "IsQuasigroupElement",
|
||||
IsLeftQuotientElement and IsRightQuotientElement );
|
||||
DeclareRepresentation( "IsQuasigroupElmRep",
|
||||
IsPositionalObjectRep and IsMultiplicativeElement, [1] );
|
||||
|
||||
@ -23,23 +55,39 @@ DeclareCategory( "IsLoopElement",
|
||||
DeclareRepresentation( "IsLoopElmRep",
|
||||
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)
|
||||
DeclareCategory( "IsLatin", IsObject );
|
||||
DeclareSynonym( "IsLatin",
|
||||
IsRightQuotientElementCollection and
|
||||
IsLeftQuotientElementCollection );
|
||||
|
||||
## quasigroup
|
||||
DeclareCategory( "IsQuasigroup", IsMagma and IsLatin );
|
||||
|
||||
## loop
|
||||
DeclareCategory( "IsLoop", IsQuasigroup and IsMultiplicativeElementWithInverseCollection);
|
||||
DeclareCategory( "IsLoop", IsQuasigroup and IsMagmaWithOne and
|
||||
IsMultiplicativeElementWithInverseCollection);
|
||||
|
||||
#############################################################################
|
||||
## TESTING MULTIPLICATION TABLES
|
||||
## -------------------------------------------------------------------------
|
||||
|
||||
DeclareOperation( "IsQuasigroupTable", [ IsMatrix ] );
|
||||
DeclareProperty( "IsLeftQuasigroupTable", [ IsMatrix ]);
|
||||
DeclareProperty( "IsRightQuasigroupTable", [ IsMatrix ]);
|
||||
DeclareSynonym( "IsQuasigroupTable",
|
||||
IsLeftQuasigroupTable and IsRightQuasigroupTable );
|
||||
DeclareSynonym( "IsQuasigroupCayleyTable", IsQuasigroupTable );
|
||||
DeclareOperation( "IsLoopTable", [ IsMatrix ] );
|
||||
DeclareProperty( "IsLoopTable", [ IsMatrix ] );
|
||||
DeclareSynonym( "IsLoopCayleyTable", IsLoopTable );
|
||||
DeclareGlobalFunction("CanonicalCayleyTableOfLeftQuasigroupTable");
|
||||
DeclareOperation( "CanonicalCayleyTable", [ IsMatrix ] );
|
||||
DeclareOperation( "NormalizedQuasigroupTable", [ IsMatrix ] );
|
||||
|
||||
@ -52,7 +100,7 @@ DeclareOperation( "QuasigroupByCayleyTable", [ IsMatrix ] );
|
||||
DeclareOperation( "LoopByCayleyTable", [ IsMatrix ] );
|
||||
DeclareOperation( "SetQuasigroupElmName", [ IsQuasigroup, IsString ] );
|
||||
DeclareSynonym( "SetLoopElmName", SetQuasigroupElmName );
|
||||
DeclareOperation( "CanonicalCopy", [ IsQuasigroup ] );
|
||||
DeclareOperation( "CanonicalCopy", [ IsMagma ] );
|
||||
|
||||
#############################################################################
|
||||
## 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
|
||||
## integral entries.
|
||||
## Returns true if <ls> is an n by n matrix with n distinct
|
||||
## integral entries, each occurring exactly once in each row
|
||||
|
||||
InstallMethod( IsQuasigroupTable, "for matrix",
|
||||
InstallMethod( IsLeftQuasigroupTable, "for matrix",
|
||||
[ IsMatrix ],
|
||||
function( ls )
|
||||
local first_row;
|
||||
@ -27,14 +27,21 @@ function( 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;
|
||||
# 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;
|
||||
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 )
|
||||
@ -51,6 +58,36 @@ function( ls )
|
||||
and ls[ 1 ] = List( [1..Length(ls)], i -> ls[ i ][ 1 ] );
|
||||
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 )
|
||||
@ -71,13 +108,15 @@ function( ls )
|
||||
for i in [1..n] do for j in [1..n] do
|
||||
AddSet( entries, ls[ i ][ j ] );
|
||||
od; 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 );
|
||||
end
|
||||
|
||||
#############################################################################
|
||||
##
|
||||
@ -94,7 +133,7 @@ function( ls )
|
||||
Error( "LOOPS: <1> must be a latin square." );
|
||||
fi;
|
||||
# renaming the entries to be 1, ..., n
|
||||
T := CanonicalCayleyTable( ls );
|
||||
T := CanonicalCayleyTableOfLeftQuasigroupTable( ls );
|
||||
# permuting the columns so that the first row reads 1, ..., n
|
||||
perm := PermList( T[ 1 ] );
|
||||
T := List( T, row -> Permuted( row, perm ) );
|
||||
@ -136,7 +175,7 @@ function( ct )
|
||||
Error( "LOOPS: <1> must be a latin square." );
|
||||
fi;
|
||||
# Making sure that entries are 1, ..., n
|
||||
ct := CanonicalCayleyTable( ct );
|
||||
ct := CanonicalCayleyTableOfLeftQuasigroupTable( ct );
|
||||
# constructing the family
|
||||
F := NewFamily( "QuasigroupByCayleyTableFam", IsQuasigroupElement );
|
||||
# installing data for the family
|
||||
@ -173,7 +212,7 @@ function( ct )
|
||||
fi;
|
||||
# Making sure that the entries are 1, ..., n.
|
||||
# The table will remain normalized.
|
||||
ct := CanonicalCayleyTable( ct );
|
||||
ct := CanonicalCayleyTableOfLeftQuasigroupTable( ct );
|
||||
# constructing the family
|
||||
F := NewFamily( "LoopByCayleyTableFam", IsLoopElement );
|
||||
# installing the data for the family
|
||||
@ -695,27 +734,30 @@ function( list, dummy )
|
||||
return quasigroup_list[ 1 ];
|
||||
fi;
|
||||
# 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
|
||||
quasigroup_list[ s ] := QuasigroupByCayleyTable( CanonicalCayleyTable( CayleyTable( quasigroup_list[ s ] ) ) );
|
||||
quasigroup_list[ s ] :=
|
||||
CanonicalCayleyTableOfLeftQuasigroupTable(
|
||||
CayleyTable( quasigroup_list[ s ] ) );
|
||||
od;
|
||||
# At this point the entries in quasigroup_list are really just tables
|
||||
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 ] );
|
||||
nL := Length( quasigroup_list[ 1 ] );
|
||||
nM := Length( quasigroup_list[ s ] );
|
||||
TL := quasigroup_list[ 1 ];
|
||||
TM := 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 );
|
||||
quasigroup_list[ 1 ] := T;
|
||||
od;
|
||||
if are_all_loops then
|
||||
return IntoLoop( quasigroup_list[1] );
|
||||
return LoopByCayleyTable( quasigroup_list[1] );
|
||||
fi;
|
||||
return quasigroup_list[ 1 ];
|
||||
return QuasigroupByCayleyTable( quasigroup_list[1] );
|
||||
end );
|
||||
|
||||
#############################################################################
|
||||
|
Loading…
Reference in New Issue
Block a user