Merge branch 'Loops3.4.0'

Incorporate the changes from 3.3.0 to 3.4.0 of LOOPS into this
development. These were mostly straightforward. The only conflicts were
in quasigroups.gd, in which all of the changes from this development
were selected, as "IsLatin" had already been removed.
This commit is contained in:
Glen Whitney 2017-10-30 00:33:44 -04:00
commit 91ba2744c1
63 changed files with 20298 additions and 29245 deletions

View file

@ -2,7 +2,7 @@
##
#A banner.g loops G. P. Nagy / P. Vojtechovsky
##
#H @(#)$Id: banner.g, v 3.3.0 2016/09/21 gap Exp $
#H @(#)$Id: banner.g, v 3.4.0 2017/10/27 gap Exp $
##
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
#Y P. Vojtechovsky (University of Denver, USA)
@ -12,7 +12,7 @@ if not QUIET and BANNER then
Print(
" ______________________________________________________\n",
" LOOPS: Computing with quasigroups and loops in GAP \n",
" version 3.3.0 \n",
" version 3.4.0 \n",
" Gabor P. Nagy & Petr Vojtechovsky \n",
" nagyg@math.u-szeged.hu petr@math.du.edu \n",
" ------------------------------------------------------\n",

View file

@ -2,7 +2,7 @@
##
#W classes.gi Testing properties/varieties [loops]
##
#H @(#)$Id: classes.gi, v 3.3.0 2016/10/26 gap Exp $
#H @(#)$Id: classes.gi, v 3.4.0 2017/10/26 gap Exp $
##
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
#Y P. Vojtechovsky (University of Denver, USA)
@ -887,16 +887,14 @@ end);
InstallMethod( IsALoop, "for loop",
[ IsLoop ],
function( Q )
return IsLeftALoop(Q) and IsRightALoop(Q) and IsMiddleALoop(Q);
return IsRightALoop(Q) and IsMiddleALoop(Q);
# Theorem: rigth A-loop + middle A-loop implies left A-loop
end);
# implies
InstallTrueMethod( IsLeftALoop, IsALoop );
InstallTrueMethod( IsRightALoop, IsALoop );
InstallTrueMethod( IsMiddleALoop, IsALoop );
InstallTrueMethod( IsMiddleALoop, IsCommutative );
InstallTrueMethod( IsALoop, IsLeftALoop and IsCommutative );
InstallTrueMethod( IsALoop, IsRightALoop and IsCommutative );
InstallTrueMethod( IsLeftALoop, IsRightALoop and HasAntiautomorphicInverseProperty );
InstallTrueMethod( IsRightALoop, IsLeftALoop and HasAntiautomorphicInverseProperty );
InstallTrueMethod( IsFlexible, IsMiddleALoop );
@ -909,8 +907,12 @@ InstallTrueMethod( IsMoufangLoop, IsALoop and HasRightInverseProperty );
InstallTrueMethod( IsMoufangLoop, IsALoop and HasWeakInverseProperty );
# is implied by
InstallTrueMethod( IsMiddleALoop, IsCommutative );
InstallTrueMethod( IsLeftALoop, IsLeftBruckLoop );
InstallTrueMethod( IsLeftALoop, IsLCCLoop );
InstallTrueMethod( IsRightALoop, IsRightBruckLoop );
InstallTrueMethod( IsRightALoop, IsRCCLoop );
InstallTrueMethod( IsALoop, IsCommutative and IsMoufangLoop );
InstallTrueMethod( IsALoop, IsLeftALoop and IsMiddleALoop );
InstallTrueMethod( IsALoop, IsRightALoop and IsMiddleALoop );
InstallTrueMethod( IsALoop, IsAssociative );

View file

@ -2,7 +2,7 @@
##
#W examples.gd Examples [loops]
##
#H @(#)$Id: examples.gd, v 3.1.0 2015/09/23 gap Exp $
#H @(#)$Id: examples.gd, v 3.4.0 2015/09/23 gap Exp $
##
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
#Y P. Vojtechovsky (University of Denver, USA)
@ -36,6 +36,8 @@ DeclareGlobalFunction( "SmallLoop" );
DeclareGlobalFunction( "InterestingLoop" );
DeclareGlobalFunction( "NilpotentLoop" );
DeclareGlobalFunction( "AutomorphicLoop" );
DeclareGlobalFunction( "LeftBruckLoop" );
DeclareGlobalFunction( "RightBruckLoop" );
# up to isotopism
@ -52,3 +54,4 @@ DeclareGlobalFunction( "LOOPS_ActivateRCCLoop" );
DeclareGlobalFunction( "LOOPS_ActivateCCLoop" );
DeclareGlobalFunction( "LOOPS_ActivateNilpotentLoop" );
DeclareGlobalFunction( "LOOPS_ActivateAutomorphicLoop" );
DeclareGlobalFunction( "LOOPS_ActivateRightBruckLoop" );

