From 7b1aac174fa5e9192156173ab3e95961138267c9 Mon Sep 17 00:00:00 2001 From: Murray Whyte <42549861+MTWhyte@users.noreply.github.com> Date: Wed, 28 Sep 2022 09:42:15 +0100 Subject: [PATCH] Add `FullTransformationMonoid` and `PartialTransformationMonoid` presentations (#371) * Update relations * Add relation that e_12 is idempotent (missing from book) * Add test using presentation * Add relations from full transformation monoid * Perform error checking and formatting * Increase degree for ToddCoxeter tests * Fix errors * Change test tags * Add extreme test * Improve lambda functions * Perform formatting * Fix compilation warning * Add extreme test * Intermediate progress: things work * Sort author value * Change Aizenstat to Sutov, for partial transformation monoid * Move function to correct unnamed namespace * Add suggestion to self * Add comment for function * Formatting * Improve comment consistency * Remove FIXME comment * Fixup per James's review * Change not for exclamation mark * Fix bracket * Perform formatting * Update Sims1 test Co-authored-by: Murray Whyte --- tests/fpsemi-examples.cpp | 186 +++++++++++++++++++++++++++------- tests/fpsemi-examples.hpp | 12 ++- tests/test-knuth-bendix-6.cpp | 87 ++++++++++++++++ tests/test-sims1.cpp | 4 +- tests/test-todd-coxeter.cpp | 54 ++++++++++ 5 files changed, 304 insertions(+), 39 deletions(-) diff --git a/tests/fpsemi-examples.cpp b/tests/fpsemi-examples.cpp index 70915650b..c5fed4c10 100644 --- a/tests/fpsemi-examples.cpp +++ b/tests/fpsemi-examples.cpp @@ -99,6 +99,112 @@ namespace libsemigroups { } } } + void add_iwahori_full_transformation_monoid_relations( + std::vector& result, + size_t n, + size_t m) { + // This function adds the full transformation monoid relations due to + // Iwahori, from Section 9.3, p161-162, (Ganyushkin + Mazorchuk), + // expressed in terms of the generating set {pi_2, ..., pi_n, + // epsilon_{12}} using the notation of that chapter. + // https://link.springer.com/book/10.1007/978-1-84800-281-4 + + // The argument m specifies the letter value the idempotent e12 + // corresponds to. When adding these relations for the full transformation + // monoid presentation, we want m = n - 1. For the partial transformation + // monoid presentation, we want m = n. + + // It is useful to have this as a separate function, to avoid computing + // duplicate presentations for the underlying symmetric group, when + // combining relations from the symmetric inverse and full transformation + // monoids. + + word_type e12 = {m}; + std::vector pi; + for (size_t i = 0; i <= n - 2; ++i) { + pi.push_back({i}); + } + + // The following expresses the epsilon idempotents in terms of the + // generating set + auto eps = [&e12, &pi](size_t i, size_t j) -> word_type { + LIBSEMIGROUPS_ASSERT(i != j); + if (i == 1 && j == 2) { + return e12; + } else if (i == 2 && j == 1) { + return pi[0] * e12 * pi[0]; + } else if (i == 1) { + return pi[0] * pi[j - 2] * pi[0] * e12 * pi[0] * pi[j - 2] * pi[0]; + } else if (j == 2) { + return pi[i - 2] * e12 * pi[i - 2]; + } else if (j == 1) { + return pi[0] * pi[i - 2] * e12 * pi[i - 2] * pi[0]; + } else if (i == 2) { + return pi[j - 2] * pi[0] * e12 * pi[0] * pi[j - 2]; + } + return pi[i - 2] * pi[0] * pi[j - 2] * pi[0] * e12 * pi[0] * pi[j - 2] + * pi[0] * pi[i - 2]; + }; + + auto transp = [&pi](size_t i, size_t j) -> word_type { + LIBSEMIGROUPS_ASSERT(i != j); + if (i > j) { + std::swap(i, j); + } + if (i == 1) { + return pi[j - 2]; + } + return pi[i - 2] * pi[j - 2] * pi[i - 2]; + }; + + // Relations a + for (size_t i = 1; i <= n; ++i) { + for (size_t j = 1; j <= n; ++j) { + if (j == i) { + continue; + } + // Relations (k) + result.emplace_back(transp(i, j) * eps(i, j), eps(i, j)); + // Relations (j) + result.emplace_back(eps(j, i) * eps(i, j), eps(i, j)); + // Relations (i) + result.emplace_back(eps(i, j) * eps(i, j), eps(i, j)); + // Relations (d) + result.emplace_back(transp(i, j) * eps(i, j) * transp(i, j), + eps(j, i)); + for (size_t k = 1; k <= n; ++k) { + if (k == i || k == j) { + continue; + } + // Relations (h) + result.emplace_back(eps(k, j) * eps(i, j), eps(k, j)); + // Relations (g) + result.emplace_back(eps(k, i) * eps(i, j), + transp(i, j) * eps(k, j)); + // Relations (f) + result.emplace_back(eps(j, k) * eps(i, j), eps(i, j) * eps(i, k)); + result.emplace_back(eps(j, k) * eps(i, j), eps(i, k) * eps(i, j)); + // Relations (c) + result.emplace_back(transp(k, i) * eps(i, j) * transp(k, i), + eps(k, j)); + // Relations (b) + result.emplace_back(transp(j, k) * eps(i, j) * transp(j, k), + eps(i, k)); + for (size_t l = 1; l <= n; ++l) { + if (l == i || l == j || l == k) { + continue; + } + // Relations (e) + result.emplace_back(eps(l, k) * eps(i, j), eps(i, j) * eps(l, k)); + // Relations (a) + result.emplace_back(transp(k, l) * eps(i, j) * transp(k, l), + eps(i, j)); + } + } + } + } + } + } // namespace std::vector RookMonoid(size_t l, int q) { @@ -1092,34 +1198,45 @@ namespace libsemigroups { return result; } - // From Proposition 1.7 in https://bit.ly/3R5ZpKW - std::vector FullTransformationMonoidAizenstat(size_t n) { + std::vector FullTransformationMonoid(size_t n, author val) { if (n < 4) { LIBSEMIGROUPS_EXCEPTION( "the 1st argument (size_t) must be at least 4, found %llu", uint64_t(n)); } - auto result = SymmetricGroup1(n); + if (val == author::Aizenstat) { + // From Proposition 1.7 in https://bit.ly/3R5ZpKW + auto result = SymmetricGroup1(n); - word_type const a = {1}; - word_type const b = {2}; - word_type const t = {3}; + word_type const a = {1}; + word_type const b = {2}; + word_type const t = {3}; - result.emplace_back(a * t, t); - result.emplace_back( - (b ^ (n - 2)) * a * (b ^ 2) * t * (b ^ (n - 2)) * a * (b ^ 2), t); - result.emplace_back(b * a * (b ^ (n - 1)) * a * b * t * (b ^ (n - 1)) * a - * b * a * (b ^ (n - 1)), - t); - result.emplace_back((t * b * a * (b ^ (n - 1))) ^ 2, t); - result.emplace_back(((b ^ (n - 1)) * a * b * t) ^ 2, - t * (b ^ (n - 1)) * a * b * t); - - result.emplace_back((t * (b ^ (n - 1)) * a * b) ^ 2, - t * (b ^ (n - 1)) * a * b * t); - result.emplace_back((t * b * a * (b ^ (n - 2)) * a * b) ^ 2, - (b * a * (b ^ (n - 2)) * a * b * t) ^ 2); - return result; + result.emplace_back(a * t, t); + result.emplace_back( + (b ^ (n - 2)) * a * (b ^ 2) * t * (b ^ (n - 2)) * a * (b ^ 2), t); + result.emplace_back(b * a * (b ^ (n - 1)) * a * b * t * (b ^ (n - 1)) * a + * b * a * (b ^ (n - 1)), + t); + result.emplace_back((t * b * a * (b ^ (n - 1))) ^ 2, t); + result.emplace_back(((b ^ (n - 1)) * a * b * t) ^ 2, + t * (b ^ (n - 1)) * a * b * t); + + result.emplace_back((t * (b ^ (n - 1)) * a * b) ^ 2, + t * (b ^ (n - 1)) * a * b * t); + result.emplace_back((t * b * a * (b ^ (n - 2)) * a * b) ^ 2, + (b * a * (b ^ (n - 2)) * a * b * t) ^ 2); + return result; + } else if (val == author::Iwahori) { + // From Theorem 9.3.1, p161-162, (Ganyushkin + Mazorchuk) + // using Theorem 9.1.4 to express presentation in terms + // of the pi_i and e_12. + // https://link.springer.com/book/10.1007/978-1-84800-281-4 + auto result = SymmetricGroup(n, author::Carmichael); + add_iwahori_full_transformation_monoid_relations(result, n, n - 1); + return result; + } + LIBSEMIGROUPS_EXCEPTION("not yet implemented"); } std::vector PartialTransformationMonoid(size_t n, author val) { @@ -1172,18 +1289,20 @@ namespace libsemigroups { {{3, 1, 1, 2, 0}, {3, 1, 1, 2}}, {{3, 1, 1, 2, 1}, {3, 1, 0, 2}}, {{1, 2, 1, 2, 0, 2}, {2, 1, 2, 0, 2}}}; - } else if (n >= 4 && val == author::Aizenstat) { - LIBSEMIGROUPS_EXCEPTION("not yet implemented"); - // FIXME this is missing the relations from T_n + } else if (n >= 4 && val == author::Sutov) { // From Theorem 9.4.1, p169, (Ganyushkin + Mazorchuk) // https://link.springer.com/book/10.1007/978-1-84800-281-4 - auto result = SymmetricInverseMonoid(n, author::Sutov); - word_type e12 = {2 * n - 1}; - std::vector epsilon = {{n - 1}, {n}, {n + 1}}; - result.emplace_back(epsilon[1] * e12, e12); - result.emplace_back(e12 * epsilon[1], epsilon[1]); - result.emplace_back(epsilon[0] * e12, e12 * epsilon[0] * epsilon[1]); - result.emplace_back(epsilon[2] * e12, e12 * epsilon[2]); + auto result = SymmetricInverseMonoid(n, author::Sutov); + + add_iwahori_full_transformation_monoid_relations(result, n, n); + word_type e12 = {n}; + std::vector epsilon = {{n - 1}, {0, n - 1, 0}, {1, n - 1, 1}}; + result.emplace_back(e12 * epsilon[1], e12); + result.emplace_back(epsilon[1] * e12, epsilon[1]); + + result.emplace_back(e12 * epsilon[0], epsilon[1] * epsilon[0] * e12); + result.emplace_back(e12 * epsilon[2], epsilon[2] * e12); + return result; } LIBSEMIGROUPS_EXCEPTION("not yet implemented"); @@ -1218,7 +1337,6 @@ namespace libsemigroups { result.emplace_back(epsilon[1] * pi[k], pi[k] * epsilon[1]); result.emplace_back(epsilon[k + 1] * pi[0], pi[0] * epsilon[k + 1]); } - result.emplace_back(epsilon[1] * epsilon[0] * pi[0], epsilon[1] * epsilon[0]); return result; @@ -1227,11 +1345,9 @@ namespace libsemigroups { } // Chinese monoid - // See: The Chinese Monoid - Cassaigne, Espie, Krob, Novelli and Hivert, - // 2001 + // See: The Chinese Monoid - Cassaigne, Espie, Krob, Novelli and Hivert, 2001 std::vector ChineseMonoid(size_t n) { std::vector result; - for (size_t a = 0; a < n; a++) { for (size_t b = a; b < n; b++) { for (size_t c = b; c < n; c++) { diff --git a/tests/fpsemi-examples.hpp b/tests/fpsemi-examples.hpp index 3458642ec..55cb983f8 100644 --- a/tests/fpsemi-examples.hpp +++ b/tests/fpsemi-examples.hpp @@ -29,7 +29,15 @@ #include "libsemigroups/types.hpp" // for relation_type namespace libsemigroups { - enum class author { Machine, Aizenstat, Carmichael, East, Moore, Sutov }; + enum class author { + Machine, + Aizenstat, + Carmichael, + East, + Iwahori, + Moore, + Sutov + }; std::vector RookMonoid(size_t l, int q); @@ -56,7 +64,7 @@ namespace libsemigroups { std::vector TemperleyLieb(size_t n); std::vector Brauer(size_t n); std::vector RectangularBand(size_t m, size_t n); - std::vector FullTransformationMonoidAizenstat(size_t n); + std::vector FullTransformationMonoid(size_t n, author val); std::vector PartialTransformationMonoid(size_t n, author val); std::vector SymmetricInverseMonoid(size_t n, author val); diff --git a/tests/test-knuth-bendix-6.cpp b/tests/test-knuth-bendix-6.cpp index 4f7c37559..cbc7730ed 100644 --- a/tests/test-knuth-bendix-6.cpp +++ b/tests/test-knuth-bendix-6.cpp @@ -437,5 +437,92 @@ namespace libsemigroups { {{2, 2, 1}, {2, 1, 2}}})); REQUIRE(kb.knuth_bendix().number_of_normal_forms(0, 10) == 1175); } + + LIBSEMIGROUPS_TEST_CASE("KnuthBendix", + "083", + "(cong) PartialTransformationMonoid4", + "[standard][congruence][knuth-bendix][cong]") { + auto rg = ReportGuard(REPORT); + + size_t n = 4; + auto s = PartialTransformationMonoid(n, author::Sutov); + for (auto& rel : s) { + if (rel.first.empty()) { + rel.first = {n + 1}; + } + if (rel.second.empty()) { + rel.second = {n + 1}; + } + } + auto p = make>(s); + p.alphabet(n + 2); + presentation::add_identity_rules(p, n + 1); + + KnuthBendix kb; + kb.set_number_of_generators(n + 2); + for (size_t i = 0; i < p.rules.size() - 1; i += 2) { + kb.add_pair(p.rules[i], p.rules[i + 1]); + } + REQUIRE(!kb.is_quotient_obviously_infinite()); + REQUIRE(kb.number_of_classes() == 625); + } + + LIBSEMIGROUPS_TEST_CASE("KnuthBendix", + "118", + "(cong) PartialTransformationMonoid5", + "[extreme][congruence][knuth-bendix][cong]") { + auto rg = ReportGuard(REPORT); + + size_t n = 5; + auto s = PartialTransformationMonoid(n, author::Sutov); + for (auto& rel : s) { + if (rel.first.empty()) { + rel.first = {n + 1}; + } + if (rel.second.empty()) { + rel.second = {n + 1}; + } + } + auto p = make>(s); + p.alphabet(n + 2); + presentation::add_identity_rules(p, n + 1); + + KnuthBendix kb; + kb.set_number_of_generators(n + 2); + for (size_t i = 0; i < p.rules.size() - 1; i += 2) { + kb.add_pair(p.rules[i], p.rules[i + 1]); + } + REQUIRE(!kb.is_quotient_obviously_infinite()); + REQUIRE(kb.number_of_classes() == 7776); + } + + LIBSEMIGROUPS_TEST_CASE("KnuthBendix", + "119", + "(cong) FullTransformationMonoid Iwahori", + "[extreme][congruence][knuth-bendix][cong]") { + auto rg = ReportGuard(REPORT); + + size_t n = 5; + auto s = FullTransformationMonoid(n, author::Iwahori); + for (auto& rel : s) { + if (rel.first.empty()) { + rel.first = {n}; + } + if (rel.second.empty()) { + rel.second = {n}; + } + } + auto p = make>(s); + p.alphabet(n + 1); + presentation::add_identity_rules(p, n); + KnuthBendix kb; + kb.set_number_of_generators(n + 1); + for (size_t i = 0; i < p.rules.size() - 1; i += 2) { + kb.add_pair(p.rules[i], p.rules[i + 1]); + } + REQUIRE(!kb.is_quotient_obviously_infinite()); + REQUIRE(kb.number_of_classes() == 3125); + } + } // namespace congruence } // namespace libsemigroups diff --git a/tests/test-sims1.cpp b/tests/test-sims1.cpp index ca100cf23..b1f301caa 100644 --- a/tests/test-sims1.cpp +++ b/tests/test-sims1.cpp @@ -321,8 +321,8 @@ namespace libsemigroups { REQUIRE(S.size() == 256); auto p = make>(S); REQUIRE(p.rules.size() == 132); - auto q - = make>(FullTransformationMonoidAizenstat(4)); + auto q = make>( + FullTransformationMonoid(4, author::Aizenstat)); // q.rules.insert(q.rules.end(), p.rules.cbegin(), p.rules.cbegin() + 100); // Using this presentation makes this perform terribly slowly. diff --git a/tests/test-todd-coxeter.cpp b/tests/test-todd-coxeter.cpp index 9e6540608..c5d116937 100644 --- a/tests/test-todd-coxeter.cpp +++ b/tests/test-todd-coxeter.cpp @@ -2605,6 +2605,60 @@ namespace libsemigroups { } REQUIRE(tc.number_of_classes() == 1546); } + LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", + "114", + "PartialTransformationMonoid", + "[todd-coxeter][standard]") { + auto rg = ReportGuard(REPORT); + size_t n = 5; + auto s = PartialTransformationMonoid(n, author::Sutov); + for (auto& rel : s) { + if (rel.first.empty()) { + rel.first = {n + 1}; + } + if (rel.second.empty()) { + rel.second = {n + 1}; + } + } + auto p = make>(s); + p.alphabet(n + 2); + presentation::add_identity_rules(p, n + 1); + p.validate(); + + ToddCoxeter tc(congruence_kind::twosided); + tc.set_number_of_generators(n + 2); + for (size_t i = 0; i < p.rules.size() - 1; i += 2) { + tc.add_pair(p.rules[i], p.rules[i + 1]); + } + REQUIRE(tc.number_of_classes() == 7776); + } + LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", + "115", + "FullTransformationMonoid5", + "[todd-coxeter][extreme]") { + auto rg = ReportGuard(REPORT); + size_t n = 7; + auto s = FullTransformationMonoid(n, author::Iwahori); + for (auto& rel : s) { + if (rel.first.empty()) { + rel.first = {n}; + } + if (rel.second.empty()) { + rel.second = {n}; + } + } + auto p = make>(s); + p.alphabet(n + 1); + presentation::add_identity_rules(p, n); + p.validate(); + + ToddCoxeter tc(congruence_kind::twosided); + tc.set_number_of_generators(n + 1); + for (size_t i = 0; i < p.rules.size() - 1; i += 2) { + tc.add_pair(p.rules[i], p.rules[i + 1]); + } + REQUIRE(tc.number_of_classes() == 823543); + } } // namespace congruence