diff --git a/README.md b/README.md
index 578164f..cca8250 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,8 @@ Perhaps the following ⪆ interactive session, which constructs the
conjugation quandle of the symmetric group on three elements and then performs
a few simple computations on that quandle, will give the flavor of &RAQ;. (It is
presumed that the &RAQ; package has already been loaded with
-`LoadPackage("RAQ");` prior to these example commands being executed.)
+`LoadPackage("RAQ");` prior to these example commands being executed, and that
+remains true throughout the package documentation.)
```
gap> S3 := SymmetricGroup(3);
diff --git a/doc/chapters.autodoc b/doc/chapters.autodoc
index 6f45f98..d2618fe 100644
--- a/doc/chapters.autodoc
+++ b/doc/chapters.autodoc
@@ -1,11 +1,29 @@
@Chapter construct
@ChapterTitle Constructing One-Sided Quasigroups, Racks, and Quandles.
+@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 (non-domain)
+ types.
@Chapter operate
@ChapterTitle Operations on One-Sided Quasigroups, Racks, and Quandles.
@Chapter basic
@ChapterTitle Basic Notions
+ In order to build up and define one-sided quasigroups, racks, and
+ quandles, &RAQ; must define several lower-level 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
+@Section collections
+@SectionTitle Categories of collections
@Chapter technical
+ This chapter covers computational/operational aspects of &RAQ;
+ rather than mathematical ones.
+
@ChapterTitle Technical Details
diff --git a/doc/makedoc.g b/doc/makedoc.g
index ac66d4d..d376d73 100644
--- a/doc/makedoc.g
+++ b/doc/makedoc.g
@@ -3,7 +3,11 @@
LoadPackage("AutoDoc");
AutoDoc(rec(
- autodoc := rec(files := ["README.md", "doc/chapters.autodoc"]),
- maketest := rec(name := "tst/AutoDoc_tests.g")
+ autodoc := rec(files := ["README.md", "doc/chapters.autodoc"]),
+ maketest := rec(name := "tst/AutoDoc_tests.g")
));
-QUIT;
+
+if not IsBound(RAQ_makedoc_no_quit) or
+ not RAQ_makedoc_no_quit then
+ QUIT_GAP();
+fi;
diff --git a/lib/bytable.gd b/lib/bytable.gd
index b4a7946..54f68be 100644
--- a/lib/bytable.gd
+++ b/lib/bytable.gd
@@ -1,43 +1,192 @@
## bytable.gd RAQ Quasigroups, racks, and quandles by multiplication tables.
-## Self-distributivity
-# Predicates on tables:
+#! @Chapter basic
+#! @Section table_predicates
+#! @SectionTitle Predicates on multiplication tables
+#! @Arguments matrix
+#! @Description This property is true if matrix is the multiplication
+#! table of a magma which satisfies the left self-distributive property (see
+#! ))
+#! for all triples of elements.
DeclareProperty( "IsLeftSelfDistributiveTable", IsMatrix );
+#! @Arguments matrix
+#! @Description This property is true if matrix is the multiplication
+#! table of a magma which satisfies the rightt self-distributive property (see
+#! ))
+#! for all triples of elements.
DeclareProperty( "IsRightSelfDistributiveTable", IsMatrix );
+#! @Arguments matrix
+#! @Description This property is true if for all $i$ less than or equal to the
+#! number of rows of matrix, the $(i,i)$ entry of matrix is
+#! $i$.
DeclareProperty( "IsElementwiseIdempotentTable", IsMatrix );
-## Attributes (typically used on the families of elements created from a
-## multiplication table) to store sections and division tables
+#! @Chapter operate
+#! @Section table
+#! @Section Information related to the multiplication table.
+#! Note that typically the functions in this section will fail unless the
+#! argument was either created with a multiplication table, or at least has
+#! had its multiplication table explicitly computed.
+#! @Arguments obj
+#! @Returns a list of permutations of length equal to `Size(obj)`, or fail
+#! @Description The $i$th element of the list returned is the permutation
+#! determined by the $i$th row of the multiplication table of
+#! obj (in the sense of the core ⪆
+#! function `PermList`). Returns fail if any row of the multiplication table
+#! does not determine a permuation.
DeclareAttribute("LeftPerms", HasMultiplicationTable);
-DeclareAttribute("RightPerms", HasMultiplicationTable);
-DeclareAttribute("LeftDivisionTable", HasMultiplicationTable);
-DeclareAttribute("RightDivisionTable", HasMultiplicationTable);
+#! @BeginExampleSession
+#! gap> D3 := LeftQuandleByMultiplicationTable([[1,3,2],[3,2,1],[2,1,3]]);
+#!
+#! gap> LeftPerms(D3);
+#! [ (2,3), (1,3), (1,2) ]
+#! @EndExampleSession
-## Create Quasigroups and racks from multiplication tables
+#! @Arguments obj
+#! @Returns a list of permutations of length equal to `Size(obj)`, or fail
+#! @Description The $i$th element of the list returned is the permutation
+#! determined by the $i$th column of the multiplication table of
+#! obj (in the sense of the core ⪆
+#! function `PermList`). Returns fail if any column of the multiplication table
+#! does not determine a permuation.
+DeclareAttribute("RightPerms", HasMultiplicationTable);
+#! @Arguments obj
+#! @Returns an operation table matrix, or fail
+#! @Description Presuming it is well-defined, this produces the operation
+#! table (following similar conventions for multiplication tables, e.g.,
+#! every entry is a natural number less than `Size(obj)`) for `LeftQuotient`
+#! on the given obj. Returns fail if `LeftQuotient` is not
+#! well-defined for obj.
+DeclareAttribute("LeftDivisionTable", HasMultiplicationTable);
+#! @Arguments obj
+#! @Returns an operation table matrix, or fail
+#! @Description Presuming it is well-defined, this produces the operation
+#! table for `\/` (the typical elementwise (right) quotient) on the given
+#! obj. Returns fail if `\/` is not
+#! well-defined for obj.
+DeclareAttribute("RightDivisionTable", HasMultiplicationTable);
+#! @BeginExampleSession
+#! gap> A4 := RightQuandleByMultiplicationTable([[1,4,2,3],
+#! > [3,2,4,1],
+#! > [4,1,3,2],
+#! > [2,3,1,4]]);
+#!
+#! gap> RightDivisionTable(A4);
+#! [ [ 1, 3, 4, 2 ], [ 4, 2, 1, 3 ], [ 2, 4, 3, 1 ], [ 3, 1, 2, 4 ] ]
+#! @EndExampleSession
+#! @Chapter construct
+#! @Section from_scratch
+#! @BeginGroup table_constructors
+#! @GroupTitle Constructors from tables
+#! @Returns a magma of the designated category
+#! @Description These functions produce magmas from their multiplication
+#! tables, exactly analogously with the core ⪆ function
+#! `MagmaByMultiplicationTable` (q.v.); all of the same conventions are
+#! followed, such as the table should be an $n\times n$ matrix in which
+#! every entry is a natural number less than or equal to $n$. These
+#! functions verify that the tables supplied in fact define an example of
+#! the designated category.
+#! @GroupInitialArguments table
DeclareGlobalFunction("LeftQuasigroupByMultiplicationTable");
-DeclareGlobalFunction("LeftQuasigroupByMultiplicationTableNC");
DeclareGlobalFunction("LeftRackByMultiplicationTable");
-DeclareGlobalFunction("LeftRackByMultiplicationTableNC");
DeclareGlobalFunction("LeftQuandleByMultiplicationTable");
-DeclareGlobalFunction("LeftQuandleByMultiplicationTableNC");
DeclareGlobalFunction("RightQuasigroupByMultiplicationTable");
-DeclareGlobalFunction("RightQuasigroupByMultiplicationTableNC");
DeclareGlobalFunction("RightRackByMultiplicationTable");
-DeclareGlobalFunction("RightRackByMultiplicationTableNC");
DeclareGlobalFunction("RightQuandleByMultiplicationTable");
+#! @EndGroup
+
+#! @BeginExampleSession
+#! gap> D3 := LeftQuandleByMultiplicationTable([[1,3,2],[3,2,1],[2,1,3]]);
+#!
+#! gap> SpecifyElmNamePrefix(D3, "d");
+#! gap> Elements(D3);
+#! [ d1, d2, d3 ]
+#! gap> IsBound(d1);
+#! false
+#! gap> BindElmNames(D3);
+#! gap> d1 * d2;
+#! d3
+#! @EndExampleSession
+
+#! @BeginGroup unchecked_table_constructors
+#! @GroupTitle Unchecked constructors from tables
+#! @Returns a magma of the designated category
+#! @Description Each of these functions is exactly like its counterpart
+#! without the `NC` suffix, except that it does not perform any verification
+#! that the supplied table in fact satisfies the necessary axioms for the
+#! designated category. (The verification is skipped to save computation
+#! time, for use in cases when the properties are known to hold.) Hence, use
+#! with caution: the behavior of this
+#! package if you supply a table which does not satisfy the appropiate
+#! axioms is undefined.
+#! @GroupInitialArguments table
+DeclareGlobalFunction("LeftQuasigroupByMultiplicationTableNC");
+DeclareGlobalFunction("LeftRackByMultiplicationTableNC");
+DeclareGlobalFunction("LeftQuandleByMultiplicationTableNC");
+DeclareGlobalFunction("RightQuasigroupByMultiplicationTableNC");
+DeclareGlobalFunction("RightRackByMultiplicationTableNC");
DeclareGlobalFunction("RightQuandleByMultiplicationTableNC");
+#! @EndGroup
## Property of a collection that its elements know their multiplication table
+#! @Chapter technical
+#! @Section reps
+#! @SectionTitle Representational issues
+#! @Arguments collection
+#! @Description True if the family of the elements in the collection possesses
+#! a global multiplication table. This value is used to control whether more
+#! efficient algorithms are used in particular cases.
DeclareProperty("IsBuiltFromMultiplicationTable", IsCollection);
## Create quasigroups etc by permutations
+#! @Chapter construct
+#! @Section from_scratch
+#! @BeginGroup perms_constructors
+#! @GroupTitle Constructors from permutations
+#! @Returns a magma of the designated category
+#! @Description These functions produce magmas from a sequence of
+#! permutations. That is to say, because all of the categories supported in
+#! &RAQ; are quasigroups on at least one side, either the left
+#! multiplicative action of an element on the magma is always a permutation
+#! (in the case of left quasigroups) or the right multiplicative action of
+#! an element on the magma is always a permutation. Hence, a magma in these
+#! categories can always be specified by a list of $n$ permutations on
+#! the natural numbers less than or equal to $n$ (i.e., ordinary ⪆
+#! permutations) and that's what these
+#! functions do. In effect, the argument to the `Left` functions gives the
+#! rows of the multiplication table (as permutation objects), and the to the
+#! `Right` functions gives the columns.
+#! @GroupInitialArguments permutation-list
DeclareGlobalFunction("LeftQuasigroupByPerms");
DeclareGlobalFunction("LeftRackByPerms");
-DeclareGlobalFunction("LeftRackByPermsNC");
DeclareGlobalFunction("LeftQuandleByPerms");
-DeclareGlobalFunction("LeftQuandleByPermsNC");
DeclareGlobalFunction("RightQuasigroupByPerms");
DeclareGlobalFunction("RightRackByPerms");
-DeclareGlobalFunction("RightRackByPermsNC");
DeclareGlobalFunction("RightQuandleByPerms");
+#! @EndGroup
+
+#! @BeginExampleSession
+#! gap> D3 := LeftQuandleByPerms( [ (2,3), (1,3), (1,2) ] );
+#!
+#! gap> SpecifyElmNamePrefix(D3, "p");
+#! gap> BindElmNames(D3);
+#! gap> p2*p3;
+#! p1
+#! @EndExampleSession
+
+#! @BeginGroup unchecked_perms_constructors
+#! @GroupTitle Unchecked constructors from permutations
+#! @Returns a magma of the designated category
+#! @Description These functions are exactly the same as their counterparts
+#! without `NC` except that to save time they do not verify that the given
+#! permutations satisfy the appropriate axioms. Hence use caution, as
+#! supplying a list of permutations which does not form the proper structure
+#! can lead to undefined behavior. Note that there are no unchecked versions
+#! for the bare quasigroup constructors because the only properties required
+#! are that all of the rows (or columns, in the `Right` case) are permutations.
+#! @GroupInitialArguments permutation-list
+DeclareGlobalFunction("LeftRackByPermsNC");
+DeclareGlobalFunction("LeftQuandleByPermsNC");
+DeclareGlobalFunction("RightRackByPermsNC");
DeclareGlobalFunction("RightQuandleByPermsNC");
+#! @EndGroup
diff --git a/lib/structure.gd b/lib/structure.gd
index 7443bf9..d6fea78 100644
--- a/lib/structure.gd
+++ b/lib/structure.gd
@@ -3,8 +3,6 @@
## GAP Categories and representations
#! @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;
@@ -22,14 +20,7 @@ DeclareInfoClass("InfoRAQ");
# new, non-conflicting terms.
#! @Chapter basic
-#! In order to build up and define one-sided quasigroups, racks, and
-#! quandles, &RAQ; must define several lower-level 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).
@@ -46,7 +37,6 @@ DeclareCategory("IsRSelfDistElement", IsMultiplicativeElement);
DeclareCategoryCollections("IsRSelfDistElement");
#! @Section collections
-#! @SectionTitle Categories of collections
#! @Description A collection which satisfies the left self-distributive
#! property (see the description of
#! )
@@ -80,11 +70,13 @@ InstallTrueMethod(IsElementwiseIdempotent, IsIdempotentCollection);
#! (i.e., IsLSelfDistributive(obj) is true).
#! @Arguments obj
#! @ItemType Filt
+#! @Returns true or false
DeclareSynonym("IsLeftRack", IsLeftQuasigroup and IsLSelfDistributive);
#! @Description Tests whether obj is a right rack, by definition
#! precisely that it is a right quasigroup and right self-distributive.
#! @Arguments obj
#! @ItemType Filt
+#! @Returns true or false
DeclareSynonym("IsRightRack", IsRightQuasigroup and IsRSelfDistributive);
#! @Description Tests whether obj is a left quandle, which by definition
@@ -93,20 +85,18 @@ DeclareSynonym("IsRightRack", IsRightQuasigroup and IsRSelfDistributive);
#! (i.e., IsElementwiseIdempotent(obj) is true).
#! @Arguments obj
#! @ItemType Filt
+#! @Returns true or false
DeclareSynonym("IsLeftQuandle", IsLeftRack and IsElementwiseIdempotent);
#! @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
+#! @Returns true or false
DeclareSynonym("IsRightQuandle", IsRightRack and IsElementwiseIdempotent);
#! @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 (non-domain)
-#! types.
#! @BeginAutoDoc
#! @BeginGroup basic_constructors
#! @GroupTitle Basic constructors (from generators)
@@ -123,13 +113,13 @@ DeclareSynonym("IsRightQuandle", IsRightRack and IsElementwiseIdempotent);
#! quotients on the specified side must exist; racks must also satisfy the
#! appropriate self-distributive law; and quandles must also have every
#! element idempotent.
-#! @Returns a magma of the named category
+#! @Returns a magma of the designated category
#! @GroupInitialArguments [family], [generators]
DeclareGlobalFunction("LeftQuasigroup");
-DeclareGlobalFunction("RightQuasigroup");
DeclareGlobalFunction("LeftRack");
-DeclareGlobalFunction("RightRack");
DeclareGlobalFunction("LeftQuandle");
+DeclareGlobalFunction("RightQuasigroup");
+DeclareGlobalFunction("RightRack");
DeclareGlobalFunction("RightQuandle");
#! @EndGroup
#! @BeginGroup unchecked_basic_constructors
@@ -144,10 +134,10 @@ DeclareGlobalFunction("RightQuandle");
#! @Returns a magma of the named category
#! @GroupInitialArguments family, generators
DeclareGlobalFunction("LeftQuasigroupNC");
-DeclareGlobalFunction("RightQuasigroupNC");
DeclareGlobalFunction("LeftRackNC");
-DeclareGlobalFunction("RightRackNC");
DeclareGlobalFunction("LeftQuandleNC");
+DeclareGlobalFunction("RightQuasigroupNC");
+DeclareGlobalFunction("RightRackNC");
DeclareGlobalFunction("RightQuandleNC");
#! @EndGroup
#! @EndAutoDoc
diff --git a/tst/testall.g b/tst/testall.g
index f4ddfe1..c43f902 100644
--- a/tst/testall.g
+++ b/tst/testall.g
@@ -9,6 +9,15 @@ TestDirectory(tst_path,
testOptions := rec(compareFunction := "uptowhitespace"))
);
+# Now make sure the manual tests are up to date
+
+doc_path := DirectoriesPackageLibrary("RAQ", "doc");
+makedoc_file := Filename(doc_path, "makedoc.g");
+
+RAQ_makedoc_no_quit := true;
+Info(InfoRAQ, 1, "Generating RAQ documentation..\n\n");
+Read(makedoc_file);
+
auto_file := Filename(tst_path, "AutoDoc_tests.g");
if auto_file <> fail then