View file

@ -2,7 +2,7 @@
##
#W examples.gi Examples [loops]
##
#H @(#)$Id: examples.gi, v 3.3.0 2016/10/19 gap Exp $
#H @(#)$Id: examples.gi, v 3.4.0 2017/10/23 gap Exp $
##
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
#Y P. Vojtechovsky (University of Denver, USA)
@ -32,6 +32,7 @@ ReadPackage("loops", "data/small.tbl"); # small loops
ReadPackage("loops", "data/interesting.tbl"); # interesting loops
ReadPackage("loops", "data/nilpotent.tbl"); # nilpotent loops
ReadPackage("loops", "data/automorphic.tbl"); # automorphic loops
ReadPackage("loops", "data/rightbruck.tbl"); # right Bruck loops
# up to isotopism
ReadPackage("loops", "data/itp_small.tbl"); # small loops up to isotopism
@ -60,6 +61,7 @@ function( name )
elif name = "interesting" then return LOOPS_interesting_data;
elif name = "nilpotent" then return LOOPS_nilpotent_data;
elif name = "automorphic" then return LOOPS_automorphic_data;
elif name = "right Bruck" then return LOOPS_right_bruck_data;
#up to isotopism
elif name = "itp small" then return LOOPS_itp_small_data;
fi;
@ -74,11 +76,8 @@ end);
InstallGlobalFunction( DisplayLibraryInfo, function( name )
local s, lib, k;
# up to isomorphism
if name = "left Bol" then
s := "The library contains all nonassociative left Bol loops of order less than 17\nand all nonassociative left Bol loops of order p*q, where p>q>2 are primes.";
elif name = "right Bol" then
s := "The library contains all nonassociative right Bol loops of order less than 17\nand all nonassociative left Bol loops of order p*q, where p>q>2 are primes.";
name := "left Bol"; # using dual data
if name = "left Bol" or name = "right Bol" then
s := Concatenation( "The library contains all nonassociative ", name, " loops of order less than 17\nand all nonassociative ", name, " loops of order p*q, where p>q>2 are primes." );
elif name = "Moufang" then
s := "The library contains all nonassociative Moufang loops \nof order less than 65, and all nonassociative Moufang \nloops of order 81 and 243.";
elif name = "Paige" then
@ -88,12 +87,9 @@ InstallGlobalFunction( DisplayLibraryInfo, function( name )
elif name = "Steiner" then
s := "The library contains all nonassociative Steiner loops \nof order less or equal to 16. It also contains the \nassociative Steiner loops of order 4 and 8.";
elif name = "CC" then
s := "The library contains all nonassociative CC loops of order less than 28 \nand all nonassociative CC loops of order p^2 and 2*p for any odd prime p.";
elif name = "RCC" then
s := "The library contains all nonassociative RCC loops of order less than 28.";
elif name = "LCC" then
s := "The library contains all nonassociative LCC loops of order less than 28.";
name := "RCC"; # using dual data
s := "The library contains all CC loops of order\n2<=2^k<=64, 3<=3^k<=81, 5<=5^k<=125, 7<=7^k<=343,\nall nonassociative CC loops of order less than 28,\nand all nonassociative CC loops of order p^2 and 2*p for any odd prime p.";
elif name = "RCC" or name = "LCC" then
s := Concatenation( "The library contains all nonassociative ", name, " loops of order less than 28." );
elif name = "small" then
s := "The library contains all nonassociative loops of order less than 7.";
elif name = "interesting" then
@ -103,23 +99,27 @@ InstallGlobalFunction( DisplayLibraryInfo, function( name )
elif name = "automorphic" then
s := "The library contains:\n";
s := Concatenation(s," - all nonassociative automorphic loops of order less than 16,\n");
s := Concatenation(s," - all commutative automorphic loops of order 3, 9, 27, 81,\n");
s := Concatenation(s," - all commutative automorphic loops of order 243 that are central\n");
s := Concatenation(s," extensions of Z_3 by F, where F is not the elem. ab. 3-group.\n");
s := Concatenation(s,"Note: Abelian groups are included among the commutative loops.");
s := Concatenation(s," - all commutative automorphic loops of order 3, 9, 27, 81.");
elif name = "left Bruck" or name = "right Bruck" then
s := Concatenation( "The library contains all ", name, " loops of orders 3, 9, 27 and 81." );
# up to isotopism
elif name = "itp small" then
s := "The library contains all nonassociative loops of order less than 7 up to isotopism.";
else
Info( InfoWarning, 1, Concatenation(
"The admissible names for loop libraries are: \n",
"[ \"left Bol\", \"right Bol\", \"Moufang\", \"Paige\", \"code\", \"Steiner\", \"CC\", \"RCC\", \"LCC\", \"small\", \"itp small\", \"interesting\", \"nilpotent\", \"automorphic\" ]."
"\"automorphic\", \"CC\", \"code\", \"interesting\", \"itp small\", \"LCC\", \"left Bol\", \"left Bruck\", \"Moufang\", \"nilpotent\", \"Paige\", \"right Bol\", \"right Bruck\", \"RCC\", \"small\", \"Steiner\"."
) );
return fail;
fi;
s := Concatenation( s, "\n------\nExtent of the library:" );
# renaming for data access
if name = "right Bol" then name := "left Bol"; fi;
if name = "LCC" then name := "RCC"; fi;
if name = "left Bruck" then name := "right Bruck"; fi;
lib := LOOPS_LibraryByName( name );
for k in [1..Length( lib[ 1 ] ) ] do
if lib[ 2 ][ k ] = 1 then
@ -128,12 +128,12 @@ InstallGlobalFunction( DisplayLibraryInfo, function( name )
s := Concatenation( s, "\n ", String( lib[ 2 ][ k ] ), " loops of order ", String( lib[ 1 ][ k ] ) );
fi;
od;
if name = "left Bol" or name = "right Bol" then
if name = "left Bol" then
s := Concatenation( s, "\n (p-q)/2 loops of order p*q for primes p>q>2 such that q divides p-1");
s := Concatenation( s, "\n (p-q+2)/2 loops of order p*q for primes p>q>2 such that q divides p+1" );
fi;
if name = "CC" then
s := Concatenation( s, "\n 3 loops of order p^2 for every odd prime p,\n 1 loop of order 2*p for every odd prime p" );
s := Concatenation( s, "\n 3 loops of order p^2 for every prime p>7,\n 1 loop of order 2*p for every odd prime p" );
fi;
s := Concatenation( s, "\n" );
Print( s );
@ -436,7 +436,48 @@ end);
InstallGlobalFunction( LOOPS_ActivateCCLoop,
function( n, pos_n, m, case )
local T, x, y, k, a, b, p;
local powers, p, i, k, F, basis, coords, coc, T, a, b, x, y;
powers := [ ,[4,8,16,32,64],[9,27,81],,[25,125],,[49,343]];
if n in Union( powers ) then # use cocycles
# determine p and position of n in database
p := Filtered([2,3,5,7], x -> n in powers[x])[1];
pos_n := Position( powers[p], n );
if not IsBound( LOOPS_cc_cocycles[p] ) then
# data not read yet, activate once
ReadPackage( "loops", Concatenation( "data/cc/cc_cocycles_", String(p), ".tbl" ) );
# decode cocycles and separate coordinates from a long string
for i in [1..Length(powers[p])] do
LOOPS_cc_cocycles[ p ][ i ] := List( LOOPS_cc_cocycles[ p ][ i ],
c -> LOOPS_DecodeCocycle( [ p^i, c[1], c[2] ], [0..p-1] )
);
LOOPS_cc_coordinates[ p ][ i ] := List( LOOPS_cc_coordinates[ p ][ i ],
c -> SplitString( c, " " )
);
od;
fi;
# data is now read
# determine position of loop in the database
k := 1;
while m > Length( LOOPS_cc_coordinates[ p ][ pos_n ][ k ] ) do
m := m - Length( LOOPS_cc_coordinates[ p ][ pos_n ][ k ] );
k := k + 1;
od;
# factor loop
F := CCLoop( n/p, LOOPS_cc_used_factors[ p ][ pos_n ][ k ] );
# basis
basis := List( LOOPS_cc_bases[ p ][ pos_n ][ k ],
i -> LOOPS_cc_cocycles[ p ][ pos_n ][ i ]
);
# coordinates
coords := LOOPS_cc_coordinates[ p ][ pos_n ][ k ][ m ];
coords := LOOPS_ConvertBase( coords, 91, p, Length( basis ) );
coords := List( coords, LOOPS_CharToDigit );
# cocycle
coc := (coords*basis) mod p;
coc := List( coc, i -> i+1 );
# return extension of Z_p by F using cocycle and trivial action
return LoopByExtension( CCLoop(p,1), F, List([1..n/p], i -> () ), coc );
fi;
if case=false then # use library of RCC loops, must recalculate pos_n
return LOOPS_ActivateRCCLoop( n, Position(LOOPS_rcc_data[ 1 ], n), LOOPS_cc_data[ 3 ][ pos_n ][ m ] );
@ -543,39 +584,52 @@ end);
InstallGlobalFunction( LOOPS_ActivateAutomorphicLoop,
function( n, m )
local i, pos_n, factor_id, F, dim, coords, basis, coc;
if IsEmpty( LOOPS_automorphic_cocycles ) then # only read on demand
ReadPackage( "loops", "data/automorphic/automorphic_cocycles.tbl");
# decode cocycles
for i in [1..3] do
LOOPS_automorphic_cocycles[ i ] := List( LOOPS_automorphic_cocycles[ i ],
c -> LOOPS_DecodeCocycle( [ 3^(i+2), true, c ], [0,1,2] )
);
od;
# separate coordinates (from a long string )
for i in [1..3] do
LOOPS_automorphic_coordinates[ i ] := SplitString( LOOPS_automorphic_coordinates[ i ], " " );
od;
fi;
# returns the associated Gamma loop (which here always happens to be automorphic)
# improve later
local P, L, s, Ls, ct, i, j, pos, f;
P := LeftBruckLoop( n, m );
L := LeftMultiplicationGroup( P );;
s := List(Elements(L), x -> x^2 );;
Ls := List([1..n], i -> LeftTranslation( P, Elements(P)[i] ) );;
ct := List([1..n],i->0*[1..n]);;
for i in [1..n] do for j in [1..n] do
pos := Position( s, Ls[i]*Ls[j]*Ls[i]^(-1)*Ls[j]^(-1) );
f := Elements(L)[pos];
ct[i][j] := 1^(f*Ls[j]*Ls[i]);
od; od;
return LoopByCayleyTable(ct);
end);
#############################################################################
##
#F LOOPS_ActivateRightBruckLoop( n, m )
##
## Activates a right Bruck loop from the library.
InstallGlobalFunction( LOOPS_ActivateRightBruckLoop,
function( n, m )
local pos_n, factor_id, F, basis, coords, coc;
# factor loop
pos_n := Position( [27,81,243], n );
factor_id := LOOPS_CharToDigit( LOOPS_automorphic_coordinates[ pos_n ][ m ][ 1 ] );
F := AutomorphicLoop( n/3, factor_id );
pos_n := Position( [27,81], n );
factor_id := LOOPS_CharToDigit( LOOPS_right_bruck_coordinates[ pos_n ][ m ][ 1 ] );
F := RightBruckLoop( n/3, factor_id );
# basis (only decode cocycles at first usage)
if IsString( LOOPS_right_bruck_cocycles[ pos_n ][ 1 ][ 3 ] ) then # not converted yet
LOOPS_right_bruck_cocycles[ pos_n ] := List( LOOPS_right_bruck_cocycles[ pos_n ],
coc -> LOOPS_DecodeCocycle( coc, [0,1,2] )
);
fi;
basis := LOOPS_right_bruck_cocycles[ pos_n ];
# coordinates determining the cocycle
dim := Length( LOOPS_automorphic_bases[ pos_n ][ factor_id ] );
coords := LOOPS_automorphic_coordinates[ pos_n ][ m ];
coords := LOOPS_right_bruck_coordinates[ pos_n ][ m ];
coords := coords{[2..Length(coords)]}; # remove the character that determines factor id
coords := LOOPS_ConvertBase( coords, 91, 3, dim );
coords := LOOPS_ConvertBase( coords, 91, 3, Length( basis ) );
coords := List( coords, LOOPS_CharToDigit );
# basis
basis := List( LOOPS_automorphic_bases[ pos_n ][ factor_id ],
i -> LOOPS_automorphic_cocycles[ pos_n ][ i ]
);
# calculate cocycle
coc := (coords*basis) mod 3;
coc := List( coc, i -> i+1 );
coc := coc + 1;
# return extension of Z_3 by F using cocycle and trivial action
return LoopByExtension( AutomorphicLoop(3,1), F, List([1..n/3], i -> () ), coc );
return LoopByExtension( RightBruckLoop(3,1), F, List([1..n/3], i -> () ), coc );
end);
#############################################################################
@ -593,13 +647,7 @@ InstallGlobalFunction( LibraryLoop, function( name, n, m )
local lib, implemented_orders, NOL, loop, pos_n, p, q, divs, PG, m_inv, root, half, case, g, h;
# selecting data library
if name = "right Bol" then # using dual data
lib := LOOPS_LibraryByName( "left Bol" );
elif name = "LCC" then # using dual data
lib := LOOPS_LibraryByName( "RCC" );
else
lib := LOOPS_LibraryByName( name );
fi;
lib := LOOPS_LibraryByName( name );
# extent of the library
implemented_orders := lib[ 1 ];
@ -614,7 +662,7 @@ InstallGlobalFunction( LibraryLoop, function( name, n, m )
# parameters for handling systematic cases, such as CCLoop( p^2, 1 )
pos_n := fail;
case := false;
if name="left Bol" or name="right Bol" then
if name="left Bol" then
divs := DivisorsInt( n );
if Length( divs ) = 4 and not IsInt( divs[3]/divs[2] ) then # case n = p*q
q := divs[ 2 ];
@ -633,13 +681,13 @@ InstallGlobalFunction( LibraryLoop, function( name, n, m )
fi;
if name="CC" then
divs := DivisorsInt( n );
if Length( divs ) = 3 then # case p^2
if Length( divs ) = 3 and divs[ 2 ] > 7 then # case p^2, p>7
p := divs[ 2 ];
case := [p,"p^2"];
if not m in [1..3] then
Error("LOOPS: There are only 3 nonassociative CC-loops of order p^2 for an odd prime p.");
fi;
elif Length( divs ) = 4 and not IsInt( divs[3]/divs[2] ) then # p*q
elif Length( divs ) = 4 and not IsInt( divs[3]/divs[2] ) and not n=21 then # p*q
p := divs[ 3 ];
case := [p,"2*p"];
if not divs[2] = 2 then
@ -670,9 +718,6 @@ InstallGlobalFunction( LibraryLoop, function( name, n, m )
if name = "left Bol" then
loop := LOOPS_ActivateLeftBolLoop( pos_n, m, case );
SetIsLeftBolLoop( loop, true );
elif name = "right Bol" then
loop := OppositeLoop( LOOPS_ActivateLeftBolLoop( pos_n, m, case ) );
SetIsRightBolLoop( loop, true );
elif name = "Moufang" then
# renaming loops so that they agree with Goodaire's classification
PG := List([1..243], i->());
@ -701,14 +746,15 @@ InstallGlobalFunction( LibraryLoop, function( name, n, m )
loop := LOOPS_ActivateSteinerLoop( n, pos_n, m );
SetIsSteinerLoop( loop, true );
elif name = "CC" then
loop := LOOPS_ActivateCCLoop( n, pos_n, m, case );
if n in [2,3,5,7] then # use Cayley table for canonical cyclic group
loop := LoopByCayleyTable( LOOPS_DecodeCayleyTable( lib[ 3 ][ pos_n ][ m ] ) );
else
loop := LOOPS_ActivateCCLoop( n, pos_n, m, case );
fi;
SetIsCCLoop( loop, true );
elif name = "RCC" then
loop := LOOPS_ActivateRCCLoop( n, pos_n, m );
SetIsRCCLoop( loop, true );
elif name = "LCC" then
loop := OppositeLoop( LOOPS_ActivateRCCLoop( n, pos_n, m ) );
SetIsLCCLoop( loop, true );
elif name = "small" then
loop := LoopByCayleyTable( LOOPS_DecodeCayleyTable( lib[ 3 ][ pos_n ][ m ] ) );
elif name = "interesting" then
@ -725,12 +771,19 @@ InstallGlobalFunction( LibraryLoop, function( name, n, m )
elif name = "nilpotent" then
loop := LOOPS_ActivateNilpotentLoop( lib[ 3 ][ pos_n ][ m ] );
elif name = "automorphic" then
if not n in [27,81,243] then # use Cayley table
if not n in [3, 9, 27, 81] then # use Cayley table
loop := LoopByCayleyTable( LOOPS_DecodeCayleyTable( lib[ 3 ][ pos_n ][ m ] ) );
else # use cocycles
loop := LOOPS_ActivateAutomorphicLoop( n, m );
else # use associated left Bruck loop
loop := LOOPS_ActivateAutomorphicLoop( n, m );
fi;
SetIsAutomorphicLoop( loop, true );
elif name = "right Bruck" then
if not n in [27,81] then # use Cayley table
loop := LoopByCayleyTable( LOOPS_DecodeCayleyTable( lib[ 3 ][ pos_n ][ m ] ) );
else # use cocycles
loop := LOOPS_ActivateRightBruckLoop( n, m );
fi;
SetIsRightBruckLoop( loop, true );
# up to isotopism
elif name = "itp small" then
return LibraryLoop( "small", n, lib[ 3 ][ pos_n ][ m ] );
@ -762,6 +815,8 @@ end);
#F InterestingLoop( n, m )
#F NilpotentLoop( n, m )
#F AutomorphicLoop( n, m )
#F LeftBruckLoop( n, m )
#F RightBruckLoop( n, m )
#F ItpSmallLoop( n, m )
##
@ -770,7 +825,11 @@ InstallGlobalFunction( LeftBolLoop, function( n, m )
end);
InstallGlobalFunction( RightBolLoop, function( n, m )
return LibraryLoop( "right Bol", n, m );
local loop;
loop := Opposite( LeftBolLoop( n, m ) );
SetIsRightBolLoop( loop, true );
SetName( loop, Concatenation( "<right Bol loop ", String( n ), "/", String( m ), ">" ) );
return loop;
end);
InstallGlobalFunction( MoufangLoop, function( n, m )
@ -808,11 +867,15 @@ InstallGlobalFunction( RightConjugacyClosedLoop, function( n, m )
end);
InstallGlobalFunction( LCCLoop, function( n, m )
return LibraryLoop( "LCC", n, m );
local loop;
loop := Opposite( RCCLoop( n, m ) );
SetIsLCCLoop( loop, true );
SetName( loop, Concatenation( "<LCC loop ", String( n ), "/", String( m ), ">" ) );
return loop;
end);
InstallGlobalFunction( LeftConjugacyClosedLoop, function( n, m )
return LibraryLoop( "LCC", n, m );
return LCCLoop( n, m );
end);
InstallGlobalFunction( SmallLoop, function( n, m )
@ -831,6 +894,18 @@ InstallGlobalFunction( AutomorphicLoop, function( n, m )
return LibraryLoop( "automorphic", n, m );
end);
InstallGlobalFunction( RightBruckLoop, function( n, m )
return LibraryLoop( "right Bruck", n, m );
end);
InstallGlobalFunction( LeftBruckLoop, function( n, m )
local loop;
loop := Opposite( RightBruckLoop( n, m ) );
SetIsLeftBruckLoop( loop, true );
SetName( loop, Concatenation( "<left Bruck loop ", String( n ), "/", String( m ), ">" ) );
return loop;
end);
InstallGlobalFunction( ItpSmallLoop, function( n, m )
return LibraryLoop( "itp small", n, m );
end);

View file

@ -2,7 +2,7 @@
##
#W iso.gd Isomorphisms and isotopisms [loops]
##
#H @(#)$Id: iso.gd, v 3.2.0 2015/06/12 gap Exp $
#H @(#)$Id: iso.gd, v 3.4.0 2016/12/13 gap Exp $
##
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
#Y P. Vojtechovsky (University of Denver, USA)
@ -23,6 +23,8 @@ DeclareOperation( "IsomorphismQuasigroups", [ IsQuasigroup, IsQuasigroup ] );
DeclareOperation( "IsomorphismLoops", [ IsLoop, IsLoop ] );
DeclareOperation( "QuasigroupsUpToIsomorphism", [ IsList ] );
DeclareOperation( "LoopsUpToIsomorphism", [ IsList ] );
DeclareOperation( "QuasigroupIsomorph", [ IsQuasigroup, IsPerm ] );
DeclareOperation( "LoopIsomorph", [ IsLoop, IsPerm ] );
DeclareOperation( "IsomorphicCopyByPerm", [ IsQuasigroup, IsPerm ] );
DeclareOperation( "IsomorphicCopyByNormalSubloop", [ IsLoop, IsLoop ] );

View file

@ -2,7 +2,7 @@
##
#W iso.gi Isomorphisms and isotopisms [loops]
##
#H @(#)$Id: iso.gi, v 3.3.0 2016/10/26 gap Exp $
#H @(#)$Id: iso.gi, v 3.4.0 2017/08/24 gap Exp $
##
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
#Y P. Vojtechovsky (University of Denver, USA)
@ -466,30 +466,54 @@ end);
#############################################################################
##
#O IsomorphicCopyByPerm( Q, p )
#O QuasigroupIsomorph( Q, p )
##
## If <Q> is a quasigroup of order n and <p> a permutation of [1..n], returns
## the quasigroup (Q,*) such that p(xy) = p(x)*p(y).
## If <Q> is a loop, p is first composed with (1,1^p) to make sure
## that the neutral element of (Q,*) remains 1.
InstallMethod( IsomorphicCopyByPerm, "for a quasigroup and permutation",
InstallMethod( QuasigroupIsomorph, "for a quasigroup and permutation",
[ IsQuasigroup, IsPerm ],
function( Q, p )
local ctQ, ct, inv_p;
ctQ := CanonicalCayleyTable( CayleyTable( Q ) );
# if Q is a loop and 1^p > 1, must normalize
if (IsLoop( Q ) and (not 1^p = 1)) then
p := p * (1, 1^p );
fi;
inv_p := Inverse( p );
ct := List([1..Size(Q)], i-> List([1..Size(Q)], j ->
( ctQ[ i^inv_p ][ j^inv_p ] )^p
) );
if IsLoop( Q ) then return LoopByCayleyTable( ct ); fi;
return QuasigroupByCayleyTable( ct );
end);
#############################################################################
##
#O LoopIsomorph( Q, p )
##
## If <Q> is a loop of order n and <p> a permutation of [1..n] such that
## p(1)=1, returns the loop (Q,*) such that p(xy)=p(x)*p(y).
## If p(1)=c<>1, then the quasigroup (Q,*) is converted into loop
## via the isomorphism (1,c).
InstallMethod( LoopIsomorph, "for a loop and permutation",
[ IsLoop, IsPerm ],
function( Q, p )
return IntoLoop( QuasigroupIsomorph( Q, p ) );
end);
#############################################################################
##
#O IsomorphicCopyByPerm( Q, p )
##
## Calls LoopIsomorph( Q, p ) if <Q> is a loop,
## else QuasigroupIsotope( Q, p ).
InstallMethod( IsomorphicCopyByPerm, "for a quasigroup and permutation",
[ IsQuasigroup, IsPerm ],
function( Q, p )
if IsLoop( Q ) then
return LoopIsomorph( Q, p );
fi;
return QuasigroupIsomorph( Q, p );
end);
#############################################################################
##
#O IsomorphicCopyByNormalSubloop( L, S )
@ -594,15 +618,13 @@ end);
##
## If L1, L2 are isotopic loops, returns true, else fail.
# (MATH) First we calculate all principal loop isotopes of L1 of the form
# PrincipalLoopIsotope(L1, f, g), where f, g, are elements of L1.
# Then we filter these up to isomorphism. If L2 is isotopic to L1, then
# L2 is isomorphic to one of these principal isotopes.
# (MATH) We check for isomorphism of L2 against all principal
# isotopes of L1.
InstallMethod( IsotopismLoops, "for two loops",
[ IsLoop, IsLoop ],
function( L1, L2 )
local istps, fg, f, g, L, phi, pos, alpha, beta, gamma, p;
local f, g, L, phi, alpha, beta, gamma, p;
# make all loops canonical to be able to calculate isotopisms
if not L1 = Parent( L1 ) then L1 := LoopByCayleyTable( CayleyTable( L1 ) ); fi;
@ -619,20 +641,11 @@ function( L1, L2 )
if not Size(InnerMappingGroup(L1)) = Size(InnerMappingGroup(L2)) then return fail; fi;
# now trying to construct an isotopism
istps := [];
fg := [];
for f in L1 do for g in L1 do
Add(istps, PrincipalLoopIsotope( L1, f, g ));
Add(fg, [ f, g ] );
od; od;
for L in LoopsUpToIsomorphism( istps ) do
L := PrincipalLoopIsotope( L1, f, g );
phi := IsomorphismLoops( L, L2 );
if not phi = fail then
# must reconstruct the isotopism (alpha, beta, gamma)
# first figure out what f and g were
pos := Position( istps, L );
f := fg[ pos ][ 1 ];
g := fg[ pos ][ 2 ];
alpha := RightTranslation( L1, g );
beta := LeftTranslation( L1, f );
# we also applied an isomorphism (1,f*g) inside PrincipalLoopIsotope
@ -649,7 +662,7 @@ function( L1, L2 )
gamma := gamma * phi;
return [ alpha, beta, gamma ];
fi;
od;
od; od;
return fail;
end);

View file

@ -2,7 +2,7 @@
##
#W memory.gi Memory management [loops]
##
#H @(#)$Id: memory.gi, v 3.3.0 2016/10/20 gap Exp $
#H @(#)$Id: memory.gi, v 3.4.0 2016/11/4 gap Exp $
##
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
#Y P. Vojtechovsky (University of Denver, USA)
@ -21,9 +21,14 @@ InstallGlobalFunction( LOOPS_FreeMemory, function( )
LOOPS_rcc_transitive_groups := [];
LOOPS_rcc_sections := List( [1..Length(LOOPS_rcc_data[1])], i-> [] );
LOOPS_rcc_conjugacy_classes := [ [], [] ];
# automorphic loops
LOOPS_automorphic_cocycles := [];
LOOPS_automorphic_coordinates := [];
# cc loops
LOOPS_cc_used_factors := [];
LOOPS_cc_cocycles := [];
LOOPS_cc_bases := [];
LOOPS_cc_coordinates := [];
# right Bruck loops
LOOPS_right_bruck_cocycles := [];
LOOPS_right_bruck_coordinates := [];
GASMAN("collect");
return GasmanStatistics().full.deadkb;
end);

View file

@ -1,151 +1,146 @@
#############################################################################
##
#W quasigroups.gd Representing, creating and displaying quasigroups [loops]
##
#H @(#)$Id: quasigroups.gd, v 3.2.0 2016/05/02 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" );
#############################################################################
##
#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] );
## latin (auxiliary category for GAP to tell apart IsMagma and IsQuasigroup)
DeclareCategory( "IsLatinMagma", IsObject );
## quasigroup
DeclareCategory( "IsQuasigroup", IsMagma and IsLatinMagma );
## 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" );

View file

@ -893,32 +893,34 @@ end );
InstallMethod( ViewObj, "for loop",
[ IsLoop ],
function( L )
if HasIsAssociative( L ) and IsAssociative( L ) then
Print( "<associative loop of order ", Size( L ), ">");
elif HasIsExtraLoop( L ) and IsExtraLoop( L ) then
Print( "<extra loop of order ", Size( L ), ">");
elif HasIsMoufangLoop( L ) and IsMoufangLoop( L ) then
Print( "<Moufang loop of order ", Size( L ), ">");
elif HasIsCLoop( L ) and IsCLoop( L ) then
Print( "<C loop of order ", Size( L ), ">");
elif HasIsLeftBolLoop( L ) and IsLeftBolLoop( L ) then
Print( "<left Bol loop of order ", Size( L ), ">");
elif HasIsRightBolLoop( L ) and IsRightBolLoop( L ) then
Print( "<right Bol loop of order ", Size( L ), ">");
elif HasIsLCLoop( L ) and IsLCLoop( L ) then
Print( "<LC loop of order ", Size( L ), ">");
elif HasIsRCLoop( L ) and IsRCLoop( L ) then
Print( "<RC loop of order ", Size( L ), ">");
local PrintMe;
PrintMe := function( name, L )
Print( "<", name, " loop of order ", Size( L ), ">");
end;
if HasIsAssociative( L ) and IsAssociative( L ) then PrintMe( "associative", L );
elif HasIsExtraLoop( L ) and IsExtraLoop( L ) then PrintMe( "extra", L );
elif HasIsMoufangLoop( L ) and IsMoufangLoop( L ) then PrintMe( "Moufang", L );
elif HasIsCLoop( L ) and IsCLoop( L ) then PrintMe( "C", L );
elif HasIsLeftBruckLoop( L ) and IsLeftBruckLoop( L ) then PrintMe( "left Bruck", L );
elif HasIsRightBruckLoop( L ) and IsRightBruckLoop( L ) then PrintMe( "right Bruck", L );
elif HasIsLeftBolLoop( L ) and IsLeftBolLoop( L ) then PrintMe( "left Bol", L );
elif HasIsRightBolLoop( L ) and IsRightBolLoop( L ) then PrintMe( "right Bol", L );
elif HasIsAutomorphicLoop( L ) and IsAutomorphicLoop( L ) then PrintMe( "automorphic", L );
elif HasIsLeftAutomorphicLoop( L ) and IsLeftAutomorphicLoop( L ) then PrintMe( "left automorphic", L );
elif HasIsRightAutomorphicLoop( L ) and IsRightAutomorphicLoop( L ) then PrintMe( "right automorphic", L );
elif HasIsLCLoop( L ) and IsLCLoop( L ) then PrintMe( "LC", L );
elif HasIsRCLoop( L ) and IsRCLoop( L ) then PrintMe( "RC", L );
elif HasIsLeftAlternative( L ) and IsLeftAlternative( L ) then
if HasIsRightAlternative( L ) and IsRightAlternative( L ) then
Print( "<alternative loop of order ", Size( L ), ">");
else
Print( "<left alternative loop of order ", Size( L ), ">");
PrintMe("alternative", L );
else
PrintMe("left alternative", L );
fi;
elif HasIsRightAlternative( L ) and IsRightAlternative( L ) then
Print( "<right alternative loop of order ", Size( L ), ">");
elif HasIsFlexible( L ) and IsFlexible( L ) then
Print( "<flexible loop of order ", Size( L ), ">");
elif HasIsRightAlternative( L ) and IsRightAlternative( L ) then PrintMe( "right alternative", L );
elif HasIsCommutative( L ) and IsCommutative( L ) then PrintMe( "commutative", L );
elif HasIsFlexible( L ) and IsFlexible( L ) then PrintMe( "flexible", L);
else
# MORE ??
Print( "<loop of order ", Size( L ), ">" );