From b22934a8cad70dd24a0a15e8e0362cd53d8673dc Mon Sep 17 00:00:00 2001 From: Reinis Cirpons <43414125+reiniscirpons@users.noreply.github.com> Date: Fri, 3 May 2024 08:38:03 +0100 Subject: [PATCH] v3 Fix bug in `SimsRefinerIdeals` when dealing with complete graphs (#537) --- include/libsemigroups/sims.hpp | 9 +- tests/test-sims.cpp | 165 +++++++++++++++++++++++---------- 2 files changed, 125 insertions(+), 49 deletions(-) diff --git a/include/libsemigroups/sims.hpp b/include/libsemigroups/sims.hpp index 1899b7aca..47a8d43dd 100644 --- a/include/libsemigroups/sims.hpp +++ b/include/libsemigroups/sims.hpp @@ -324,7 +324,7 @@ namespace libsemigroups { //! * \ref number_of_threads to set the number of threads; //! * \ref include to set the pairs to be included; //! * \ref exclude to set the pairs to be excluded; - //! * \ref add_pruner to add a pruninf function; + //! * \ref add_pruner to add a pruner; //! * \ref long_rule_length to set the length of long rules; //! * \ref idle_thread_restarts to set the number of idle thread restarts. //! @@ -3120,6 +3120,13 @@ namespace libsemigroups { return false; } } + } else { + auto const N = wg.number_of_active_nodes(); + auto first = wg.cbegin_nodes(); + auto last = wg.cbegin_nodes() + N; + if (word_graph::is_complete(wg, first, last)) { + return false; + } } return true; } diff --git a/tests/test-sims.cpp b/tests/test-sims.cpp index 96588ac41..4a36da7f8 100644 --- a/tests/test-sims.cpp +++ b/tests/test-sims.cpp @@ -18,6 +18,7 @@ #include "libsemigroups/detail/stl.hpp" #include "libsemigroups/word-graph.hpp" +#include #define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER #define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER @@ -3848,6 +3849,7 @@ namespace libsemigroups { "[quick][sims1]") { Presentation p; p.alphabet("ab"); + p.contains_empty_word(false); presentation::add_rule(p, "aaa", "bb"); presentation::add_rule(p, "aab", "ba"); @@ -3858,53 +3860,6 @@ namespace libsemigroups { SimsRefinerIdeals ip(s.presentation()); s.add_pruner(ip); - // size_t result = 0; - // s.for_each(3, [&ip, &result](auto const& wg) { - // if (ip(wg)) { - // result++; - // } - // }); - // REQUIRE(result == 5); - // result = 0; - // s.for_each(4, [&ip, &result](auto const& wg) { - // if (ip(wg)) { - // result++; - // } - // }); - // REQUIRE(result == 7); - // - // result = 0; - // s.for_each(5, [&ip, &result](auto const& wg) { - // if (ip(wg)) { - // result++; - // } - // }); - // REQUIRE(result == 9); - // - // result = 0; - // s.for_each(6, [&ip, &result](auto const& wg) { - // if (ip(wg)) { - // result++; - // } - // }); - // REQUIRE(result == 11); - // - // result = 0; - // s.for_each(7, [&ip, &result](auto const& wg) { - // if (ip(wg)) { - // result++; - // } - // }); - // REQUIRE(result == 12); - // - // result = 0; - // s.for_each(8, [&ip, &result](auto const& wg) { - // if (ip(wg)) { - // result++; - // } - // }); - // REQUIRE(result == 12); - REQUIRE(s.number_of_congruences(1) == 1); // computed using GAP REQUIRE(s.number_of_congruences(2) == 3); // computed using GAP REQUIRE(s.number_of_congruences(3) == 5); // computed using GAP @@ -3912,7 +3867,8 @@ namespace libsemigroups { REQUIRE(s.number_of_congruences(5) == 9); // computed using GAP REQUIRE(s.number_of_congruences(6) == 11); // computed using GAP REQUIRE(s.number_of_congruences(7) == 12); // computed using GAP - REQUIRE(s.number_of_congruences(8) == 12); // computed using GAP + for (size_t nr_classes = 8; nr_classes < 16; ++nr_classes) + REQUIRE(s.number_of_congruences(nr_classes) == 12); // computed using GAP } // about 2 seconds @@ -4031,6 +3987,119 @@ namespace libsemigroups { // REQUIRE(result == 6); // REQUIRE(s.number_of_congruences(15) == 0); } + + LIBSEMIGROUPS_TEST_CASE("Sims2", + "123", + "Adding and removing pruners", + "[quick][low-index]") { + Presentation p; + p.alphabet("ab"); + p.contains_empty_word(false); + presentation::add_rule(p, "aaa", "bb"); + presentation::add_rule(p, "aab", "ba"); + + Sims2 s(p); + SimsRefinerIdeals ip(s.presentation()); + s.add_pruner(ip); + REQUIRE(s.number_of_congruences(12) == 12); // computed using GAP + s.clear_pruners(); + REQUIRE(s.number_of_congruences(12) == 41); // computed using GAP + s.add_pruner(ip); + REQUIRE(s.number_of_congruences(12) == 12); // computed using GAP + } + + LIBSEMIGROUPS_TEST_CASE("Sims1", + "124", + "Right congruence checking", + "[quick][low-index]") { + Presentation p; + p.alphabet(01_w); + p.contains_empty_word(true); + presentation::add_rule(p, 000_w, 11_w); + presentation::add_rule(p, 001_w, 10_w); + + word_graph_type wg; + + // Wrong alphabet size + wg = to_word_graph(3, {{1, 1, 1}, {2, 2, 2}, {2, 2, 2}}); + wg.number_of_active_nodes(3); + REQUIRE(!sims::is_right_congruence(p, wg)); + + // Incomplete + wg = to_word_graph(2, {{1, 1}, {1, UNDEFINED}}); + wg.number_of_active_nodes(2); + REQUIRE(!sims::is_right_congruence(p, wg)); + + // Incompatible + wg = to_word_graph(2, {{1, 1}, {1, 0}}); + wg.number_of_active_nodes(2); + REQUIRE(!sims::is_right_congruence(p, wg)); + REQUIRE_THROWS_AS(sims::validate_right_congruence(p, wg), + LibsemigroupsException); + + // Works + wg = to_word_graph(4, {{1, 2}, {2, 2}, {3, 3}, {3, 3}}); + wg.number_of_active_nodes(4); + REQUIRE(sims::is_right_congruence(p, wg)); + + // Non maximal + wg = to_word_graph(2, {{1, 1}, {1, 0}}); + wg.number_of_active_nodes(2); + REQUIRE(!sims::is_maximal_right_congruence(p, wg)); + wg = to_word_graph(4, {{1, 2}, {2, 2}, {3, 3}, {3, 3}}); + wg.number_of_active_nodes(4); + REQUIRE(!sims::is_maximal_right_congruence(p, wg)); + wg = to_word_graph(1, {{0, 0}}); + wg.number_of_active_nodes(1); + REQUIRE(!sims::is_maximal_right_congruence(p, wg)); + + // Is maximal + wg = to_word_graph(2, {{1, 1}, {1, 1}}); + wg.number_of_active_nodes(2); + REQUIRE(sims::is_maximal_right_congruence(p, wg)); + } + + LIBSEMIGROUPS_TEST_CASE("Sims2", + "125", + "Two-sided congruence checking", + "[quick][low-index]") { + Presentation p; + p.alphabet(01_w); + p.contains_empty_word(true); + presentation::add_rule(p, 000_w, 11_w); + presentation::add_rule(p, 001_w, 10_w); + + word_graph_type wg; + + // Wrong alphabet size + wg = to_word_graph(3, {{1, 1, 1}, {2, 2, 2}, {2, 2, 2}}); + wg.number_of_active_nodes(3); + REQUIRE(!sims::is_two_sided_congruence(p, wg)); + + // Incomplete + wg = to_word_graph(2, {{1, 1}, {1, UNDEFINED}}); + wg.number_of_active_nodes(2); + REQUIRE(!sims::is_two_sided_congruence(p, wg)); + + // Incompatible + wg = to_word_graph(2, {{1, 1}, {1, 0}}); + wg.number_of_active_nodes(2); + REQUIRE(!sims::is_two_sided_congruence(p, wg)); + REQUIRE_THROWS_AS(sims::validate_two_sided_congruence(p, wg), + LibsemigroupsException); + + // Not compatible with X_Gamma + wg = to_word_graph(4, {{1, 2}, {2, 2}, {3, 3}, {3, 3}}); + wg.number_of_active_nodes(4); + REQUIRE(!sims::is_two_sided_congruence(p, wg)); + REQUIRE_THROWS_AS(sims::validate_two_sided_congruence(p, wg), + LibsemigroupsException); + + // Works + wg = to_word_graph(2, {{1, 1}, {1, 1}}); + wg.number_of_active_nodes(2); + REQUIRE(sims::is_two_sided_congruence(p, wg)); + } } // namespace libsemigroups // [[[0, 0, 0]], #1#