396 lines
13 KiB
Plaintext
396 lines
13 KiB
Plaintext
## structure.gi RAQ Implementation of definitiions, reps, and elt operations
|
|
|
|
## Create structures with generators
|
|
InstallGlobalFunction(CloneOfTypeByGenerators,
|
|
function(cat, fam, gens, genAttrib, tableCstr)
|
|
local M;
|
|
if not(IsEmpty(gens) or IsIdenticalObj(FamilyObj(gens), fam)) then
|
|
Error("<fam> and family of <gens> do not match");
|
|
fi;
|
|
M := Objectify(NewType( fam, cat and IsAttributeStoringRep), rec());
|
|
Setter(genAttrib)(M, AsList(gens));
|
|
SetConstructorFromTable(M, tableCstr);
|
|
return M;
|
|
end);
|
|
|
|
## Functions for each of the magma categories here
|
|
InstallGlobalFunction(LeftQuasigroup, function(arg)
|
|
local fam;
|
|
if Length(arg) = 0 then
|
|
Error("usage: LeftQuasigroup([<family>], <gens>)");
|
|
fi;
|
|
# Extract the family
|
|
if IsFamily(arg[1]) then
|
|
fam := arg[1];
|
|
Remove(arg, 1);
|
|
arg := Flat(arg);
|
|
else
|
|
arg := Flat(arg);
|
|
fam := FamilyObj(arg[1]);
|
|
fi;
|
|
return CloneOfTypeByGenerators(IsLeftQuasigroup, fam, arg,
|
|
GeneratorsOfLeftQuasigroup,
|
|
LeftQuasigroupByMultiplicationTable);
|
|
end);
|
|
|
|
InstallGlobalFunction(LeftRack, function(arg)
|
|
local fam;
|
|
if Length(arg) = 0 then
|
|
Error("usage: LeftRack([<family>], <gens>)");
|
|
fi;
|
|
# Extract the family
|
|
if IsFamily(arg[1]) then
|
|
fam := arg[1];
|
|
Remove(arg, 1);
|
|
arg := Flat(arg);
|
|
else
|
|
arg := Flat(arg);
|
|
fam := FamilyObj(arg[1]);
|
|
fi;
|
|
return CloneOfTypeByGenerators(IsLeftRack, fam, arg,
|
|
GeneratorsOfLeftQuasigroup,
|
|
LeftRackByMultiplicationTableNC);
|
|
end);
|
|
|
|
InstallGlobalFunction(RightQuasigroup, function(arg)
|
|
local fam;
|
|
if Length(arg) = 0 then
|
|
Error("usage: RightQuasigroup([<family>], <gens>)");
|
|
fi;
|
|
# Extract the family
|
|
if IsFamily(arg[1]) then
|
|
fam := arg[1];
|
|
Remove(arg, 1);
|
|
arg := Flat(arg);
|
|
else
|
|
arg := Flat(arg);
|
|
fam := FamilyObj(arg[1]);
|
|
fi;
|
|
return CloneOfTypeByGenerators(IsRightQuasigroup, fam, arg,
|
|
GeneratorsOfRightQuasigroup,
|
|
RightQuasigroupByMultiplicationTable);
|
|
end);
|
|
|
|
InstallGlobalFunction(RightRack, function(arg)
|
|
local fam;
|
|
if Length(arg) = 0 then
|
|
Error("usage: RightRack([<family>], <gens>)");
|
|
fi;
|
|
# Extract the family
|
|
if IsFamily(arg[1]) then
|
|
fam := arg[1];
|
|
Remove(arg, 1);
|
|
arg := Flat(arg);
|
|
else
|
|
arg := Flat(arg);
|
|
fam := FamilyObj(arg[1]);
|
|
fi;
|
|
return CloneOfTypeByGenerators(IsRightRack, fam, arg,
|
|
GeneratorsOfRightQuasigroup,
|
|
RightRackByMultiplicationTableNC);
|
|
end);
|
|
|
|
## Predicates to check tables for distributivity
|
|
InstallMethod(IsRightSelfDistributiveTable, "for matrix",
|
|
[ IsMatrix ],
|
|
T -> IsLeftSelfDistributiveTable(TransposedMat(T))
|
|
);
|
|
|
|
InstallMethod(IsLeftSelfDistributiveTable, "for matrix",
|
|
[ IsMatrix ],
|
|
function(T)
|
|
# Everybody else does it by checking all of the cases, so why not me, too?
|
|
# Is there a better way?
|
|
local n,i,j,k;
|
|
n := Length(T);
|
|
for i in [1..n] do for j in [1..n] do for k in [1..n] do
|
|
if T[i, T[j,k]] <> T[T[i,j], T[i,k]] then return false; fi;
|
|
od; od; od;
|
|
return true;
|
|
end);
|
|
|
|
## And now create them from multiplication tables
|
|
InstallGlobalFunction(LeftQuasigroupByMultiplicationTable,
|
|
function(T)
|
|
if not IsLeftQuasigroupTable(T) then
|
|
Error("Multiplication table <T> must have each row a permutation of ",
|
|
"the same entries.");
|
|
fi;
|
|
return MagmaByMultiplicationTableCreatorNC(
|
|
CanonicalCayleyTableOfLeftQuasigroupTable(T),
|
|
LeftQuasigroup,
|
|
IsLeftQuotientElement and IsMagmaByMultiplicationTableObj
|
|
);
|
|
end);
|
|
|
|
InstallGlobalFunction(RightQuasigroupByMultiplicationTable,
|
|
function(T)
|
|
if not IsRightQuasigroupTable(T) then
|
|
Error("Multiplication table <T> must have each column a permutation of ",
|
|
"the same entries.");
|
|
fi;
|
|
return MagmaByMultiplicationTableCreatorNC(
|
|
CanonicalCayleyTable(T),
|
|
RightQuasigroup,
|
|
IsRightQuotientElement and IsMagmaByMultiplicationTableObj
|
|
);
|
|
end);
|
|
|
|
InstallGlobalFunction(LeftRackByMultiplicationTable,
|
|
function(T)
|
|
if not IsLeftQuasigroupTable(T) then
|
|
Error("Multiplication table <T> must have each row a permutation of ",
|
|
"the same entries.");
|
|
fi;
|
|
T := CanonicalCayleyTableOfLeftQuasigroupTable(T);
|
|
if not IsLeftSelfDistributiveTable(T) then
|
|
Error("Multiplication table <T> must be left self distributive.");
|
|
fi;
|
|
return LeftRackByMultiplicationTableNC(T);
|
|
end);
|
|
|
|
InstallGlobalFunction(LeftRackByMultiplicationTableNC,
|
|
T -> MagmaByMultiplicationTableCreatorNC(T, LeftRack,
|
|
IsLeftQuotientElement and IsLSelfDistElement and
|
|
IsMagmaByMultiplicationTableObj
|
|
)
|
|
);
|
|
|
|
InstallGlobalFunction(RightRackByMultiplicationTable,
|
|
function(T)
|
|
if not IsRightQuasigroupTable(T) then
|
|
Error("Multiplication table <T> must have each column a permutation of ",
|
|
"the same entries.");
|
|
fi;
|
|
T := CanonicalCayleyTable(T);
|
|
if not IsRightSelfDistributiveTable(T) then
|
|
Error("Multiplication table <T> must be right self distributive.");
|
|
fi;
|
|
return RightRackByMultiplicationTableNC(T);
|
|
end);
|
|
|
|
InstallGlobalFunction(RightRackByMultiplicationTableNC,
|
|
T -> MagmaByMultiplicationTableCreatorNC(T, RightRack,
|
|
IsRightQuotientElement and IsRSelfDistElement and
|
|
IsMagmaByMultiplicationTableObj
|
|
)
|
|
);
|
|
|
|
## And define the operations
|
|
|
|
InstallOtherMethod(LeftQuotient,
|
|
"for two elts in magma by mult table, when left has left quotients",
|
|
IsIdenticalObj,
|
|
[IsLeftQuotientElement, IsMagmaByMultiplicationTableObj],
|
|
function (l,r)
|
|
local fam, ix;
|
|
fam := FamilyObj(l);
|
|
ix := LeftDivisionTable(fam)[l![1],r![1]];
|
|
return fam!.set[ix];
|
|
end);
|
|
|
|
InstallOtherMethod(\/,
|
|
"for two elts in magma by mult table, when right has right quotients",
|
|
IsIdenticalObj,
|
|
[IsMagmaByMultiplicationTableObj, IsRightQuotientElement],
|
|
function (l,r)
|
|
local fam, ix;
|
|
fam := FamilyObj(r);
|
|
ix := RightDivisionTable(fam)[l![1],r![1]];
|
|
return fam!.set[ix];
|
|
end);
|
|
|
|
## Create division tables as needed
|
|
InstallMethod(LeftDivisionTable,
|
|
"for an object with a multiplication table",
|
|
[HasMultiplicationTable],
|
|
function(fam)
|
|
local LS, n;
|
|
LS := LeftPerms(fam);
|
|
n := Size(LS);
|
|
return List(LS, x->ListPerm(Inverse(x), n));
|
|
end);
|
|
|
|
InstallMethod(RightDivisionTable,
|
|
"for an object with a multiplication table",
|
|
[HasMultiplicationTable],
|
|
function (obj)
|
|
local RS, n;
|
|
RS := RightPerms(obj);
|
|
n := Size(RS);
|
|
return TransposedMat(List(RS, x->ListPerm(Inverse(x), n)));
|
|
end);
|
|
|
|
## Create perm lists as needed
|
|
InstallMethod(LeftPerms,
|
|
"for an object with a multiplication table",
|
|
[HasMultiplicationTable],
|
|
function(fam)
|
|
return List(MultiplicationTable(fam), x->PermList(x));
|
|
end);
|
|
|
|
InstallMethod(RightPerms,
|
|
"for an object with a muliplication table",
|
|
[HasMultiplicationTable],
|
|
function(fam)
|
|
return List(TransposedMat(MultiplicationTable(fam)), x->PermList(x));
|
|
end);
|
|
|
|
## Distributivity checkers for when need be
|
|
InstallMethod(IsLSelfDistributive, "for magma",
|
|
[IsMagma],
|
|
M -> IsLeftSelfDistributiveTable(MultiplicationTable(M))
|
|
);
|
|
|
|
InstallMethod(IsRSelfDistributive, "for magma",
|
|
[IsMagma],
|
|
M -> IsRightSelfDistributiveTable(MultiplicationTable(M))
|
|
);
|
|
|
|
## View and print and such
|
|
LeftObjString@ := function(Q)
|
|
if IsLeftRack(Q) then return "LeftRack"; fi;
|
|
return "LeftQuasigroup";
|
|
end;
|
|
|
|
RightObjString@ := function(Q)
|
|
if IsRightRack(Q) then return "RightRack"; fi;
|
|
return "RightQuasigroup";
|
|
end;
|
|
|
|
InstallMethod(String, "for a left quasigroup",
|
|
[IsLeftQuasigroup],
|
|
Q -> Concatenation(LeftObjString@(Q), "(...)"));
|
|
|
|
InstallMethod(String, "for a left quasigroup with generators",
|
|
[IsLeftQuasigroup and HasGeneratorsOfLeftQuasigroup],
|
|
Q -> Concatenation(LeftObjString@(Q), "( ",
|
|
String(GeneratorsOfLeftQuasigroup(Q)), " )"));
|
|
|
|
InstallMethod(String, "for a left quasigroup with multiplication table",
|
|
[IsLeftQuasigroup and HasMultiplicationTable],
|
|
Q -> Concatenation(LeftObjString@(Q),
|
|
"ByMultiplicationTableNC( ",
|
|
String(MultiplicationTable(Q)), " )"));
|
|
|
|
InstallMethod(String, "for a right quasigroup",
|
|
[IsRightQuasigroup],
|
|
Q -> Concatenation(RightObjString@(Q), "(...)"));
|
|
|
|
InstallMethod(String, "for a right quasigroup with generators",
|
|
[IsRightQuasigroup and HasGeneratorsOfRightQuasigroup],
|
|
Q -> Concatenation(RightObjString@(Q), "( ",
|
|
String(GeneratorsOfRightQuasigroup(Q)), " )"));
|
|
|
|
InstallMethod(String, "for a right quasigroup with multiplication table",
|
|
[IsRightQuasigroup and HasMultiplicationTable],
|
|
Q -> Concatenation(RightObjString@(Q),
|
|
"ByMultiplicationTableNC( ",
|
|
String(MultiplicationTable(Q)), " )"));
|
|
|
|
InstallMethod(DisplayString, "for a left quasigroup",
|
|
[IsLeftQuasigroup], Q -> String(Q));
|
|
|
|
InstallMethod(DisplayString, "for a rightt quasigroup",
|
|
[IsRightQuasigroup], Q -> String(Q));
|
|
|
|
InstallMethod(Display, "for a left quasigroup with multiplication table",
|
|
[IsLeftQuasigroup and HasMultiplicationTable],
|
|
function(Q)
|
|
Print(LeftObjString@(Q), " with ", Size(Q),
|
|
" elements, generated by ",
|
|
GeneratorsOfLeftQuasigroup(Q), ", with table\n");
|
|
Display(MultiplicationTable(Q));
|
|
end);
|
|
|
|
InstallMethod(Display, "for a right quasigroup with multiplication table",
|
|
[IsRightQuasigroup and HasMultiplicationTable],
|
|
function(Q)
|
|
Print(RightObjString@(Q), " with ", Size(Q),
|
|
" elements, generated by ",
|
|
GeneratorsOfRightQuasigroup(Q), ", with table\n");
|
|
Display(MultiplicationTable(Q));
|
|
end);
|
|
|
|
LeftObjView@ := function(Q)
|
|
if IsLeftRack(Q) then return "<left rack"; fi;
|
|
return "<left quasigroup";
|
|
end;
|
|
|
|
RightObjView@ := function(Q)
|
|
if IsRightRack(Q) then return "<right rack"; fi;
|
|
return "<right quasigroup";
|
|
end;
|
|
|
|
InstallMethod(ViewString, "for a left quasigroup",
|
|
[IsLeftQuasigroup],
|
|
Q -> Concatenation(LeftObjView@(Q), ">");
|
|
|
|
InstallMethod(ViewString, "for a left quasigroup with generators",
|
|
[IsLeftQuasigroup and HasGeneratorsOfLeftQuasigroup],
|
|
Q -> Concatenation(LeftObjView@(Q), " with ",
|
|
Size(GeneratorsOfLeftQuasigroup),
|
|
" generators>"));
|
|
|
|
InstallMethod(ViewString, "for a right quasigroup",
|
|
[IsRightQuasigroup],
|
|
Q -> Concatenation(RightObjView@(Q), ">");
|
|
|
|
InstallMethod(ViewString, "for a right quasigroup with generators",
|
|
[IsRightQuasigroup and HasGeneratorsOfRightQuasigroup],
|
|
Q -> Concatenation(RightObjView@(Q), " with ",
|
|
Size(GeneratorsOfRightQuasigroup),
|
|
" generators>"));
|
|
|
|
# Patch View/Print/Display for magma by mult objects
|
|
InstallMethod(String, "for an element of magma by multiplication table",
|
|
[IsMagmaByMultiplicationTableObj],
|
|
function(obj)
|
|
local fam;
|
|
fam := FamilyObj(obj);
|
|
if IsBound(fam!.elmNamePrefix) then
|
|
return Concatenation(fam!.elmNamePrefix, String(obj![1]));
|
|
fi;
|
|
return Concatenation("m", String(obj![1]));
|
|
end);
|
|
|
|
InstallMethod(ViewString, "for an element of magma by multiplication table",
|
|
[IsMagmaByMultiplicationTableObj],
|
|
obj -> String(obj));
|
|
|
|
InstallMethod(DisplayString, "for an element of magma by multiplication table",
|
|
[IsMagmaByMultiplicationTableObj],
|
|
obj -> String(obj));
|
|
|
|
InstallMethod(PrintObj, "for an element of magma by multiplication table",
|
|
[IsMagmaByMultiplicationTableObj],
|
|
function(obj) Print(String(obj)); end);
|
|
|
|
## Special case the Opposite function from LOOPS package, since the opposite
|
|
## of a left quasigroup is a right quasigroup and vice versa
|
|
|
|
# Is there a way to do this just once for each direction?
|
|
InstallMethod(Opposite, "for left quasigroup",
|
|
[ IsLeftQuasigroup ],
|
|
L -> RightQuasigroupByMultiplicationTable(
|
|
TransposedMat(MultiplicationTable(L))
|
|
)
|
|
);
|
|
|
|
InstallMethod(Opposite, "for left rack",
|
|
[ IsLeftRack ],
|
|
L -> RightRackByMultiplicationTableNC(TransposedMat(MultiplicationTable(L)))
|
|
);
|
|
|
|
InstallMethod(Opposite, "for right quasigroup",
|
|
[ IsRightQuasigroup ],
|
|
L -> LeftQuasigroupByMultiplicationTable(
|
|
TransposedMat(MultiplicationTable(L))
|
|
)
|
|
);
|
|
|
|
InstallMethod(Opposite, "for right rack",
|
|
[ IsRightRack ],
|
|
L -> LeftRackByMultiplicationTableNC(TransposedMat(MultiplicationTable(L)))
|
|
);
|