RAQ, a GAP System package for Racks And Quandles.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

#### 456 lines 14 KiB Raw Blame History

 `## 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` `MagmaNumber@ := 1;` `MagmaLetters@ := "VABCDEFGHJKMNPSTU";` `MagmaBase@ := Length(MagmaLetters@);` `NextMagmaString@ := function(filts)` ` local str, n;` ` str := "l";` ` if not "IsLeftQuotientElement" in NamesFilter(filts) then` ` str := "r";` ` fi;` ` n := MagmaNumber@;` ` MagmaNumber@ := MagmaNumber@ + 1;` ` while n > 0 do` ` Add(str, MagmaLetters@[RemInt(n, MagmaBase@) + 1]);` ` n := QuoInt(n, MagmaBase@);` ` od;` ` return str;` `end;` ``` ``` `FiniteMagmaCreator@ := function(tbl, cnstr, filts)` ` local M;` ` M := MagmaByMultiplicationTableCreatorNC(` ` tbl, cnstr, filts and IsMagmaByMultiplicationTableObj);` ` # Is there such a thing as a non-finite table in GAP? Anyhow...` ` SetIsFinite(ElementsFamily(FamilyObj(M)), IsFinite(tbl));` ` SpecifyElmNamePrefix(M, NextMagmaString@(filts));` ` 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)` `);` ``` ``` `## Creators from permutations` `InstallGlobalFunction(LeftQuasigroupByPerms,` ` function(perms)` ` local Q;` ` Q := LeftQuasigroupByMultiplicationTableNC(` ` CayleyTableByPerms(perms, [1..Length(perms)]));` ` SetLeftPerms(Q, perms);` ` return Q;` `end);` ``` ``` `InstallGlobalFunction(LeftRackByPerms,` ` function(perms)` ` local Q;` ` Q := LeftRackByMultiplicationTable(` ` CayleyTableByPerms(perms, [1..Length(perms)]));` ` SetLeftPerms(Q, perms);` ` return Q;` `end);` ``` ``` `InstallGlobalFunction(LeftRackByPermsNC,` ` function(perms)` ` local Q;` ` Q := LeftRackByMultiplicationTableNC(` ` CayleyTableByPerms(perms, [1..Length(perms)]));` ` SetLeftPerms(Q, perms);` ` return Q;` `end);` ` ` `InstallGlobalFunction(LeftQuandleByPerms,` ` function(perms)` ` local Q;` ` Q := LeftQuandleByMultiplicationTable(` ` CayleyTableByPerms(perms, [1..Length(perms)]));` ` SetLeftPerms(Q, perms);` ` return Q;` `end);` ``` ``` `InstallGlobalFunction(LeftQuandleByPermsNC,` ` function(perms)` ` local Q;` ` Q := LeftQuandleByMultiplicationTableNC(` ` CayleyTableByPerms(perms, [1..Length(perms)]));` ` SetLeftPerms(Q, perms);` ` return Q;` `end);` ``` ``` `InstallGlobalFunction(RightQuasigroupByPerms,` ` function(perms)` ` local Q;` ` Q := RightQuasigroupByMultiplicationTableNC(` ` TransposedMat(` ` CayleyTableByPerms(perms, [1..Length(perms)])));` ` SetRightPerms(Q, perms);` ` return Q;` `end);` ``` ``` `InstallGlobalFunction(RightRackByPerms,` ` function(perms)` ` local Q;` ` Q := RightRackByMultiplicationTable(` ` TransposedMat(` ` CayleyTableByPerms(perms, [1..Length(perms)])));` ` SetRightPerms(Q, perms);` ` return Q;` `end);` ``` ``` `InstallGlobalFunction(RightRackByPermsNC,` ` function(perms)` ` local Q;` ` Q := RightRackByMultiplicationTableNC(` ` TransposedMat(` ` CayleyTableByPerms(perms, [1..Length(perms)])));` ` SetRightPerms(Q, perms);` ` return Q;` `end);` ` ` `InstallGlobalFunction(RightQuandleByPerms,` ` function(perms)` ` local Q;` ` Q := RightQuandleByMultiplicationTable(` ` TransposedMat(` ` CayleyTableByPerms(perms, [1..Length(perms)])));` ` SetRightPerms(Q, perms);` ` return Q;` `end);` ``` ``` `InstallGlobalFunction(RightQuandleByPermsNC,` ` function(perms)` ` local Q;` ` Q := RightQuandleByMultiplicationTableNC(` ` TransposedMat(` ` CayleyTableByPerms(perms, [1..Length(perms)])));` ` SetRightPerms(Q, perms);` ` return Q;` `end);` ``` ``` `## 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` `InstallImmediateMethod(IsBuiltFromMultiplicationTable,` ` IsCollection, 1,` ` 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)))` `);` ``` ``` `# Note that opposite of quandles seems to come for free from above, which is` `# good.` ``` ``` `## Direct products` `# As in the case of general one-sided quasigroups, this implementation should` `# only be called with a second-argument collection which is not a group or` `# quasigroup.` `InstallOtherMethod(DirectProductOp, ` ` "for a list and non-quasigroup magma built from multiplication table",` ` [IsList, IsMagma and IsBuiltFromMultiplicationTable],` ` function (list, first)` ` local n, item, i, jof, bigtable;` ` n := Length(list);` ` # Simple checks` ` if n < 1 then` ` Error("Usage: Cannot take DirectProduct of zero items.");` ` elif n < 2 then` ` return list[1];` ` fi;` ` # See if we can handle all objects` ` for i in [2..n] do` ` if not HasMultiplicationTable(list[i]) then` ` return DirectProductOp(Permuted(list, (1,i)), list[i]);` ` fi;` ` od;` ` # OK, safe to take everyone's multiplication table.` ` # So go ahead and make the big thing` ` bigtable := ProductTableOfCanonicalCayleyTables(` ` List(list, MultiplicationTable));` ` # But we have to figure out what to do with it.` ` jof := RoughJoinOfFilters@(list, first);` ` # Dispatch modeled after the general one` ` if "IsMagmaWithOne" in jof then` ` if "IsMonoid" in jof then` ` return MonoidByMultiplicationTable(bigtable);` ` fi;` ` return MagmaWithOneByMultiplicationTable(bigtable);` ` fi;` ` if "IsAssociative" in jof then` ` return SemigroupByMultiplicationTable(bigtable);` ` elif "IsLeftQuasigroup" in jof then` ` if "IsLSelfDistributive" in jof then` ` if "IsElementwiseIdempotent" in jof then` ` return LeftQuandleByMultiplicationTableNC(bigtable);` ` fi;` ` return LeftRackByMultiplicationTableNC(bigtable);` ` fi;` ` return LeftQuasigroupByMultiplicationTableNC(bigtable);` ` elif "IsRightQuasigroup" in jof then` ` if "IsRSelfDistributive" in jof then` ` if "IsElementwiseIdempotent" in jof then` ` return RightQuandleByMultiplicationTableNC(bigtable);` ` fi;` ` return RightRackByMultiplicationTableNC(bigtable);` ` fi;` ` return RightQuasigroupByMultiplicationTableNC(bigtable);` ` fi;` ` return MagmaByMultiplicationTable(bigtable);` ```end); ``` ``` ```