#############################################################################
##
#W  quasigroups.gd  Representing, creating and displaying quasigroups [loops]
##
#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                        P. Vojtechovsky (University of Denver, USA)
##

#############################################################################
##  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
DeclareSynonym( "IsQuasigroupElement",
                IsMultiplicativeElement and 
                IsLeftQuotientElement and IsRightQuotientElement );
DeclareRepresentation( "IsQuasigroupElmRep",
    IsPositionalObjectRep and IsMultiplicativeElement, [1] );

## element of a loop
DeclareSynonym( "IsLoopElement",
    IsQuasigroupElement and IsMultiplicativeElementWithInverse );
DeclareRepresentation( "IsLoopElmRep",
    IsPositionalObjectRep and IsMultiplicativeElementWithInverse, [1] );

## Right quasigroup
DeclareCategory("IsRightQuasigroup", 
                IsMagma and IsRightQuotientElementCollection);

## Left quasigroup
DeclareCategory("IsLeftQuasigroup",
                IsMagma and IsLeftQuotientElementCollection);

## quasigroup
DeclareSynonym( "IsQuasigroup", IsRightQuasigroup and IsLeftQuasigroup );

## loop
DeclareSynonym( "IsLoop", IsQuasigroup and IsMagmaWithOne and 
                          IsMultiplicativeElementWithInverseCollection);

#############################################################################
##  TESTING MULTIPLICATION TABLES
##  -------------------------------------------------------------------------

DeclareProperty( "IsLeftQuasigroupTable", IsMatrix );
DeclareProperty( "IsRightQuasigroupTable", IsMatrix );
DeclareSynonym( "IsQuasigroupTable", 
                IsLeftQuasigroupTable and IsRightQuasigroupTable );
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" );
