209 lines
7.5 KiB
Plaintext
209 lines
7.5 KiB
Plaintext
|
#############################################################################
|
||
|
##
|
||
|
#W random.gi Random loops [loops]
|
||
|
##
|
||
|
#H @(#)$Id: random.gi, v 2.1.0 2008/12/08 gap Exp $
|
||
|
##
|
||
|
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
|
||
|
#Y P. Vojtechovsky (University of Denver, USA)
|
||
|
##
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O RandomQuasigroup( n, iter )
|
||
|
##
|
||
|
## Returns a random quasigroup of order <n> using <iter> random steps to move into an
|
||
|
## initial position in the Jacobson & Matthews method.
|
||
|
## (MATH) This is an implementation of the Jacobson & Matthews random walk method with
|
||
|
## some ad hoc mixing parameters. We always start with the cyclic group of order n.
|
||
|
## It is proved in Jacobson & Matthews that a random walk in the graph visits all
|
||
|
## latin squares uniformly. (But the problem is how to move to an initial position.)
|
||
|
|
||
|
InstallMethod( RandomQuasigroup, "for two integers",
|
||
|
[ IsInt, IsInt ],
|
||
|
function( n, iter )
|
||
|
local f, x, y, z, is_proper, xx, yy, zz, random_walk_step, i, ct;
|
||
|
|
||
|
if not ( n > 0 and iter > 0 ) then
|
||
|
Error("LOOPS: the arguments must be positive integers.");
|
||
|
fi;
|
||
|
|
||
|
# n=1 is a special case
|
||
|
if n=1 then
|
||
|
return LoopByCayleyTable( [[1]] );
|
||
|
fi;
|
||
|
|
||
|
# initializing funciton for proper and improper Latin squares
|
||
|
# the meaning of f(x,y,z)=1 is that there is symbol z in row x and column y
|
||
|
f := List([1..n], i -> List([1..n], j -> 0*[1..n]));
|
||
|
# cyclic group of order n on symbols [1..n]
|
||
|
for x in [1..n] do for y in [1..n] do
|
||
|
z := x+y-1;
|
||
|
if z > n then
|
||
|
z := z - n;
|
||
|
fi;
|
||
|
f[x][y][z] := 1;
|
||
|
od; od;
|
||
|
is_proper := true; # proper latin square to start with
|
||
|
|
||
|
# one random walk step
|
||
|
random_walk_step := function()
|
||
|
local x, y, z, triples, x2, y2, z2, triple;
|
||
|
if is_proper then
|
||
|
repeat
|
||
|
x := Random([1..n]);
|
||
|
y := Random([1..n]);
|
||
|
z := Random([1..n]);
|
||
|
until f[x][y][z]=0;
|
||
|
fi;
|
||
|
if not is_proper then # use unique point with f(x,y,z)=-1
|
||
|
x := xx;
|
||
|
y := yy;
|
||
|
z := zz;
|
||
|
fi;
|
||
|
# find all suitable triples
|
||
|
x2 := Filtered( [1..n], a -> f[a][y][z] = 1 );
|
||
|
y2 := Filtered( [1..n], a -> f[x][a][z] = 1 );
|
||
|
z2 := Filtered( [1..n], a -> f[x][y][a] = 1 );
|
||
|
# pick a random suitable triple
|
||
|
x2 := Random( x2 );
|
||
|
y2 := Random( y2 );
|
||
|
z2 := Random( z2 );
|
||
|
# shuffle values
|
||
|
f[x][y][z] := f[x][y][z] + 1;
|
||
|
f[x][y2][z2] := f[x][y2][z2] + 1;
|
||
|
f[x2][y][z2] := f[x2][y][z2] + 1;
|
||
|
f[x2][y2][z] := f[x2][y2][z] + 1;
|
||
|
f[x2][y][z] := f[x2][y][z] - 1;
|
||
|
f[x][y2][z] := f[x][y2][z] - 1;
|
||
|
f[x][y][z2] := f[x][y][z2] - 1;
|
||
|
f[x2][y2][z2] := f[x2][y2][z2] - 1;
|
||
|
# determine properness
|
||
|
if f[x2][y2][z2] = 0 then
|
||
|
is_proper := true;
|
||
|
else
|
||
|
is_proper := false;
|
||
|
xx := x2;
|
||
|
yy := y2;
|
||
|
zz := z2;
|
||
|
fi;
|
||
|
end;
|
||
|
|
||
|
# moving into an initial point in the graph
|
||
|
for i in [1..iter] do
|
||
|
random_walk_step();
|
||
|
od;
|
||
|
# finding a proper square nearby
|
||
|
while not is_proper do
|
||
|
random_walk_step();
|
||
|
od;
|
||
|
# constructing the multiplication table from the function
|
||
|
ct := List([1..n], i->[1..n]);
|
||
|
for x in [1..n] do for y in [1..n] do
|
||
|
ct[x][y] := Filtered([1..n], z -> f[x][y][z] = 1)[ 1 ];
|
||
|
od; od;
|
||
|
return QuasigroupByCayleyTable( ct );
|
||
|
end);
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O RandomQuasigroup( n )
|
||
|
##
|
||
|
## Returns random quasigroup of order <n> using n^3 steps to move into an
|
||
|
## initial position in the Jacobson & Matthews algorithm.
|
||
|
|
||
|
InstallOtherMethod( RandomQuasigroup, "for a positive integer",
|
||
|
[ IsInt ],
|
||
|
function( n )
|
||
|
return RandomQuasigroup( n, n^3 );
|
||
|
end);
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O RandomLoop( n, iter )
|
||
|
##
|
||
|
## Returns a normalized random quasigroup of order <n>.
|
||
|
|
||
|
InstallOtherMethod( RandomLoop, "for two positive integers",
|
||
|
[ IsInt, IsInt ],
|
||
|
function( n, iter )
|
||
|
local Q;
|
||
|
Q := RandomQuasigroup( n, iter );
|
||
|
return LoopByCayleyTable( NormalizedQuasigroupTable( CayleyTable( Q ) ) );
|
||
|
end);
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O RandomLoop( n )
|
||
|
##
|
||
|
## Returns random loop of order <n> using n^3 steps to move into an
|
||
|
## initial position in the Jacobson & Matthews algorithm.
|
||
|
|
||
|
InstallOtherMethod( RandomLoop, "for a positive integer",
|
||
|
[ IsInt ],
|
||
|
function( n )
|
||
|
local Q;
|
||
|
Q := RandomQuasigroup( n );
|
||
|
return LoopByCayleyTable( NormalizedQuasigroupTable( CayleyTable( Q ) ) );
|
||
|
end);
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O RandomNilpotentLoop( lst )
|
||
|
##
|
||
|
## lst must be a list of positive integers and/or finite abelian groups.
|
||
|
## If lst = [n] and n is an integer, returns a random abelian group of order n.
|
||
|
## If lst = [A] and A is an abelian group, returns AsLoop( A ).
|
||
|
## If lst = [a1,..,am] and a1 is an integer, returns a central extension
|
||
|
## of an abelian group of order a1 by RandomNilpotentLoop( [a2,...,am] ).
|
||
|
## If lst = [a1,..,am] and a1 is a group, returns a central extension
|
||
|
## of a1 by RandomNilpotentLoop( [a2,...,am] ).
|
||
|
## To determine the nilpotency class CL of the resulting loop, assume that
|
||
|
## lst has length at least 2, contains only integers bigger than 1 (the "1" entries are trivial),
|
||
|
## and let m be the last entry of lst. If m>2 then CL=Length(lst), else CL = Length(lst)-1.
|
||
|
|
||
|
InstallMethod( RandomNilpotentLoop, "for a list of abelian groups and positive integers",
|
||
|
[ IsList ],
|
||
|
function( lst )
|
||
|
local n, K, F, f, theta, i, j, phi;
|
||
|
if IsEmpty( lst ) then
|
||
|
Error("LOOPS: the argument must be a list of finite abelian groups and/or positive integers.");
|
||
|
fi;
|
||
|
n := lst[1];
|
||
|
if not ( IsPosInt( n ) or (IsGroup( n ) and IsAbelian( n ) and IsFinite( n ) ) ) then
|
||
|
Error("LOOPS: the argument must be a list of finite abelian groups and/or positive integers.");
|
||
|
fi;
|
||
|
# central subloop
|
||
|
if IsInt( n ) then # first argument is a positive integer
|
||
|
K := IntoLoop( Random( AllGroups( n, IsAbelian ) ) );
|
||
|
else # first argument is an abelian group
|
||
|
K := IntoLoop( n );
|
||
|
fi;
|
||
|
# factor loop
|
||
|
if Length( lst ) = 1 then # trivial factor
|
||
|
F := LoopByCayleyTable( [ [ 1 ] ] );
|
||
|
else
|
||
|
F := RandomNilpotentLoop( lst{[2..Length(lst)]} );
|
||
|
fi;
|
||
|
# cocycle (random)
|
||
|
f := Size( F );
|
||
|
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] := Random( [1..Size(K)] );
|
||
|
od; od;
|
||
|
# To guarantee that the resulting loop has maximal nilpotency class,
|
||
|
# it suffices to make sure that theta is not symmetric.
|
||
|
if f>2 then
|
||
|
i := Random([2..f]);
|
||
|
j := Random( Difference( [2..f], [i] ) );
|
||
|
theta[i][j] := Random( Difference( [1..Size(K)], [ theta[j][i] ] ) );
|
||
|
fi;
|
||
|
# trivial action
|
||
|
phi := List( [1..f], i->() );
|
||
|
# the loop
|
||
|
return LoopByExtension( K, F, phi, theta );
|
||
|
end);
|