GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
# The GAP code in this function has been taken, essentially verbatim, from
# an appendix to the paper
# Hulpke, Stanovsky, Vojtechovsky: Connected quandles and transitive groups
############################################################
############################################################
InstallGlobalFunction(QuandleIsomorphismRepresentatives,
function(L)
local C,R, P, Q, invariant, ExtendHomomorphismByClosingSource,
ExtendIsomorphism, IsomorphismQuandles, QuandlesUpToIsomorphism,
QuandleGenerators, T, Subquandle;
#########################
invariant:=function(QQ)
local rt, A, F, Q;
Q:=MagmaByMultiplicationTable(QQ);
rt:=RightMultiplicationGroupOfQuandle(Q);
if HasIdGroup(rt) then
rt:=IdGroup(rt);
else
rt:=false;
fi;
A:=[rt];
return A;
end;
#########################
#########################
Subquandle := function( Q, gens )
# returns the subquandle of Q generated by gens as a list of elements
local sub, i, j;
sub := ShallowCopy( gens );
repeat
gens := ShallowCopy( sub );
for i in gens do for j in gens do
AddSet( sub, Q[i][j] );
od; od;
until Length( sub ) = Length( gens );
return sub;
end;
#########################
#########################
QuandleGenerators := function( Q )
# returns a small generating set of Q
local gens, diff, n;
gens := [ ];
n := Length( Q );
diff := [1..n];
while diff <> [ ] do
AddSet( gens, diff[ 1 ] );
diff := Difference( diff, Subquandle( Q, gens ) );
od;
return Set( gens );
end;
#########################
ExtendHomomorphismByClosingSource := function( f, L, M )
# <L>, <M> are multiplication tables, <f> is a partial map from a subset of elements of <L>
# to a subset of elements of <M>. This function attempts to extend <f> into a homomorphism
# by extending the source of <f> into (the smallest possible) subquandle of <L>.
local oldS, newS, pairs, x, y, newNow, p, z, fz;
oldS := [ ];
newS := f[ 2 ];
repeat
pairs := [];
for x in oldS do for y in newS do
Add( pairs, [ x, y ] );
Add( pairs, [ y, x ] );
od; od;
for x in newS do for y in newS do
Add( pairs, [ x, y ] );
od; od;
newNow := [];
for p in pairs do
x := p[ 1 ];
y := p[ 2 ];
z := L[ x ][ y ];
fz := M[ f[ 1 ][ x ] ][ f[ 1 ][ y ] ];
if f[ 1 ][ z ] = 0 then
f[ 1 ][ z ] := fz; AddSet( f[ 2 ], z ); AddSet( f[ 3 ], fz );
Add( newNow, z );
else
if not f[ 1 ][ z ] = fz then return fail; fi;
fi;
od;
oldS := Union( oldS, newS );
newS := ShallowCopy( newNow );
until IsEmpty( newS );
return f;
end;
ExtendIsomorphism := function( f, L, GenL, M )
# Given a partial map <f> from quandle <L> to quandle <M>, it attempts to extend
# <f> into an isomorphism betweem <L> and <M>.
# <GenL> is a small generating set of <L>.
local x, possible_images, y, g, n;
n := Length( L );
f := ExtendHomomorphismByClosingSource( f, L, M );
if f = fail or Length( f[ 2 ] ) > Length( f[ 3 ] ) then return fail; fi;
if Length( f[ 2 ] ) = Length( L ) then return f; fi; #isomorphism found
x := GenL[ 1 ];
GenL := List( [ 2..Length( GenL ) ], i -> GenL[ i ] );
possible_images := Filtered( [1..n], y -> not y in f[ 3 ] );
for y in possible_images do
g := StructuralCopy( f );
g[ 1 ][ x ] := y; AddSet( g[ 2 ], x ); AddSet( g[ 3 ], y );
g := ExtendIsomorphism( g, L, GenL, M );
if not g = fail then return g; fi; #isomorphism found
od;
return fail;
end;
IsomorphismQuandles := function( L, M )
# returns an isomorphism of L to M if such exists, else returns fail.
local GenL, map, iso;
GenL := QuandleGenerators( L );
map := 0 * [ 1.. Length( L ) ]; map[ 1 ] := 1; # THIS IS ONLY OK IN INDECOMPOSABLE QUANDLES
iso := ExtendIsomorphism( [ map, [ 1 ], [ 1 ] ], L, GenL, M);
if not iso = fail then return SortingPerm( iso[ 1 ] ); fi;
return fail;
end;
QuandlesUpToIsomorphism := function( ls )
# given a list of quandles ls, returns representatives up to isomorphism
local qs, L, D, G, with_same_D, is_new, K;
qs := [];
for L in ls do
D := invariant( L );
G := QuandleGenerators( L );
# will be testing only quandles with the same discriminator
with_same_D := Filtered( qs, K -> K[2] = D );
is_new := true;
for K in with_same_D do # K is a set of ordered tuples [quandle, discriminator]
if not IsomorphismQuandles( L, K[1] ) = fail then
is_new := false;
break;
fi;
od;
if is_new then Add( qs, [ L, D ] ); fi;
od;
# returning only quandles, not their discriminators
return List( qs, L -> L[1] );
end;
T:=List(L,x->MultiplicationTable(Elements(x)));
return List(QuandlesUpToIsomorphism(T), x->MagmaByMultiplicationTable(x));
end);
############################################################
############################################################