From cfe2996e058427422591625298a5f500b7e3cebf Mon Sep 17 00:00:00 2001 From: reiniscirpons Date: Fri, 27 Sep 2024 11:58:29 +0100 Subject: [PATCH] Fix some failing tests and add function to check output result via the free object --- tests/test-sims.cpp | 215 +++++++++++++++++++++++--------------------- 1 file changed, 113 insertions(+), 102 deletions(-) diff --git a/tests/test-sims.cpp b/tests/test-sims.cpp index 53abc90a0..4b87390e2 100644 --- a/tests/test-sims.cpp +++ b/tests/test-sims.cpp @@ -204,6 +204,28 @@ namespace libsemigroups { } } + template + void check_congruence_count_with_free_object(Sims1Or2 const& sims, + size_t index, + size_t expected) { + auto p = sims.presentation(); + Sims1Or2 SF(sims); + Presentation F; + F.alphabet(p.alphabet()); + F.contains_empty_word(p.contains_empty_word()); + std::atomic count = 0; + SF.presentation(F); + SF.for_each(index, [&p, &count](auto const& wg) { + count += word_graph::is_compatible(wg, + wg.cbegin_nodes(), + wg.cbegin_nodes() + + wg.number_of_active_nodes(), + p.rules.cbegin(), + p.rules.cend()); + }); + REQUIRE(count == expected); + } + } // namespace LIBSEMIGROUPS_TEST_CASE("Sims1", @@ -251,8 +273,8 @@ namespace libsemigroups { REQUIRE(*it == to_word_graph(3, {{0, 0}})); // Note that Catch's REQUIRE macro is not thread safe, see: // https://github.com/catchorg/Catch2/issues/99 - // as such we cannot call any function (like check_right_generating_pairs) - // that uses REQUIRE in multiple threads. + // as such we cannot call any function (like + // check_right_generating_pairs) that uses REQUIRE in multiple threads. S.number_of_threads(1).for_each( 5, [S](auto const& wg) { check_right_generating_pairs(S, wg); }); } @@ -646,6 +668,8 @@ namespace libsemigroups { auto p = symmetric_inverse_monoid(5, author::Gay); presentation::reverse(p); Sims1 C(p); + // NOTE: Never ran to completion, there should be a non-zero number of + // congruences. REQUIRE(C.number_of_threads(std::thread::hardware_concurrency()) .number_of_congruences(1'546) == 0); @@ -1930,8 +1954,6 @@ namespace libsemigroups { "rectangular_band(m, n) - m = 1 .. 5, n = 1 .. 5", "[fail][sims1]") { // This doesn't fail it's just very extreme - // TODO(2): This does now fail, we get 30 instead of 22 in the relevant - // entry. // Note: num_congs[n][m] is the number of right congruences of // rectangular_band(m, n) std::vector> num_congs @@ -2131,38 +2153,24 @@ namespace libsemigroups { C.presentation(p).long_rule_length(6).number_of_threads( std::thread::hardware_concurrency()); - // NOTE: Never ran to completion, if you do, change the 0 to the answer. + // NOTE: Never ran to completion, there should be a non-zero number of + // congruences. REQUIRE(C.number_of_congruences(625) == 0); } LIBSEMIGROUPS_TEST_CASE("Sims1", "055", - "plactic_monoid(3) up to index 8", - "[fail][low-index][plactic]") { + "Plactic semigroup 3 up to index 8", + "[extreme][low-index][plactic]") { std::array const num - // TODO(2): returns 15 when n=2 instead of 29, why? = {0, 1, 29, 484, 6'896, 103'204, 1'773'360, 35'874'182, 849'953'461}; - auto rg = ReportGuard(true); - auto p = plactic_monoid(3); - Sims1 S, SF; - Presentation F; - F.alphabet(3); + auto rg = ReportGuard(true); + auto p = plactic_monoid(3); + p.contains_empty_word(false); + Sims1 S; for (size_t n = 2; n < 9; ++n) { - std::atomic count = 0; S.init(p); - SF.init(F); - SF.number_of_threads(std::thread::hardware_concurrency()); - SF.for_each(n, [&n, &p, &count](auto const& wg) { - count += word_graph::is_compatible(wg, - wg.cbegin_nodes(), - wg.cbegin_nodes() - + wg.number_of_active_nodes(), - p.rules.cbegin(), - p.rules.cend()); - }); - // REQUIRE(presentation::to_gap_string(p, "S") == ""); - REQUIRE(count == num[n]); - S.number_of_threads(1); + S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); REQUIRE(S.number_of_congruences(n) == num[n]); presentation::reverse(p); S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2172,14 +2180,14 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "056", - "plactic_monoid(4) up to index 6", - "[fail][low-index][plactic]") { + "Plactic semigroup 4 up to index 6", + "[extreme][low-index][plactic]") { std::array const num - // TODO(2): Get different result when n=2 = {0, 1, 67, 2'794, 106'264, 4'795'980, 278'253'841, 20'855'970'290}; // Last value too 1h34m to compute so is not included. auto rg = ReportGuard(true); auto p = plactic_monoid(4); + p.contains_empty_word(false); for (size_t n = 2; n < 7; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2192,14 +2200,14 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "057", - "plactic_monoid(5) up to index 5", - "[fail][low-index][plactic]") { + "Plactic semigroup 5 up to index 5", + "[extreme][low-index][plactic]") { std::array const num - // TODO(2): Get different result when n=2 = {0, 1, 145, 14'851, 1'496'113, 198'996'912, 37'585'675'984}; // Last value took 5h11m to compute auto rg = ReportGuard(true); auto p = plactic_monoid(5); + p.contains_empty_word(false); for (size_t n = 3; n < 6; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2212,14 +2220,14 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "058", - "plactic_monoid(6) up to index 4", - "[fail][low-index][plactic]") { + "Plactic semigroup 6 up to index 4", + "[extreme][low-index][plactic]") { std::array const num - // TODO(2): get wrong value when n=2 = {0, 1, 303, 77'409, 20'526'128, 7'778'840'717}; // The last value took 4h5m to run and is omitted. auto rg = ReportGuard(true); auto p = plactic_monoid(6); + p.contains_empty_word(false); for (size_t n = 2; n < 5; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2233,14 +2241,14 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "059", - "plactic_monoid(7) up to index 3", - "[fail][low-index][plactic]") { - // TODO(2): get wrong value when n=2 + "Plactic semigroup 7 up to index 3", + "[extreme][low-index][plactic]") { std::array const num = {0, 1, 621, 408'024, 281'600'130}; // The last value took approx. 12m34s to run and is omitted from the - // extreme test 12m34s to run and is omitted from the extreme test. + // extreme test. auto rg = ReportGuard(true); auto p = plactic_monoid(7); + p.contains_empty_word(false); for (size_t n = 2; n < 4; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2253,12 +2261,12 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "060", - "plactic_monoid(8) up to index 3", - "[fail][low-index][plactic]") { - // TODO(2): get wrong value when n=2 + "Plactic semigroup 8 up to index 3", + "[extreme][low-index][plactic]") { std::array const num = {0, 1, 1'259, 2'201'564}; auto rg = ReportGuard(true); auto p = plactic_monoid(8); + p.contains_empty_word(false); for (size_t n = 2; n < 4; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2271,15 +2279,16 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "061", - "chinese_monoid(3) up to index 8", - "[fail][low-index][chinese]") { + "Chinese semigroup 3 up to index 8", + "[extreme][low-index][chinese]") { std::array const num - // TODO(2): Get wrong result for n = 2 = {0, 1, 31, 559, 8'904, 149'529, 2'860'018, 63'828'938, 1'654'488'307}; // index 8 is doable and the value is included above, but it took about X - // minutes to run, so isn't included in the loop below. + // minutes, where X could be considered large, so isn't included in the loop + // below. auto rg = ReportGuard(true); auto p = chinese_monoid(3); + p.contains_empty_word(false); for (size_t n = 2; n < 8; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2289,16 +2298,16 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "062", - "chinese_monoid(4) up to index 6", - "[fail][low-index][chinese]") { + "Chinese semigroup 4 up to index 6", + "[extreme][low-index][chinese]") { + std::array const num + = {0, 1, 79, 3'809, 183'995, 10'759'706, 804'802'045, 77'489'765'654}; // n = 6 took between 3 and 4 minutes // n = 7 took 6h16m // both are omitted - std::array const num - // TODO(2): Get wrong result for n = 3 - = {0, 1, 79, 3'809, 183'995, 10'759'706, 804'802'045, 77'489'765'654}; auto rg = ReportGuard(true); auto p = chinese_monoid(4); + p.contains_empty_word(false); for (size_t n = 3; n < 7; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2308,15 +2317,14 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "063", - "chinese_monoid(5) up to index 5", - "[fail][low-index][chinese]") { + "Chinese semigroup 5 up to index 5", + "[extreme][low-index][chinese]") { std::array const num - // TODO(2): Get wrong result for n = 3 = {0, 1, 191, 23'504, 3'382'921, 685'523'226, 199'011'439'587}; - // The last value took 21h32m and so is omitted auto rg = ReportGuard(true); auto p = chinese_monoid(5); + p.contains_empty_word(false); for (size_t n = 3; n < 6; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2326,15 +2334,14 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "064", - "chinese_monoid(6) up to index 4", - "[fail][low-index][chinese]") { - // 0 1 2 3 4 + "Chinese semigroup 6 up to index 4", + "[extreme][low-index][chinese]") { std::array const num - // TODO(2): Get wrong result for n = 3 = {0, 1, 447, 137'694, 58'624'384, 40'823'448'867}; // The last value took 9h54m to compute, and is omitted! auto rg = ReportGuard(true); auto p = chinese_monoid(6); + p.contains_empty_word(false); for (size_t n = 3; n < 5; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2344,13 +2351,13 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "065", - "chinese_monoid(7) up to index 4", - "[fail][low-index][chinese]") { - // Last value took about 50m to compute - // TODO(2): get different answer when n=2 + "Chinese semigroup 7 up to index 4", + "[extreme][low-index][chinese]") { std::array const num = {0, 1, 1'023, 786'949, 988'827'143}; - auto rg = ReportGuard(true); - auto p = chinese_monoid(7); + // Last value took about 50m to compute + auto rg = ReportGuard(true); + auto p = chinese_monoid(7); + p.contains_empty_word(false); for (size_t n = 2; n < 4; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2360,12 +2367,12 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "066", - "chinese_monoid(8) up to index 3", - "[fail][low-index][chinese]") { - // TODO(2): get different answer when n=2 + "Chinese semigroup 8 up to index 3", + "[extreme][low-index][chinese]") { std::array const num = {0, 1, 2'303, 4'459'599}; auto rg = ReportGuard(true); auto p = chinese_monoid(8); + p.contains_empty_word(false); for (size_t n = 2; n < 4; ++n) { Sims1 S; S.presentation(p).number_of_threads(std::thread::hardware_concurrency()); @@ -2621,7 +2628,8 @@ namespace libsemigroups { presentation::reverse(p); Sims1 C(p); C.presentation(p).number_of_threads(std::thread::hardware_concurrency()); - // TODO(2): the expected answer is wrong + // NOTE: Never ran to completion, there should be a non-zero number of + // congruences. REQUIRE(C.number_of_congruences(624) == 0); } @@ -2802,11 +2810,11 @@ namespace libsemigroups { REQUIRE(p.rules.size() == 72); Sims1 S; + // Took 1h38min on RC office computer REQUIRE(S.presentation(p) .number_of_threads(std::thread::hardware_concurrency()) .number_of_congruences(462) - // TODO(2): This answer is likely wrong - == 37'951); + == 91'304'735); } LIBSEMIGROUPS_TEST_CASE("Sims1", @@ -2885,7 +2893,6 @@ namespace libsemigroups { ToddCoxeter tc(congruence_kind::twosided, p); tc.strategy(ToddCoxeter::options::strategy::felsch); - // TODO(0) Todd-Coxeter seems to be broken REQUIRE(tc.number_of_classes() == 1); tc.shrink_to_fit(); REQUIRE(tc.word_graph().number_of_nodes() == 1); @@ -3024,8 +3031,9 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "086", "search for possibly non-existent monoid", - "[extreme][sims1]") { + "[fail][sims1]") { // TODO(0): does not seem to use sims? + // Also does not terminate Presentation p; p.contains_empty_word(true); p.alphabet("abcde"); @@ -3111,7 +3119,8 @@ namespace libsemigroups { 011222210_w, 102221220_w, 012221220_w}; auto S = Sims1(p); - // TODO(2): The expected answer is wrong + // NOTE: Never ran to completion, there should be a non-zero number of + // congruences. REQUIRE(S.number_of_threads(std::thread::hardware_concurrency()) .number_of_congruences(31) == 0); @@ -3205,7 +3214,7 @@ namespace libsemigroups { LIBSEMIGROUPS_TEST_CASE("Sims1", "091", "free semilattice n = 8", - "[extreme][sims1]") { + "[fail][sims1]") { Presentation p; p.alphabet("abcdef"); presentation::add_rule(p, "a^2"_p, "a"); @@ -3231,7 +3240,8 @@ namespace libsemigroups { presentation::add_rule(p, "fe"_p, "ef"); Sims1 s(p); - // TODO(2): The expected number here is wrong + // NOTE: Never ran to completion, there should be a non-zero number of + // congruences. REQUIRE(s.number_of_threads(std::thread::hardware_concurrency()) .number_of_congruences(std::pow(2, 6)) == 0); @@ -3410,20 +3420,16 @@ namespace libsemigroups { presentation::add_rule(p, "YxyyXXYYxyxYxyyXYXyXYYxxyyXYXyXYYxyxY", ""); // REQUIRE(presentation::to_gap_string(p, "S") == ""); Sims2 S(p); - // TODO: check correctness - // JDM: not sure how to check correctness of this result, other than - // possibly running through the 36'892'600 2-sided congruences of the free - // monoid with 4 generators and checking for compatibility with the - // relations? Or running through the one-sided congruences and checking - // which are 2-sided also. S.include(0_w, 2_w); REQUIRE(S.number_of_threads(std::thread::hardware_concurrency()) .number_of_congruences(8) == 9); + check_congruence_count_with_free_object(S, 8, 9); S.clear_include().exclude(0_w, 2_w); REQUIRE(S.number_of_threads(std::thread::hardware_concurrency()) .number_of_congruences(8) == 63 - 9); + check_congruence_count_with_free_object(S, 8, 63 - 9); } // Takes approx. 1 minute @@ -3455,7 +3461,7 @@ namespace libsemigroups { // REQUIRE(presentation::to_gap_string(p, "S") == ""); Sims2 S(p); - // TODO: check correctness + // TODO(2): check correctness REQUIRE(S.number_of_threads(std::thread::hardware_concurrency()) .number_of_congruences(64) == 10); @@ -3472,11 +3478,14 @@ namespace libsemigroups { presentation::add_rule(p, "baaabaaa", "aba"); Sims2 S(p); - // TODO: check correctness REQUIRE(S.number_of_threads(8).number_of_congruences(1) == 1); + check_congruence_count_with_free_object(S, 1, 1); REQUIRE(S.number_of_threads(8).number_of_congruences(2) == 5); + check_congruence_count_with_free_object(S, 2, 5); REQUIRE(S.number_of_threads(8).number_of_congruences(3) == 17); + check_congruence_count_with_free_object(S, 3, 17); REQUIRE(S.number_of_threads(8).number_of_congruences(4) == 52); + check_congruence_count_with_free_object(S, 4, 52); // sims::dot_poset("example-104-baaabaaa=aba", S.cbegin(4), S.cend(4)); std::atomic_size_t count = 0; @@ -3531,15 +3540,18 @@ namespace libsemigroups { // sims::dot_poset("example-105-baabbaa=a-2-sided", S.cbegin(8), // S.cend(8)); - // TODO: check correctness // Takes a long time to run, seems like we get all the congruences quite // early on, but then spend very long checking that there are no more. // Perhaps if we had some sort of upper bound could speed things up? size_t num_threads = std::thread::hardware_concurrency(); REQUIRE(S.number_of_threads(num_threads).number_of_congruences(1) == 1); + check_congruence_count_with_free_object(S, 1, 1); REQUIRE(S.number_of_threads(num_threads).number_of_congruences(2) == 4); + check_congruence_count_with_free_object(S, 2, 4); REQUIRE(S.number_of_threads(num_threads).number_of_congruences(3) == 13); + check_congruence_count_with_free_object(S, 3, 13); REQUIRE(S.number_of_threads(num_threads).number_of_congruences(4) == 28); + check_congruence_count_with_free_object(S, 4, 28); REQUIRE(S.number_of_threads(num_threads).number_of_congruences(5) == 49); REQUIRE(S.number_of_threads(num_threads).number_of_congruences(6) == 86); REQUIRE(S.number_of_threads(num_threads).number_of_congruences(7) == 134); @@ -4117,16 +4129,16 @@ namespace libsemigroups { REQUIRE(presentation::length(p) == 128); Sims1 s(p); s.number_of_threads(std::thread::hardware_concurrency()); - // The expected answer is wrong here - // RC ran this for a while and this is the last line of output before it was - // terminated: - // #1: Sims1: total 90,217,309 (cong.) | 1,370,495,022,905 (nodes) - // #1: Sims1: diff +2,237 (cong.) | +63,535,732 (nodes) - // #1: Sims1: mean 3,633 (cong./s) | 218,936 (node/s) - // #1: Sims1: time last s. 447µs (/cong.) | 15ns (/node) - // #1: Sims1: mean time 275µs (/cong.) | 18ns (/node) - // #1: Sims1: time 6h53min48s (total) | - + // RC ran this for a while and this is the last line of output before it + // was terminated: #1: Sims1: total 90,217,309 (cong.) | + // 1,370,495,022,905 (nodes) #1: Sims1: diff +2,237 (cong.) | + // +63,535,732 (nodes) #1: Sims1: mean 3,633 (cong./s) | + // 218,936 (node/s) #1: Sims1: time last s. 447µs (/cong.) | 15ns + // (/node) #1: Sims1: mean time 275µs (/cong.) | 18ns (/node) #1: + // Sims1: time 6h53min48s (total) | + + // NOTE: Never ran to completion, there should be a non-zero number of + // congruences. REQUIRE(s.number_of_congruences(462) == 0); } @@ -4387,12 +4399,11 @@ namespace libsemigroups { == fmt::format( "", to_human_readable_repr(p))); - REQUIRE( - to_human_readable_repr(rep_orc) - == fmt::format( - "", - to_human_readable_repr(p))); + REQUIRE(to_human_readable_repr(rep_orc) + == fmt::format("", + to_human_readable_repr(p))); REQUIRE(to_human_readable_repr(minimal_rep_orc) == fmt::format("",