## bytable.gi RAQ Implementation of racks etc. by multiplication tables. ## 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); InstallMethod(IsElementwiseIdempotentTable, "for matrix", [ IsMatrix ], T -> ForAll([1..Length(T)], i->(T[i,i]=i)) ); ## And a general principle: collections from finite families are finite. InstallMethod(IsFinite, "for any collection (with a finite element family)", [IsCollection], function(C) local ef; ef := ElementsFamily(FamilyObj(C)); if HasIsFinite(ef) and IsFinite(ef) then return true; fi; TryNextMethod(); return fail; end); ## And now create them from multiplication tables #First a helper function FiniteMagmaCreator@ := function(tbl, const, filts) local M; M := MagmaByMultiplicationTableCreatorNC( T, const, filts and IsMagmaByMultiplicationTableObj); SetIsFinite(ElementsFamily(FamilyObject(M))); return M; end; InstallGlobalFunction(LeftQuasigroupByMultiplicationTable, function(T) if not IsLeftQuasigroupTable(T) then Error("Multiplication table must have each row a permutation of ", "the same entries."); fi; return LeftQuasigroupByMultiplicationTableNC( CanonicalCayleyTableOfLeftQuasigroupTable(T)); end); InstallGlobalFunction(LeftQuasigroupByMultiplicationTableNC, T -> FiniteMagmaCreator@(T, LeftQuasigroupNC, IsLeftQuotientElement) ); InstallGlobalFunction(RightQuasigroupByMultiplicationTable, function(T) if not IsRightQuasigroupTable(T) then Error("Multiplication table must have each row a permutation of ", "the same entries."); fi; return RightQuasigroupByMultiplicationTableNC(CanonicalCayleyTable(T)); end); InstallGlobalFunction(RightQuasigroupByMultiplicationTableNC, T -> FiniteMagmaCreator@(T, RightQuasigroupNC, IsRightQuotientElement) ); InstallGlobalFunction(LeftRackByMultiplicationTable, function(T) if not IsLeftQuasigroupTable(T) then Error("Multiplication table must have each row a permutation of ", "the same entries."); fi; T := CanonicalCayleyTableOfLeftQuasigroupTable(T); if not IsLeftSelfDistributiveTable(T) then Error("Multiplication table must be left self distributive."); fi; return LeftRackByMultiplicationTableNC(T); end); InstallGlobalFunction(LeftRackByMultiplicationTableNC, T -> FiniteMagmaCreator@(T, LeftRackNC, IsLeftQuotientElement and IsLSelfDistElement) ); InstallGlobalFunction(LeftQuandleByMultiplicationTable, function(T) if not IsLeftQuasigroupTable(T) then Error("Multiplication table must have each row a permutation of ", "the same entries."); fi; T := CanonicalCayleyTableOfLeftQuasigroupTable(T); if not (IsLeftSelfDistributiveTable(T) and IsElementwiseIdempotentTable(T)) then Error("Multiplication table must be left self-dist and idempotent."); fi; return LeftQuandleByMultiplicationTableNC(T); end); InstallGlobalFunction(LeftQuandleByMultiplicationTableNC, T -> FiniteMagmaCreator@(T, LeftQuandleNC, IsLeftQuotientElement and IsLSelfDistElement and IsIdempotent) ); InstallGlobalFunction(RightRackByMultiplicationTable, function(T) if not IsRightQuasigroupTable(T) then Error("Multiplication table must have each column a permutation of ", "the same entries."); fi; T := CanonicalCayleyTable(T); if not IsRightSelfDistributiveTable(T) then Error("Multiplication table must be right self distributive."); fi; return RightRackByMultiplicationTableNC(T); end); InstallGlobalFunction(RightRackByMultiplicationTableNC, T -> FiniteMagmaCreator@(T, RightRackNC, IsRightQuotientElement and IsRSelfDistElement) ); InstallGlobalFunction(RightQuandleByMultiplicationTable, function(T) if not IsRightQuasigroupTable(T) then Error("Multiplication table must have each column a permutation of ", "the same entries."); fi; T := CanonicalCayleyTable(T); if not (IsRightSelfDistributiveTable(T) and IsElementwiseIdempotentTable(T)) then Error("Multiplication table must be right self-dist and idempotent."); fi; return RightQuandleByMultiplicationTableNC(T); end); InstallGlobalFunction(RightQuandleByMultiplicationTableNC, T -> FiniteMagmaCreator@(T, RightQuandleNC, IsRightQuotientElement and IsRSelfDistElement and IsIdempotent) ); ## 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/idempotence checkers for when need be InstallMethod(IsLSelfDistributive, "for collections with multiplication tables", [IsMultiplicativeElementCollection and HasMultiplicationTable], M -> IsLeftSelfDistributiveTable(MultiplicationTable(M)) ); InstallMethod(IsRSelfDistributive, "for collections with multiplication table", [IsMultiplicativeElementCollection and HasMultiplicationTable], M -> IsRightSelfDistributiveTable(MultiplicationTable(M)) ); ## 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); ## Property of a collection that its elements know their multiplication table InstallMethod(IsBuiltFromMultiplicationTable, "for a collection", [IsCollection], C -> HasMultiplicationTable(ElementsFamily(FamilyObj(C))) ); ## 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 and IsBuiltFromMultiplicationTable], L -> RightQuasigroupByMultiplicationTable( TransposedMat(MultiplicationTable(L)) ) ); InstallMethod(Opposite, "for left rack", [ IsLeftRack and IsBuiltFromMultiplicationTable], L -> RightRackByMultiplicationTableNC(TransposedMat(MultiplicationTable(L))) ); InstallMethod(Opposite, "for right quasigroup", [ IsRightQuasigroup and IsBuiltFromMultiplicationTable], L -> LeftQuasigroupByMultiplicationTable( TransposedMat(MultiplicationTable(L)) ) ); InstallMethod(Opposite, "for right rack", [ IsRightRack and IsBuiltFromMultiplicationTable], L -> LeftRackByMultiplicationTableNC(TransposedMat(MultiplicationTable(L))) );