loops/gap/examples.gi

912 lines
37 KiB
Plaintext

#############################################################################
##
#W examples.gi Examples [loops]
##
#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)
##
#############################################################################
## Binding global variable LOOPS_aux
##
## The variable is used for temporary storage throughout the package.
## We therefore do not want the variable to be read only.
LOOPS_aux := [];
#############################################################################
## READING DATA
## -------------------------------------------------------------------------
# up to isomorphism
ReadPackage("loops", "data/leftbol.tbl"); # left Bol loops
ReadPackage("loops", "data/moufang.tbl"); # Moufang loops
ReadPackage("loops", "data/paige.tbl"); # Paige loops
ReadPackage("loops", "data/code.tbl"); # code loops
ReadPackage("loops", "data/steiner.tbl"); # Steiner loops
ReadPackage("loops", "data/cc.tbl"); # CC loops
ReadPackage("loops", "data/rcc.tbl"); # RCC loops (more is read upon calling RCCLoop(n,m) for the first time
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
#############################################################################
## DISPLAYING INFORMATION ABOUT A LIBRARY
## -------------------------------------------------------------------------
#############################################################################
##
#F LOOPS_LibraryByName( name )
##
## Auxiliary. Returns the library corresponding to <name>.
InstallGlobalFunction( LOOPS_LibraryByName,
function( name )
#up to isomorphism
if name = "left Bol" then return LOOPS_left_bol_data;
elif name = "Moufang" then return LOOPS_moufang_data;
elif name = "Paige" then return LOOPS_paige_data;
elif name = "code" then return LOOPS_code_data;
elif name = "Steiner" then return LOOPS_steiner_data;
elif name = "CC" then return LOOPS_cc_data;
elif name = "RCC" then return LOOPS_rcc_data;
elif name = "small" then return LOOPS_small_data;
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;
end);
#############################################################################
##
#F DisplayLibraryInfo( name )
##
## Display information about library named <name>.
InstallGlobalFunction( DisplayLibraryInfo, function( name )
local s, lib, k;
# up to isomorphism
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
s := "The library contains the smallest nonassociative finite \nsimple Moufang loop.";
elif name = "code" then
s := "The library contains all nonassociative even code loops \nof order less than 65.";
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 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
s := "The library contains a few interesting loops.";
elif name = "nilpotent" then
s := "The library contains all nonassociative nilpotent loops \nof order less than 12.";
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.");
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",
"\"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
s := Concatenation( s, "\n ", String( lib[ 2 ][ k ] ), " loop of order ", String( lib[ 1 ][ k ] ) );
else
s := Concatenation( s, "\n ", String( lib[ 2 ][ k ] ), " loops of order ", String( lib[ 1 ][ k ] ) );
fi;
od;
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 prime p>7,\n 1 loop of order 2*p for every odd prime p" );
fi;
s := Concatenation( s, "\n" );
Print( s );
return true;
end);
#############################################################################
## AUXILIARY FUNCTIONS
## -------------------------------------------------------------------------
## When the data in the database is encoded in some way, we usually
## retrieve the loop via function LOOPS_ActivateXLoop, where X is the name
## of the class.
#############################################################################
##
#F LOOPS_SmallestNonsquare( p )
##
## Auxiliary function.
## Returns the smallest nonsquare modulo p.
InstallGlobalFunction( LOOPS_SmallestNonsquare,
function( p )
local squares, i;
squares := Set( [1..p-1], i->i^2 mod p );
for i in [2..p-1] do
if not i in squares then return i; fi;
od;
return fail; # will never happen if p>2 is prime
end);
#############################################################################
##
#F LOOPS_ActivateLeftBolLoopPQ( p, q, m )
##
## Auxiliary function for activating left Bol loop of order p*q.
## See paper by Kinyon, Nagy and Vojtechovsky.
## p>q>2 are primes such that q divides p^2-1, m is an integer in the range [1..(p-q)/2] or [1..(p-q+2)/2]
InstallGlobalFunction( LOOPS_ActivateLeftBolLoopPQ,
function( p, q, m )
local F, omega, lambda, ev, inv_ev, params, t, sqrt_t, final_params, alpha, theta, GFp, ct, i, j, k, l, u, v, w, x, y;
F := GF(p^2);
omega := PrimitiveRoot( F )^((p^2-1)/q);
lambda := omega + omega^(-1);
ev := List([0..q-1], j -> omega^j);
inv_ev := List([0..q-1], j -> omega^(-j));
if IsInt((p-1)/q) then
params := List([2..p-1], j->j*One(F)); # GF(p); 0 and 1 correspond to isomorphic nonabelian groups
params := Filtered( params, x -> not ((One(F) - x^(-1)) in ev) );
else # q divides p+1
t := LOOPS_SmallestNonsquare( p );
sqrt_t := RootsOfPolynomial( F, X(F,"x")^2 - t )[ 1 ]; # a squre root of t in GF(p^2)
params := List([0..p-1], j -> (1/2)*One(F) + j*One(F)*sqrt_t ); # 1/2 + GF(p)\sqrt{t}
params := Filtered( params, x -> not ((One(F) - x^(-1)) in ev) );
fi;
final_params := [];
for x in params do
if not ( (One(F)-x) in final_params ) then
Add( final_params, x );
fi;
od;
alpha := final_params[ m ];
theta := alpha*ev + (One(F)-alpha)*inv_ev;
theta := List( theta, x -> x^(-1) );
GFp := List([0..p-1], j -> j*One(F));
theta := List( theta, x -> Position( GFp, x )-1 );
# construct the Cayley table according to (a^i b^j)*(a^k b^l) = a^{i+k} b^{ w + (l+w)*theta[k]^{-1}*theta[i+k], where w+w*theta[i] = j
ct := List([1..p*q], i -> 0*[1..p*q]);
for i in [0..q-1] do for j in [0..p-1] do for k in [0..q-1] do for l in [0..p-1] do
u := (i+k) mod q;
w := ( j/(1+theta[i+1]) ) mod p;
v := ( w + (l+w)*theta[ ((i+k) mod q) + 1 ]/theta[k+1] ) mod p;
x := i*p+j+1;
y := k*p+l+1;
ct[x][y] := u*p+v+1;
od; od; od; od;
# return the loop
return LoopByCayleyTable( ct );
end);
#############################################################################
##
#F LOOPS_ActivateLeftBolLoop( pos_n, m, case )
##
## Auxiliary function for activating left Bol loops from the database.
## case = [p,q] if it is a left Bol loop of order p*q, with p>q>2 primes such that q divides p^2-1
## case = false otherwise
## pos_n is meaningless when case = [p,q]
InstallGlobalFunction( LOOPS_ActivateLeftBolLoop,
function( pos_n, m, case )
local rep_m, ct, perm;
if not case=false then # p*q
return LOOPS_ActivateLeftBolLoopPQ( case[1], case[2], m );
fi;
# in database
rep_m := m;
# searching for a Cayley table on which the loop is based
while not IsString( LOOPS_left_bol_data[ 3 ][ pos_n ][ rep_m ] ) do
rep_m := rep_m - 1;
od;
if rep_m = m then # loop given by encoded Cayley table
ct := LOOPS_DecodeCayleyTable( LOOPS_left_bol_data[ 3 ][ pos_n ][ m ] );
else # loop given as an isotope of another loop
ct := LOOPS_DecodeCayleyTable( LOOPS_left_bol_data[ 3 ][ pos_n ][ rep_m ] );
perm := PermList( ct[ LOOPS_left_bol_data[ 3 ][ pos_n ][ m ] ] );
ct := Set( List( ct, row -> OnTuples( row, perm^-1 ) ) );
fi;
return LoopByCayleyTable( ct );
end);
#############################################################################
##
#F LOOPS_ActivateMoufangLoop( n, pos_n, m )
##
## Auxiliary function for activating Moufang loops from the database.
InstallGlobalFunction( LOOPS_ActivateMoufangLoop,
function( n, pos_n, m )
local d, parent_m, parent, S, a, h, e, f, G, ret, x, row, y, b, c, z;
d := LOOPS_moufang_data[ 3 ][ pos_n ][ m ]; #data
# orders 81 and 243 are represented as central extensions
if n = 81 or n = 243 then
return LoopByExtension(
IntoLoop( SmallGroup( d[1], d[2] ) ), # K
IntoLoop( SmallGroup( d[3], d[4] ) ), # F
List([1..d[3]], i -> () ), # trivial action F -> Aut( K )
LOOPS_DecodeCocycle( [ n/d[1], false, d[5] ], [1..d[1]] ) # cocycle
);
fi;
# all other orders
if d[ 1 ] > 0 then # must activate parent first
# determine position of parent ( d[1] gives it relative to the class leader )
while LOOPS_moufang_data[ 3 ][ pos_n ][ m ][ 1 ] > 0 do
m := m - 1;
od;
m := m + d[ 1 ] - 1;
parent := LOOPS_ActivateMoufangLoop( n, pos_n, m );
if d[ 2 ] = "C" then #cyclic modification
S := List( d[ 3 ], i -> Elements( parent )[ i ] );
a := Elements( parent )[ d[ 4 ] ];
h := Elements( parent )[ d[ 5 ] ];
return LoopByCyclicModification( parent, S, a, h );
fi;
if d[ 2 ] = "D" then # dihedral modification
S := List( d[ 3 ], i -> Elements( parent )[ i ] );
e := Elements( parent )[ d[ 4 ] ];
f := Elements( parent )[ d[ 5 ] ];
h := Elements( parent )[ d[ 6 ] ];
return LoopByDihedralModification( parent, S, e, f, h );
fi;
fi;
# no parent;
if d[ 2 ]="G" then # loop of type MG2
G := AllGroups( d[ 3 ], IsCommutative, false)[ d[ 4 ] ]; #relies on GAP group libraries !!
return LoopMG2( G );
fi;
if d[ 2 ]="T" then # special loop (direct product of an old loop and a cyclic group)
parent := MoufangLoop( d[ 3 ][ 1 ], d[ 3 ][ 2 ]);
return DirectProduct( parent, CyclicGroup( d[ 3 ][ 3 ] ) );
fi;
end);
#############################################################################
##
#F LOOPS_ActivateSteinerLoop( n, pos_n, m )
##
## Auxiliary function activating Steiner loops from the database.
##
## The database LOOPS_steiner_data contains blocks of steiner triple systems.
## If the system is on k points, the poitns are labelled 0,...,k-1.
## The constructed Steiner loop has elements labelled 1,...,k+1=n
InstallGlobalFunction( LOOPS_ActivateSteinerLoop,
function( n, pos_n, m )
local d, blocks, i, T, i_in, ij_in, j, MyInt;
#############################################################################
##
#F MyInt( s )
##
## Auxiliary function.
## Given a digit or a lower case letter, returns the numerical value, where
## a = 10, f=15
MyInt := function( s )
return Position( "0123456789abcdef", s ) - 1;
end;
d := LOOPS_steiner_data[ 3 ][ pos_n ][ m ]; # data for the loop = three strings
# creating the blocks
blocks := [];
for i in [1..Length( d[ 1 ] )] do
Add( blocks, [ MyInt( d[1][i] ), MyInt( d[2][i] ), MyInt( d[3][i] ) ] );
od;
#creating the multiplication table
T := List( [1..n], i->[1..n] );
for i in [1..n] do T[i][1] := i; od;
for i in [0..n-2] do
i_in := Filtered( blocks, B->i in B);
for j in [0..n-2] do
if j=i then T[i+2][j+2] := 1; fi;
if not j=i then
ij_in := Filtered( i_in, B->j in B )[1]; #unique block;
T[i+2][j+2] := Difference( ij_in, [i,j])[1] + 2;
fi;
od;
od;
return LoopByCayleyTable( T );
end);
#############################################################################
##
#F LOOPS_ActivateRCCLoop( n, pos_n, m )
##
## Activates an RCC loop from the library.
## See manual for complete discussion concerning this library.
InstallGlobalFunction( LOOPS_ActivateRCCLoop,
function( n, pos_n, m )
local pos_m, g, nr_conj_classes, data, data2, next_compactified, x, i, rel_m, G, section, pos_conjugacy_classes;
if IsEmpty( LOOPS_rcc_transitive_groups ) then # data not read yet
ReadPackage( "loops", "data/rcc/rcc_transitive_groups.tbl" );
fi;
# determining the transitive group corresponding to pos_n, m
pos_m := Length( LOOPS_rcc_data[ 3 ][ pos_n ][ 1 ] ); # nr of transitive groups associated with order n
while LOOPS_rcc_data[ 3 ][ pos_n ][ 2 ][ pos_m ] > m do
pos_m := pos_m - 1;
od;
g := LOOPS_rcc_data[ 3 ][ pos_n ][ 1 ][ pos_m ]; # index of transitive group (of degree n) in GAP library
# activating data for the group, if needed
if not IsBound( LOOPS_rcc_sections[ pos_n ][ pos_m ] ) then
# data must be read from file and decoded
ReadPackage( "loops", Concatenation( "data/rcc/sections", String(n), ".", String(g), ".tbl" ) );
# variable LOOPS_aux is now read and ready to be processed
nr_conj_classes := Length( LOOPS_rcc_transitive_groups[ pos_n ][ pos_m ][ 2 ] );
data := SplitString( LOOPS_aux, " " );
data2 := [];
next_compactified := false;
for x in data do
if x="" then # the next entry is compactified, eg. "a$X" means "a", "$", "X"
next_compactified := true;
elif not next_compactified then
Add( data2, x );
else # compactified string
next_compactified := false;
for i in [1..Length(x)] do
Add( data2, x{[i..i]} ); # Add( data2, x[i] ) is not safe when data2 is empty
od;
fi;
od;
data := List( data2, x -> LOOPS_ConvertToDecimal( x, 91 ) );
# reconstructing the sequence from the difference sequence
for i in [2..Length( data )] do
data[ i ] := data[ i-1 ] - data[ i ];
od;
LOOPS_rcc_sections[ pos_n ][ pos_m ] := data;
fi;
# data is now loaded
G := TransitiveGroup(n, g);
rel_m := m - LOOPS_rcc_data[ 3 ][ pos_n ][ 2 ][ pos_m ] + 1; # relative position of the loop in the file for G
section := [];
nr_conj_classes := Length( LOOPS_rcc_transitive_groups[ pos_n ][ pos_m ][ 2 ] );
if not LOOPS_rcc_conjugacy_classes[ 1 ] = [ n, g ] then # must calculate conjugacy classes, so let's reset old data
LOOPS_rcc_conjugacy_classes[ 1 ] := [ n, g ];
LOOPS_rcc_conjugacy_classes[ 2 ] := List( [1..nr_conj_classes], x->[] );
fi;
x := LOOPS_rcc_sections[ pos_n ][ pos_m ][ rel_m ];
x := LOOPS_ConvertFromDecimal( x, 2, nr_conj_classes ); # convert to a binary string of prescribed length
pos_conjugacy_classes := Positions( x, '1' );
for i in [1..nr_conj_classes] do
if LOOPS_rcc_conjugacy_classes[ 2 ][ i ] = [] then
LOOPS_rcc_conjugacy_classes[ 2 ][ i ] := Elements( ConjugacyClass( G, LOOPS_rcc_transitive_groups[ pos_n ][ pos_m ][ 2 ][ i ] ) );
fi;
od;
section := Concatenation( LOOPS_rcc_conjugacy_classes[ 2 ]{pos_conjugacy_classes} );
Add( section, One( G ) ); # the trivial class is contained in all loops and never stored
Sort( section );
return LoopByRightSection( section );
end);
#############################################################################
##
#F LOOPS_ActivateCCLoop( n, pos_n, m, case )
##
## Activates a CC-loop from the library.
## The argument p_case is set to [p,"p^2"] if n = p^2, to [p,"2*p"] if n=2*p, and false otherwise.
## See manual for complete discussion concerning this library.
InstallGlobalFunction( LOOPS_ActivateCCLoop,
function( n, pos_n, m, case )
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 ] );
fi;
# parameters n, m are already checked to be permissible
p := case[ 1 ];
if case[ 2 ] = "2*p" then # 2*p
T := List( [1..n], i -> [1..n ] );
for a in [0..p-1] do for b in [0..p-1] do
T[a+1][b+1]:= ((a+b) mod p) + 1;
T[a+1][p+b+1] := p + ((-a+b) mod p ) + 1;
T[p+a+1][b+1] := p + ((a+b) mod p) + 1;
T[p+a+1][p+b+1] := ((1-a+b) mod p) + 1;
od; od;
return LoopByCayleyTable( T );
fi;
# p^2
T := List([1..n], i->[1..n]);
if m = 1 then
for x in [0..n-1] do for y in [0..n-1] do
T[ x+1 ][ y+1 ] := ((x + y + p*(x^2)*y) mod n) + 1;
od; od;
elif m = 2 then
k := LOOPS_SmallestNonsquare( p );
for x in [0..n-1] do for y in [0..n-1] do
T[ x+1 ][ y+1 ] := ((x + y + k*p*(x^2)*y) mod n) + 1;
od; od;
elif m = 3 then
for x in [0..p-1] do for y in [0..p-1] do for a in [0..p-1] do for b in [0..p-1] do
T[ x*p+a+1 ][ y*p+b+1 ] := ((x+y) mod p)*p + ((a+b+(x^2)*y) mod p) + 1;
od; od; od; od;
fi;
return LoopByCayleyTable( T );
end);
#############################################################################
##
#F LOOPS_ActivateNilpotentLoop( data )
##
## Activates the nilpotent loop based on data = [ K, F, t ], where
## K determines a central (normal) subloop,
## F determines the factor loop,
## t determines the cocycle.
## Understanding K and F:
## If the value of K or F is in [2,3,4,5], it is the cyclic group of order V.
## If the value of K or F is 0, it is the Klein group.
## Understanding t:
## The cocycle is mapping from F x F to K. Let f = |F|. Let k = |K|.
## The value t corresponds to a (f-1)x(f-1) array of values in [0..k-1].
## It is represented by a single integer in base k, with the least
## significant digit in the first row and first column, then following
## the rows.
## Once t is decoded into a (f-1)x(f-1) array, 1 is added to all entries.
## Then a first row and forst column of all ones is added to t,
## resulting in a f x f array.
## The loop is then obtained via LoopByExtension( K, F, phi, t), where
## phi is trivial.
InstallGlobalFunction( LOOPS_ActivateNilpotentLoop,
function( data )
local K, F, f, k, t, theta, i, j, phi;
# preparing normal subloop and factor loop
if data[ 1 ] = 0 then
K := IntoLoop( Group( (1,2),(3,4) ) );
else
K := IntoLoop( CyclicGroup( data[ 1 ] ) );
fi;
if data[ 2 ] = 0 then
F := IntoLoop( Group( (1,2),(3,4) ) );
else
F := IntoLoop( CyclicGroup( data[ 2 ] ) );
fi;
# preparing cocycle
f := Size( F );
k := Size( K );
t := data[ 3 ];
theta := List( [1..f], i->[1..f] );
for i in [2..f] do
theta[ 1 ][ i ] := 1;
od;
for i in [2..f] do for j in [2..f] do
theta[ i ][ j ] := t mod k;
t := (t - theta[i][j])/k;
theta[ i ][ j ] := theta[ i ][ j ] + 1;
od; od;
# preparing trivial action
phi := List([1..f], i -> () );
# constructing the loop
return LoopByExtension( K, F, phi, theta );
end);
#############################################################################
##
#F LOOPS_ActivateAutomorphicLoop( n, m )
##
## Activates an automorphic loop from the library.
InstallGlobalFunction( LOOPS_ActivateAutomorphicLoop,
function( n, m )
# 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], 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
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, Length( basis ) );
coords := List( coords, LOOPS_CharToDigit );
# calculate cocycle
coc := (coords*basis) mod 3;
coc := coc + 1;
# return extension of Z_3 by F using cocycle and trivial action
return LoopByExtension( RightBruckLoop(3,1), F, List([1..n/3], i -> () ), coc );
end);
#############################################################################
## READING LOOPS FROM THE LIBRARY - GENERIC METHOD
## -------------------------------------------------------------------------
#############################################################################
##
#F LibraryLoop( name, n, m )
##
## returns he <m>th loop of order <n> from the library named <name>
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
lib := LOOPS_LibraryByName( name );
# extent of the library
implemented_orders := lib[ 1 ];
# number of loops of given order in the library
NOL := lib[ 2 ];
# testing arguments
if (not n in Integers) or (not m in Integers) or not (n>0) or not (m>0) then
Error("LOOPS: Both arguments must be positive integers.");
fi;
# parameters for handling systematic cases, such as CCLoop( p^2, 1 )
pos_n := fail;
case := false;
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 ];
p := divs[ 3 ];
case := [p,q];
if not (IsOddInt( q ) and IsInt((p^2-1)/q)) then
Error("LOOPS: Nonassociative ", name, " loops of order p*q exist only for primes p>q>2 such that q divides p^2-1.");
fi;
if IsInt((p-1)/q) and (not m in [1..(p-q)/2]) then
Error("LOOPS: There are only ", (p-q)/2, " nonassociative ", name, " loops of order ", n, ".");
fi;
if IsInt((p+1)/q) and (not m in [1..(p-q+2)/2]) then
Error("LOOPS: There are only ", (p-q+2)/2, " nonassociative ", name, " loops of order ", n, ".");
fi;
fi;
fi;
if name="CC" then
divs := DivisorsInt( n );
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] ) and not n=21 then # p*q
p := divs[ 3 ];
case := [p,"2*p"];
if not divs[2] = 2 then
Error("LOOPS: Order ", n, " not implemented.");
fi;
if not m=1 then
Error("LOOPS: There is only 1 nonassociative CC-loop of order 2*p for an odd prime p.");
fi;
fi;
fi;
if case=false then
if not n in implemented_orders then
Error("LOOPS: Order ", n, " not implemented.");
fi;
pos_n := Position( implemented_orders, n );
if NOL[ pos_n ] < m then
if NOL[ pos_n ] = 1 then
Error("LOOPS: There is only ", NOL[ pos_n ], " ", name, " loop of order ", n, " in the library.");
else
Error("LOOPS: There are only ", NOL[ pos_n ], " ", name, " loops of order ", n, " in the library.");
fi;
fi;
fi;
# activating the desired loop (treat cases separately below)
# up to isomorphism
if name = "left Bol" then
loop := LOOPS_ActivateLeftBolLoop( pos_n, m, case );
SetIsLeftBolLoop( loop, true );
elif name = "Moufang" then
# renaming loops so that they agree with Goodaire's classification
PG := List([1..243], i->());
PG[16] := (2,5,3,4);
PG[24] := (1,3,4)(2,5);
PG[32] := (1,4,61,7,64,31,19,44,3,51,24,46,22,49,65,9,50,39,41,2,63,27,57,14,5,55,13,69,32,58,17,53,15)
(6,71,28,36,30,47,18,42,26,60,21,59,35,52,25,40,23,43,29,56,20,66,8,70,33,67,38,54,16,62,37,11,68,34,45,10,48,12);
PG[36] := (1,2);
PG[40] := (1,2,5,3,4);
PG[48] := (1,11,43,49,30,7,28,23,36,21,50,31,41,32,46,51,29,12,42,15)
(2,25,24,35,22,8,39,5,6,38,16,19,17,37,34,33,4,47,13,20,10,40,48,14,3,26,45)
(9,27,44);
PG[56] := (1,2,4);
PG[60] := (1,2);
m_inv := m^Inverse( PG[ n ] );
# activating the loop
loop := LOOPS_ActivateMoufangLoop( n, pos_n, m_inv );
SetIsMoufangLoop( loop, true );
elif name = "Paige" then
loop := LoopByCayleyTable( lib[ 3 ][ 1 ][ 1 ] ); #only one loop there at this point
SetIsMoufangLoop( loop, true );
elif name = "code" then
loop := LibraryLoop( "Moufang", n, lib[ 3 ][ pos_n ][ m ] );
SetIsCodeLoop( loop, true );
elif name = "Steiner" then
loop := LOOPS_ActivateSteinerLoop( n, pos_n, m );
SetIsSteinerLoop( loop, true );
elif name = "CC" then
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 = "small" then
loop := LoopByCayleyTable( LOOPS_DecodeCayleyTable( lib[ 3 ][ pos_n ][ m ] ) );
elif name = "interesting" then
if [n,m] = [96,1] then # simple Bol loop of order 96
g := Group((1,4)(2,9)(3,10)(6,11)(7,12)(13,21)(14,22)(15,24)(16,23)(17,30)(18,29)(19,31)(20,32)(33,35)(38,40),
(1,2,4,6,8,7,5,3)(9,13,25,18,10,14,26,17)(11,15,27,20,12,16,28,19)(21,30,38,34,23,31,40,35)(22,32,39,36,24,29,37,33));
h := Normalizer( g, SylowSubgroup( g, 5) );
g := Action( g, RightCosets( g, h ), OnRight );
loop := LoopByRightSection(Union(Filtered(ConjugacyClasses(g),c->Size(c) in [1,15,80])));
else
loop := LoopByCayleyTable( LOOPS_DecodeCayleyTable( lib[ 3 ][ pos_n ][ m ][ 1 ] ) );
fi;
SetName( loop, lib[ 3 ][ pos_n ][ m ][ 2 ] );
elif name = "nilpotent" then
loop := LOOPS_ActivateNilpotentLoop( lib[ 3 ][ pos_n ][ m ] );
elif name = "automorphic" then
if not n in [3, 9, 27, 81] then # use Cayley table
loop := LoopByCayleyTable( LOOPS_DecodeCayleyTable( lib[ 3 ][ pos_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 ] );
fi;
# setting the name
if not name = "interesting" then
SetName( loop, Concatenation( "<", name, " loop ", String( n ), "/", String( m ), ">" ) );
fi;
# returning the loop
return loop;
end);
#############################################################################
## READING LOOPS FROM THE LIBRARY - SPECIFIC CALLS
## -------------------------------------------------------------------------
#############################################################################
##
#F LeftBolLoop( n, m )
#F RightBolLoop( n, m )
#F MoufangLoop( n, m )
#F PaigeLoop( q )
#F CodeLoop( n, m )
#F SteinerLoop( n, m )
#F CCLoop( n, m )
#F SmallLoop( n, m )
#F InterestingLoop( n, m )
#F NilpotentLoop( n, m )
#F AutomorphicLoop( n, m )
#F LeftBruckLoop( n, m )
#F RightBruckLoop( n, m )
#F ItpSmallLoop( n, m )
##
InstallGlobalFunction( LeftBolLoop, function( n, m )
return LibraryLoop( "left Bol", n, m );
end);
InstallGlobalFunction( RightBolLoop, function( 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 )
return LibraryLoop( "Moufang", n, m );
end);
InstallGlobalFunction( PaigeLoop, function( q )
# Paige loop over GF(q)
if not q=2 then return Error("LOOPS: Only q=2 is implemented."); fi;
return LibraryLoop( "Paige", 120, 1 );
end);
InstallGlobalFunction( CodeLoop, function( n, m )
return LibraryLoop( "code", n, m );
end);
InstallGlobalFunction( SteinerLoop, function( n, m )
return LibraryLoop( "Steiner", n, m );
end);
InstallGlobalFunction( CCLoop, function( n, m )
return LibraryLoop( "CC", n, m );
end);
InstallGlobalFunction( ConjugacyClosedLoop, function( n, m )
return LibraryLoop( "CC", n, m );
end);
InstallGlobalFunction( RCCLoop, function( n, m )
return LibraryLoop( "RCC", n, m );
end);
InstallGlobalFunction( RightConjugacyClosedLoop, function( n, m )
return LibraryLoop( "RCC", n, m );
end);
InstallGlobalFunction( LCCLoop, function( 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 LCCLoop( n, m );
end);
InstallGlobalFunction( SmallLoop, function( n, m )
return LibraryLoop( "small", n, m );
end);
InstallGlobalFunction( InterestingLoop, function( n, m )
return LibraryLoop( "interesting", n, m );
end);
InstallGlobalFunction( NilpotentLoop, function( n, m )
return LibraryLoop( "nilpotent", n, m );
end);
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);