RAQ/gap/structure.gi

306 lines
11 KiB
Plaintext

## structure.gi RAQ Implementation of definitiions, reps, and elt operations
## Testing properties of collections the hard way if we have to
InstallMethod(IsElementwiseIdempotent, "for finite collections",
[IsMultiplicativeElementCollection and IsFinite],
M -> ForAll(Elements(M), m->IsIdempotent(m))
);
InstallMethod(IsLSelfDistributive,
"for arbitrary multiplicative collections, the hard way",
[IsMultiplicativeElementCollection],
function (C)
local a,b,d;
for a in C do for b in C do for d in C do
if d*(a*b) <> (d*a)*(d*b) then return false; fi;
od; od; od;
return true;
end);
InstallMethod(IsRSelfDistributive,
"for arbitrary multiplicative collections, the hard way",
[IsMultiplicativeElementCollection],
function (C)
local a,b,d;
for a in C do for b in C do for d in C do
if (a*b)*d <> (a*d)*(b*d) then return false; fi;
od; od; od;
return true;
end);
## Create structures with generators
InstallGlobalFunction(CloneOfTypeByGenerators,
function(cat, fam, gens, genAttrib, tableCstr)
local M, elf;
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);
elf := ElementsFamily(fam);
# Since there doesn't seem to be a way to make the IsFinite method based
# on the family being finite into an immediate method:
if HasIsFinite(elf) and IsFinite(elf) then SetIsFinite(M, true); fi;
return M;
end);
## Helpers for the constructors below:
ArgHelper@ := function(parmlist)
# returns a list of the family and the flat list of elements of parmlist
if Length(parmlist) = 0 then
Error("usage: RAQ constructors take an optional family, followed by gens");
fi;
if IsFamily(parmlist[1]) then return [Remove(parmlist,1), Flat(parmlist)]; fi;
parmlist := Flat(parmlist);
return [FamilyObj(parmlist), parmlist];
end;
CheckLQGprop@ := function(gens)
local g, h;
# Make sure all elements in gens have left quotient property pairwise
for g in gens do for h in gens do
if g*LeftQuotient(g,h) <> h or LeftQuotient(g,g*h) <> h then
Error("left quasigroup property of left quotients violated");
fi;
od; od;
return;
end;
CheckRQGprop@ := function(gens)
local g, h;
# Make sure all elements in gens have right quotient property pairwise
for g in gens do for h in gens do
if (h*g)/g <> h or (h/g)*g <> h then
Error("right quasigroup property of / violated");
fi;
od; od;
return;
end;
## Functions for each of the magma categories here
InstallGlobalFunction(LeftQuasigroup, function(arg)
arg := ArgHelper@(arg);
CheckLQGprop@(arg[2]);
return LeftQuasigroupNC(arg[1], arg[2]);
end);
InstallGlobalFunction(LeftQuasigroupNC, function(fam, gens)
return CloneOfTypeByGenerators(IsLeftQuasigroup, fam, gens,
GeneratorsOfLeftQuasigroup,
LeftQuasigroupByMultiplicationTableNC);
end);
InstallGlobalFunction(LeftRack, function(arg)
arg := ArgHelper@(arg);
CheckLQGprop@(arg[2]);
if not IsLSelfDistributive(arg[2]) then
Error("Left rack must have left distributive generators");
fi;
return LeftRackNC(arg[1], arg[2]);
end);
InstallGlobalFunction(LeftRackNC, function(fam, gens)
return CloneOfTypeByGenerators(IsLeftRack, fam, gens,
GeneratorsOfLeftQuasigroup,
LeftRackByMultiplicationTableNC);
end);
InstallGlobalFunction(LeftQuandle, function(arg)
arg := ArgHelper@(arg);
CheckLQGprop@(arg[2]);
if not IsLSelfDistributive(arg[2]) then
Error("Left quandle must have left distributive generators");
fi;
if not IsElementwiseIdempotent(arg[2]) then
Error("Quandles must contain only idempotent elements");
fi;
return LeftQuandleNC(arg[1], arg[2]);
end);
InstallGlobalFunction(LeftQuandleNC, function(fam, gens)
return CloneOfTypeByGenerators(IsLeftQuandle, fam, gens,
GeneratorsOfLeftQuasigroup,
LeftQuandleByMultiplicationTableNC);
end);
InstallGlobalFunction(RightQuasigroup, function(arg)
arg := ArgHelper@(arg);
CheckRQGprop@(arg[2]);
return RightQuasigroupNC(arg[1], arg[2]);
end);
InstallGlobalFunction(RightQuasigroupNC, function(fam, gens)
return CloneOfTypeByGenerators(IsRightQuasigroup, fam, gens,
GeneratorsOfRightQuasigroup,
RightQuasigroupByMultiplicationTableNC);
end);
InstallGlobalFunction(RightRack, function(arg)
arg := ArgHelper@(arg);
CheckRQGprop@(arg[2]);
if not IsRSelfDistributive(arg[2]) then
Error("Right rack must have right distributive generators");
fi;
return RightRackNC(arg[1], arg[2]);
end);
InstallGlobalFunction(RightRackNC, function(fam, gens)
return CloneOfTypeByGenerators(IsRightRack, fam, gens,
GeneratorsOfRightQuasigroup,
RightRackByMultiplicationTableNC);
end);
InstallGlobalFunction(RightQuandle, function(arg)
arg := ArgHelper@(arg);
CheckRQGprop@(arg[2]);
if not IsRSelfDistributive(arg[2]) then
Error("Right quandle must have right distributive generators");
fi;
if not IsElementwiseIdempotent(arg[2]) then
Error("Quandles must contain only idempotent elements");
fi;
return RightQuandleNC(arg[1], arg[2]);
end);
InstallGlobalFunction(RightQuandleNC, function(fam, gens)
return CloneOfTypeByGenerators(IsRightQuandle, fam, gens,
GeneratorsOfRightQuasigroup,
RightQuandleByMultiplicationTableNC);
end);
## NOTE: If it is the case that the magma generated by the
## GeneratorsOf[Left|Right]Quasigroup is finite, then since the [left|right]
## multiplication is injective, it is also surjective on that set and in fact
## it is the whole quasigroup. However, it is not yet clear to me how best to
## capture this fact in GAP in a computationally useful way.
## View and print and such
LeftObjString@ := function(Q)
# Don't test distributivity if we haven't already
if HasIsLSelfDistributive(Q) and IsLeftRack(Q) then
if HasIsElementwiseIdempotent(Q) and IsElementwiseIdempotent(Q) then
return "LeftQuandle";
fi;
return "LeftRack";
fi;
return "LeftQuasigroup";
end;
RightObjString@ := function(Q)
# Don't test distributivity if we haven't already
if HasIsRSelfDistributive(Q) and IsRightRack(Q) then
if HasIsElementwiseIdempotent(Q) and IsElementwiseIdempotent(Q) then
return "RightQuandle";
fi;
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(PrintString, "for a left quasigroup",
[IsLeftQuasigroup], Q -> String(Q));
InstallMethod(PrintString, "for a right quasigroup",
[IsRightQuasigroup], Q -> String(Q));
InstallMethod(DisplayString, "for a left quasigroup",
[IsLeftQuasigroup], Q -> String(Q));
InstallMethod(DisplayString, "for a right 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)
# Don't test distributivity if we haven't already
if HasIsLSelfDistributive(Q) and IsLeftRack(Q) then
if HasIsElementwiseIdempotent(Q) and IsElementwiseIdempotent(Q) then
return "<left quandle";
fi;
return "<left rack";
fi;
return "<left quasigroup";
end;
RightObjView@ := function(Q)
# Don't test distributivity if we haven't already
if HasIsRSelfDistributive(Q) and IsRightRack(Q) then
if HasIsElementwiseIdempotent(Q) and IsElementwiseIdempotent(Q) then
return "<right quandle";
fi;
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 ",
String(Size(GeneratorsOfLeftQuasigroup(Q))),
" 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 ",
String(Size(GeneratorsOfRightQuasigroup(Q))),
" generators>"));