diff git a/PackageInfo.g b/PackageInfo.g
index 0c19a9f..b73677c 100644
 a/PackageInfo.g
+++ b/PackageInfo.g
@@ 2,7 +2,7 @@ SetPackageInfo( rec(
PackageName := "RAQ",
Subtitle := "Racks And Quandles in GAP",
Version := "0.1.0",
 Date := "2018Oct1",
+ Date := "2018/10/01",
PackageWWWPrefix := Concatenation("http://code.studioinfinity.org/",
~.PackageName),
PackageWWWHome := Concatenation(~.PackageWWWPrefix, "/wiki"),
@@ 49,7 +49,7 @@ SetPackageInfo( rec(
"quasigroups, but more more particularly with racks and quandles. ",
"This package builds on fundamentals of nonassociative algebra ",
"established in the LOOPS package, and ",
 "and provides enhanced functionality, libraries, and implementations ",
+ "provides enhanced functionality, libraries, and implementations ",
"as compared to the earlier RIG package ",
"on which RAQ is generally modeled."
),
diff git a/README.md b/README.md
index caf7d3f..578164f 100644
 a/README.md
+++ b/README.md
@@ 8,7 +8,10 @@
#! @Chapter Introduction
#! @AutoDocPlainText >
The &RAQ; package provides a variety of facilities for constructing and
computing with onesided quasigroups, racks, and quandles in &GAP;.
+computing with onesided quasigroups, racks, and quandles in &GAP;. Highlights
+include:
+* Constructing quandles from operation tables, groups, or other quandles.
+* And more to come..
@@ 53,4 +56,12 @@ Note in particular that &RAQ; generally, unless otherwise specifically
requested, produces __left__ quandles and racks. (That is to say, quandles in
which for any fixed element $l$, the "leftmultiplication by $l$" operation
$x\mapsto l*x$ is a permutation of the quandle.)
+
+
+©right; 2018 by Glen Whitney.
+
+This package may be distributed under the terms and conditions of the GNU
+Public License version 3. See the LICENSE file in the package directory
+for details.
diff git a/doc/chapters.autodoc b/doc/chapters.autodoc
new file mode 100644
index 0000000..6f45f98
 /dev/null
+++ b/doc/chapters.autodoc
@@ 0,0 +1,11 @@
+@Chapter construct
+@ChapterTitle Constructing OneSided Quasigroups, Racks, and Quandles.
+
+@Chapter operate
+@ChapterTitle Operations on OneSided Quasigroups, Racks, and Quandles.
+
+@Chapter basic
+@ChapterTitle Basic Notions
+
+@Chapter technical
+@ChapterTitle Technical Details
diff git a/doc/makedoc.g b/doc/makedoc.g
index 706a238..ac66d4d 100644
 a/doc/makedoc.g
+++ b/doc/makedoc.g
@@ 3,7 +3,7 @@
LoadPackage("AutoDoc");
AutoDoc(rec(
 autodoc := rec(files := ["README.md"]),
+ autodoc := rec(files := ["README.md", "doc/chapters.autodoc"]),
maketest := rec(name := "tst/AutoDoc_tests.g")
));
QUIT;
diff git a/lib/structure.gd b/lib/structure.gd
index 425ea59..7443bf9 100644
 a/lib/structure.gd
+++ b/lib/structure.gd
@@ 2,7 +2,14 @@
## GAP Categories and representations
## Info class for RAQ
+#! @Chapter technical
+#! This chapter covers computational/operational aspects of &RAQ;
+#! rather than mathematical ones.
+#! @Section Messages
+#! @Description Controls the level of verbosity of &RAQ;'s informative
+#! messages. Use `SetInfoLevel` to set it to 0 to quiet &RAQ;
+#! entirely, or to values greater than 1 to yield more details of &RAQ;'s
+#! internal algorithms.
DeclareInfoClass("InfoRAQ");
## Selfdistributivity
@@ 14,63 +21,146 @@ DeclareInfoClass("InfoRAQ");
# (cf. https://arxiv.org/abs/0910.4760). Hence, we implement them in RAQ with
# new, nonconflicting terms.
# An element that knows that multiplication in its family is left
# selfdistributive:
+#! @Chapter basic
+#! In order to build up and define onesided quasigroups, racks, and
+#! quandles, &RAQ; must define several lowerlevel objects and properties,
+#! which are documented in this section. Although logically they come before
+#! the domain constructors and operations, they are presented afterwards
+#! because it's rare that one needs to use them directly when working with
+#! &RAQ;.
+#! @Section elements
+#! @SectionTitle Categories of elements
+#! @Description An element x with the property
+#! that for all elements y and z in its family, x*(y*z) =
+#! (x*y)*(x*z).
DeclareCategory("IsLSelfDistElement", IsMultiplicativeElement);
+# Have to skip a line because of AutoDoc's convention on documenting
+# consecutive declarations.
DeclareCategoryCollections("IsLSelfDistElement");
# An element that knows that multiplication in its family is right
# selfdistributive:
+#! @Description An element x with the property
+#! that for all elements y and z in its family, (y*z)*x =
+#! (y*x)*(z*x).
DeclareCategory("IsRSelfDistElement", IsMultiplicativeElement);
+
DeclareCategoryCollections("IsRSelfDistElement");
# Left selfdistributive collections of elements:
+#! @Section collections
+#! @SectionTitle Categories of collections
+#! @Description A collection which satisfies the left selfdistributive
+#! property (see the description of
+#! [)
+#! for all triples of elements of the collection.
DeclareProperty("IsLSelfDistributive", IsMultiplicativeElementCollection);
InstallTrueMethod(IsLSelfDistributive, IsLSelfDistElementCollection);
# Right selfdistributive collections of elements:
+#! @Description A collection which satisfies the right selfdistributive
+#! property (see the description of
+#! ][)
+#! for all triples of elements of the collection.
DeclareProperty("IsRSelfDistributive", IsMultiplicativeElementCollection);
InstallTrueMethod(IsRSelfDistributive, IsRSelfDistElementCollection);
## Idempotence
# There is already a property IsIdempotent on elements, but to definw
+# There is already a property IsIdempotent on elements, but to define
# structures which will automatically be quandles we need a corresponding
# collections category:
DeclareCategoryCollections("IsIdempotent");
# Collections in which every element is idempotent
+#! @Description A collection in which every element x is
+#! **idempotent**, i.e. satisfies x*x=x.
DeclareProperty("IsElementwiseIdempotent", IsMultiplicativeElementCollection);
InstallTrueMethod(IsElementwiseIdempotent, IsIdempotentCollection);
## Left and right racks and quandles
+#! @Description Tests whether obj is a left rack, which by definition
+#! is precisely that obj is a left quasigroup (i.e.,
+#! IsLeftQuasigroup(obj), defined in the &LOOPS;
+#! package, is true) and is left selfdistributive
+#! (i.e., IsLSelfDistributive(obj) is true).
+#! @Arguments obj
+#! @ItemType Filt
DeclareSynonym("IsLeftRack", IsLeftQuasigroup and IsLSelfDistributive);
+#! @Description Tests whether obj is a right rack, by definition
+#! precisely that it is a right quasigroup and right selfdistributive.
+#! @Arguments obj
+#! @ItemType Filt
DeclareSynonym("IsRightRack", IsRightQuasigroup and IsRSelfDistributive);
+#! @Description Tests whether obj is a left quandle, which by definition
+#! is precisely that obj is a left rack (i.e.,
+#! IsLeftRack(obj) is true) and every element is idempotent
+#! (i.e., IsElementwiseIdempotent(obj) is true).
+#! @Arguments obj
+#! @ItemType Filt
DeclareSynonym("IsLeftQuandle", IsLeftRack and IsElementwiseIdempotent);
DeclareSynonym("IsRightQuandle", IsRightRack and IsElementwiseIdempotent);
## Onesided quasigroups and racks and quandles by generators
+#! @Description Tests whether obj is a right quandle, by definition
+#! precisely that it is a right rack and every element is idempotent.
+#! @Arguments obj
+#! @ItemType Filt
+DeclareSynonym("IsRightQuandle", IsRightRack and IsElementwiseIdempotent);
# Returns the closure of under * and LeftQuotient;
# the family of elements of M may be specified, and must be if
# is empty (in which case M will be empty as well).
+#! @Chapter construct
+#! @Section from_scratch
+#! @SectionTitle Direct constructors
+#! All of the functions in this section produce magmas (of one of the
+#! categories with which &RAQ; is concerned) from data of other (nondomain)
+#! types.
+#! @BeginAutoDoc
+#! @BeginGroup basic_constructors
+#! @GroupTitle Basic constructors (from generators)
+#! @Description These are the fundamental constructors of these
+#! categories. They produce the closure of the specified generators,
+#! which are considered to be of the given family, under both the
+#! binary operation of the magma, which is always considered to be * in
+#! &RAQ;, and the quotient on the specified side. (If
+#! family is omitted, these functions attempt to infer it from the
+#! generators; if there are no generators then the
+#! family must be specified, and note that the resulting magma will
+#! be empty.) The resulting magma must satisfy the defining
+#! characteristics of the respective category: for the quasigroups, all
+#! quotients on the specified side must exist; racks must also satisfy the
+#! appropriate selfdistributive law; and quandles must also have every
+#! element idempotent.
+#! @Returns a magma of the named category
+#! @GroupInitialArguments [family], [generators]
DeclareGlobalFunction("LeftQuasigroup");
DeclareGlobalFunction("LeftQuasigroupNC");
DeclareGlobalFunction("RightQuasigroup");
DeclareGlobalFunction("RightQuasigroupNC");
DeclareGlobalFunction("LeftRack");
DeclareGlobalFunction("LeftRackNC");
DeclareGlobalFunction("RightRack");
DeclareGlobalFunction("RightRackNC");
DeclareGlobalFunction("LeftQuandle");
DeclareGlobalFunction("LeftQuandleNC");
DeclareGlobalFunction("RightQuandle");
+#! @EndGroup
+#! @BeginGroup unchecked_basic_constructors
+#! @GroupTitle Unchecked basic constructors
+#! @Description Each function is the same as its checked counterpart, but the
+#! family of elements must be specified and no checks that the
+#! appropriate axioms are satisfied are performed. They may be used for
+#! efficiency when those properties are guaranteed to be satisfied by the
+#! generators. NOTE that the behavior of &RAQ; is undefined if the
+#! unchecked versions are called on generators that do **not**
+#! satisfy the proper axioms.
+#! @Returns a magma of the named category
+#! @GroupInitialArguments family, generators
+DeclareGlobalFunction("LeftQuasigroupNC");
+DeclareGlobalFunction("RightQuasigroupNC");
+DeclareGlobalFunction("LeftRackNC");
+DeclareGlobalFunction("RightRackNC");
+DeclareGlobalFunction("LeftQuandleNC");
DeclareGlobalFunction("RightQuandleNC");
+#! @EndGroup
+#! @EndAutoDoc
# Underlying operation
DeclareGlobalFunction("CloneOfTypeByGenerators");
## Opposite structures
+#! @Section from_quasigroups
+#! @SectionTitle Constructors from other onesided quasigroups
+#! All of the functions in this section produce magmas from other objects of
+#! similar domain categories.
+
DeclareCategory("IsOppositeObject", IsMultiplicativeElement);
DeclareCategoryCollections("IsOppositeObject");
DeclareAttribute("OppositeFamily", IsFamily);
@@ 80,20 +170,44 @@ DeclareSynonym("IsDefaultOppositeObject",
DeclareAttribute("OppositeObj", IsMultiplicativeElement);
DeclareAttribute("UnderlyingMultiplicativeElement", IsOppositeObject);
+#! @Chapter operate
+#! @Section basic_info
+#! @SectionTitle Basic information
+
# Attributes for the generators
# Generates the structure by \* and LeftQuotient. Note that for finite
# structures, these are the same as the GeneratorsOfMagma but in general more
# elements might be required to generate the structure just under *
+#! @Arguments q
+#! @Returns list of elements generating q
+#! @Description This produces a list of elements that generate q by
+#! `\*` and `LeftQuotient`. There are no guarantees that the list is minimal
+#! in any respect. Note that for finite structures, the
+#! `GeneratorsOfMagma(q)` will suffice, but in general more
+#! elements might be required to generate the structure just under `\*`.
DeclareAttribute("GeneratorsOfLeftQuasigroup", IsLeftQuasigroup);
# Generates the structure by \* and \/, same considerations as above
+#! @Arguments q
+#! @Returns list of elements generating q
+#! @Description This produces a list of elements that generate q by
+#! `\*` and `\/`, with the same caveats as above.
DeclareAttribute("GeneratorsOfRightQuasigroup", IsRightQuasigroup);
## Conversions into quasigroup/rack/quandle
+#! @Chapter construct
+#! @Section from_scratch
+#! @BeginAutoDoc
+#! @BeginGroup conversions
+#! @GroupTitle Conversions
+#! @Description These functions convert a potentially arbitrary
+#! collection of elements to one of the categories of objects with
+#! which &RAQ; is concerned. The collection must be closed under *
+#! and satisfy the appropriate axioms for the conversion to succeed.
+#! @Returns a magma of the named category
+#! @GroupInitialArguments collection
DeclareAttribute("AsLeftQuasigroup", IsCollection);
DeclareAttribute("AsLeftRack", IsCollection);
DeclareAttribute("AsLeftQuandle", IsCollection);
DeclareAttribute("AsRightQuasigroup", IsCollection);
DeclareAttribute("AsRightRack", IsCollection);
DeclareAttribute("AsRightQuandle", IsCollection);
+#! @EndGroup
+#! @EndAutoDoc
diff git a/lib/structure.gi b/lib/structure.gi
index c6ad2f7..b7e5083 100644
 a/lib/structure.gi
+++ b/lib/structure.gi
@@ 489,7 +489,23 @@ OppHelper@ := function(Q, whichgens, cnstr)
return opp;
end;

+#! @Chapter construct
+#! @Section from_quasigroups
+#! @Arguments magma
+#! @ItemType Attr
+#! @Label for various finitelygenerated magmas
+#! @Description Given `q`, one of the structures covered in &RAQ;,
+#! `Opposite(q)` returns a structure which is just the same except the order
+#! of the operation is exactly reversed: `a*b` in the new structure means
+#! exactly what `b*a` did in the original structure. (This is the same
+#! operation as transposing the Cayley table.) Actually, this operation is
+#! originally defined in &LOOPS;, and it is extended in &RAQ; to onesided
+#! quasigroups, racks, and quandles. Moreover, since Opposite actually makes
+#! sense for an arbitrary magma, &RAQ; makes an effort to extend it to as
+#! wide a class of arguments as are easily implemented. Note for example
+#! Opposite has no effect on a commutative magma, and &RAQ;
+#! recognizes this fact.
+#! @Returns a magma of the same category
InstallMethod(Opposite, "for a left quasigroup",
[IsLeftQuasigroup and HasGeneratorsOfLeftQuasigroup],
Q > OppHelper@(Q, GeneratorsOfLeftQuasigroup, RightQuasigroupNC)
@@ 549,6 +565,15 @@ RoughJoinOfFilters@ := function(list, first)
return jof;
end;
+#! @ItemType Meth
+#! @Arguments listoffactors, distinguishedfactor
+#! @Returns a magma with only the structure common to all factors
+#! @Description Extends the `DirectProduct` operation to allow factors that
+#! are not even quasigroups, such as the onesided quasigroups, racks, and
+#! quandles with which &RAQ; is concerned. This direct product operation
+#! makes its best effort to find the most structured category for the result
+#! that it can, given that every factor in the product must lie in that
+#! category.
InstallOtherMethod(DirectProductOp, "for a list and nonquasigroup magma",
[IsList, IsMagma],
function (list, first)
@@ 669,18 +694,18 @@ end);
## Coversions among the structure types
InstallMethod(AsLeftQuasigroup, "for a left quasigroup",
+InstallMethod(AsLeftQuasigroup, "for a left quasigroup",
[IsLeftQuasigroup], IdFunc);
InstallMethod(AsLeftRack, "for a left rack",
+InstallMethod(AsLeftRack, "for a left rack",
[IsLeftRack], IdFunc);
InstallMethod(AsLeftQuandle, "for a left quandle",
+InstallMethod(AsLeftQuandle, "for a left quandle",
[IsLeftQuandle], IdFunc);
InstallMethod(AsRightQuasigroup, "for a right quasigroup",
+InstallMethod(AsRightQuasigroup, "for a right quasigroup",
[IsRightQuasigroup], IdFunc);
InstallMethod(AsRightRack, "for a right rack",
+InstallMethod(AsRightRack, "for a right rack",
[IsRightRack], IdFunc);
InstallMethod(AsRightQuandle, "for a left quandle",
 [IsLeftQuandle], IdFunc);
+InstallMethod(AsRightQuandle, "for a right quandle",
+ [IsRightQuandle], IdFunc);
AsAStructure@ := function(struc, D)
local T,S;
]