RAQ/gap/structure.gi

396 lines
13 KiB
Plaintext
Raw Normal View History

## structure.gi RAQ Implementation of definitiions, reps, and elt operations
## Create structures with generators
InstallGlobalFunction(CloneOfTypeByGenerators,
2017-10-18 20:00:02 +00:00
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
2017-10-18 11:25:13 +00:00
fam := arg[1];
Remove(arg, 1);
2017-10-18 11:25:13 +00:00
arg := Flat(arg);
else
2017-10-18 11:25:13 +00:00
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
2017-10-18 11:25:13 +00:00
fam := arg[1];
Remove(arg, 1);
2017-10-18 11:25:13 +00:00
arg := Flat(arg);
else
2017-10-18 11:25:13 +00:00
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
2017-10-18 11:25:13 +00:00
fam := arg[1];
Remove(arg, 1);
2017-10-18 11:25:13 +00:00
arg := Flat(arg);
else
2017-10-18 11:25:13 +00:00
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
2017-10-18 11:25:13 +00:00
fam := arg[1];
Remove(arg, 1);
2017-10-18 11:25:13 +00:00
arg := Flat(arg);
else
2017-10-18 11:25:13 +00:00
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;
2017-10-18 20:05:48 +00:00
return LeftRackByMultiplicationTableNC(T);
end);
2017-10-18 20:05:48 +00:00
InstallGlobalFunction(LeftRackByMultiplicationTableNC,
T -> MagmaByMultiplicationTableCreatorNC(T, LeftRack,
IsLeftQuotientElement and IsLSelfDistElement and
IsMagmaByMultiplicationTableObj
2017-10-18 20:05:48 +00:00
)
);
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
2017-10-18 20:05:48 +00:00
)
);
## 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);
2017-10-18 11:32:42 +00:00
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;
2017-10-18 20:16:56 +00:00
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
2017-10-18 20:18:38 +00:00
InstallMethod(IsLSelfDistributive, "for magma",
[IsMagma],
M -> IsLeftSelfDistributiveTable(MultiplicationTable(M))
);
2017-10-18 20:18:38 +00:00
InstallMethod(IsRSelfDistributive, "for magma",
[IsMagma],
M -> IsRightSelfDistributiveTable(MultiplicationTable(M))
);
2017-10-18 23:12:31 +00:00
## View and print and such
LeftObjString@ := function(Q)
if IsLeftRack(Q) then return "LeftRack"; fi;
2017-10-18 23:12:31 +00:00
return "LeftQuasigroup";
end;
RightObjString@ := function(Q)
if IsRightRack(Q) then return "RightRack"; fi;
2017-10-18 23:12:31 +00:00
return "RightQuasigroup";
end;
InstallMethod(String, "for a left quasigroup",
[IsLeftQuasigroup],
2017-10-18 23:22:48 +00:00
Q -> Concatenation(LeftObjString@(Q), "(...)"));
2017-10-18 23:12:31 +00:00
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],
2017-10-18 23:22:48 +00:00
Q -> Concatenation(RightObjString@(Q), "(...)"));
2017-10-18 23:12:31 +00:00
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)), " )"));
2017-10-18 23:30:57 +00:00
InstallMethod(DisplayString, "for a left quasigroup",
[IsLeftQuasigroup], Q -> String(Q));
InstallMethod(DisplayString, "for a rightt quasigroup",
[IsRightQuasigroup], Q -> String(Q));
2017-10-18 23:12:31 +00:00
InstallMethod(Display, "for a left quasigroup with multiplication table",
[IsLeftQuasigroup and HasMultiplicationTable],
function(Q)
Print(LeftObjString@(Q), " with ", Size(Q),
2017-10-18 23:12:31 +00:00
" 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),
2017-10-18 23:12:31 +00:00
" elements, generated by ",
GeneratorsOfRightQuasigroup(Q), ", with table\n");
Display(MultiplicationTable(Q));
end);
LeftObjView@ := function(Q)
if IsLeftRack(Q) then return "<left rack"; fi;
2017-10-18 23:12:31 +00:00
return "<left quasigroup";
end;
RightObjView@ := function(Q)
if IsRightRack(Q) then return "<right rack"; fi;
2017-10-18 23:12:31 +00:00
return "<right quasigroup";
end;
InstallMethod(ViewString, "for a left quasigroup",
[IsLeftQuasigroup],
2017-10-18 23:37:07 +00:00
Q -> Concatenation(LeftObjView@(Q), ">"));
2017-10-18 23:12:31 +00:00
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],
2017-10-18 23:37:07 +00:00
Q -> Concatenation(RightObjView@(Q), ">"));
2017-10-18 23:12:31 +00:00
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)))
);