From 5717e17a010ead93400e522b69a422960ea7dbef Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Wed, 7 Oct 2026 08:34:23 +0100 Subject: [PATCH] Add a presentation for the Grammic monoid Implement grammic_monoid_LXZ26 and the default grammic_monoid helper using the Knuth relations and the additional relations of Luo, Xie, and Zhang. Document the presentation and cover its boundary cases and plactic quotient. AI assistance: OpenAI Codex researched the presentation and prepared the implementation, documentation, tests, and commit message. Co-authored-by: Codex --- docs/libsemigroups.bib | 12 ++++ .../libsemigroups/presentation-examples.hpp | 31 +++++++++ src/presentation-examples.cpp | 19 ++++++ tests/test-presentation-examples-2.cpp | 67 +++++++++++++++++++ 4 files changed, 129 insertions(+) diff --git a/docs/libsemigroups.bib b/docs/libsemigroups.bib index 767d62aa7..7d0cdc276 100644 --- a/docs/libsemigroups.bib +++ b/docs/libsemigroups.bib @@ -5,6 +5,18 @@ %% Saved with string encoding Unicode (UTF-8) +@article{Luo2026aa, + author = {Luo, Yan Feng and Xie, Jia Jia and Zhang, Wen Ting}, + title = {A presentation of the grammic monoid}, + journal = {Semigroup Forum}, + volume = {113}, + number = {2}, + pages = {575--593}, + year = {2026}, + doi = {10.1007/s00233-026-10671-1}, + url = {https://doi.org/10.1007/s00233-026-10671-1} +} + @misc{Hivert2026aa, author = {Hivert, Florent and Scott, Jeanne}, title = {Diagrammatic {Okada} monoid and cellularity of the {Okada} algebra}, diff --git a/include/libsemigroups/presentation-examples.hpp b/include/libsemigroups/presentation-examples.hpp index 33bd2c6ab..4399922f7 100644 --- a/include/libsemigroups/presentation-examples.hpp +++ b/include/libsemigroups/presentation-examples.hpp @@ -55,6 +55,7 @@ namespace libsemigroups { Presentation dual_symmetric_inverse_monoid(size_t n); Presentation fibonacci_semigroup(size_t r, size_t n); Presentation full_transformation_monoid(size_t n); + Presentation grammic_monoid(size_t n); Presentation hypo_plactic_monoid(size_t n); Presentation monogenic_semigroup(size_t m, size_t r); Presentation motzkin_monoid(size_t n); @@ -336,6 +337,22 @@ namespace libsemigroups { [[nodiscard]] Presentation full_transformation_monoid_MW24_b(size_t n); + //! \brief A presentation for the grammic monoid. + //! + //! This function returns a monoid presentation defining the grammic monoid + //! with \p n generators, as in Theorem 3.17 of \cite Luo2026aa. + //! + //! This presentation consists of the Knuth relations from + //! \ref plactic_monoid_Knu70 together with \f$dbac = badc\f$ for all + //! \f$0 \leq a < b \leq c < d < n\f$. + //! + //! \param n the number of generators. + //! + //! \returns A value of type `Presentation`. + //! + //! \throws LibsemigroupsException if `n < 1`. + [[nodiscard]] Presentation grammic_monoid_LXZ26(size_t n); + //! \brief A presentation for the hypoplactic monoid. //! //! This function returns a presentation for the hypoplactic monoid with @@ -1019,6 +1036,20 @@ namespace libsemigroups { //! * `full_transformation_monoid_MW24_b`. [[nodiscard]] Presentation full_transformation_monoid(size_t n); + //! \copydoc grammic_monoid_LXZ26 + //! + //! \note + //! This function performs exactly the same as `grammic_monoid_LXZ26`, + //! and exists as a convenience function for when a presentation for the + //! grammic monoid is required, but the relations of the presentation are + //! not important. + //! + //! \sa + //! `grammic_monoid_LXZ26`. + [[nodiscard]] inline Presentation grammic_monoid(size_t n) { + return grammic_monoid_LXZ26(n); + } + //! \copydoc hypo_plactic_monoid_Nov00 //! //! \note diff --git a/src/presentation-examples.cpp b/src/presentation-examples.cpp index dfccb4943..319ab1302 100644 --- a/src/presentation-examples.cpp +++ b/src/presentation-examples.cpp @@ -456,6 +456,25 @@ namespace libsemigroups { return p; } + // Theorem 3.17 of https://doi.org/10.1007/s00233-026-10671-1. + Presentation grammic_monoid_LXZ26(size_t n) { + auto p = plactic_monoid_Knu70(n); + p.contains_empty_word(true); + // Use dbac = badc as in the abstract; the Knuth relations identify + // badc and bdac, the right-hand side used in Equation (3.3). + for (size_t d = 2; d < n; ++d) { + for (size_t c = 1; c < d; ++c) { + for (size_t b = 1; b <= c; ++b) { + for (size_t a = 0; a < b; ++a) { + presentation::add_rule_no_checks( + p, word_type({d, b, a, c}), word_type({b, a, d, c})); + } + } + } + } + return p; + } + Presentation catalan_monoid_Sol96(size_t n) { if (n < 1) { LIBSEMIGROUPS_EXCEPTION( diff --git a/tests/test-presentation-examples-2.cpp b/tests/test-presentation-examples-2.cpp index e14b2d628..9fed1e0ea 100644 --- a/tests/test-presentation-examples-2.cpp +++ b/tests/test-presentation-examples-2.cpp @@ -320,4 +320,71 @@ namespace libsemigroups { REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); } + LIBSEMIGROUPS_TEST_CASE("Example", + "110", + "grammic_monoid arguments and small ranks", + "[quick][presentation-examples]") { + REQUIRE_THROWS_AS(grammic_monoid(0), LibsemigroupsException); + REQUIRE_THROWS_AS(grammic_monoid_LXZ26(0), LibsemigroupsException); + + auto p = grammic_monoid(1); + REQUIRE(p.alphabet() == 0_w); + REQUIRE(p.rules.empty()); + REQUIRE(p.contains_empty_word()); + REQUIRE(grammic_monoid(2) == plactic_monoid(2)); + + for (size_t n = 1; n <= 6; ++n) { + p = grammic_monoid(n); + REQUIRE(p == grammic_monoid_LXZ26(n)); + REQUIRE(p.alphabet().size() == n); + REQUIRE(p.contains_empty_word()); + REQUIRE_NOTHROW(p.throw_if_bad_alphabet_or_rules()); + } + } + + LIBSEMIGROUPS_TEST_CASE("Example", + "111", + "grammic_monoid(3) is a proper plactic quotient", + "[quick][presentation-examples]") { + auto rg = ReportGuard(false); + auto p = grammic_monoid(3); + REQUIRE(p.rules.size() == 18); + KnuthBendix kb(congruence_kind::twosided, p); + REQUIRE(is_obviously_infinite(kb)); + REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); + // The b = c case: cbab = bacb, equivalently cbab = bcab. + REQUIRE(knuth_bendix::contains(kb, 2101_w, 1021_w)); + REQUIRE(knuth_bendix::contains(kb, 2101_w, 1201_w)); + REQUIRE(!knuth_bendix::contains(kb, 01_w, 10_w)); + REQUIRE(!knuth_bendix::contains(kb, 0_w, 00_w)); + REQUIRE(knuth_bendix::normal_forms(kb).min(4).max(4).count() == 38); + + KnuthBendix plactic(congruence_kind::twosided, plactic_monoid(3)); + REQUIRE(!knuth_bendix::contains(plactic, 2101_w, 1021_w)); + } + + LIBSEMIGROUPS_TEST_CASE("Example", + "112", + "grammic_monoid relations for larger ranks", + "[quick][presentation-examples]") { + auto p = grammic_monoid(4); + auto expected = plactic_monoid(4).rules; + // All five instances of dbac = badc with a < b <= c < d. + expected.insert(expected.end(), + {2101_w, + 1021_w, + 3101_w, + 1031_w, + 3102_w, + 1032_w, + 3202_w, + 2032_w, + 3212_w, + 2132_w}); + REQUIRE(p.rules == expected); + // There are binomial(n + 1, 4) extra relations. + REQUIRE(grammic_monoid(5).rules.size() == 110); + REQUIRE(grammic_monoid(6).rules.size() == 210); + } + } // namespace libsemigroups