From 93e5cb2d1b9a2ffa33c043c9d3d6226338f2d72d Mon Sep 17 00:00:00 2001 From: Joseph Edwards Date: Mon, 8 Jul 2024 17:35:54 +0100 Subject: [PATCH] Add to_(inverse_)presentation tests --- tests/test-presentation.cpp | 5 + tests/test-to-presentation.cpp | 227 +++++++++++++++++++++++++++++++-- 2 files changed, 220 insertions(+), 12 deletions(-) diff --git a/tests/test-presentation.cpp b/tests/test-presentation.cpp index 2e174c6ba..7aedfe7d9 100644 --- a/tests/test-presentation.cpp +++ b/tests/test-presentation.cpp @@ -1014,6 +1014,7 @@ namespace libsemigroups { ip.inverses_no_checks({2, 1, 0}); REQUIRE(ip != ip2); + ip.validate(); } template @@ -1033,6 +1034,7 @@ namespace libsemigroups { REQUIRE(ip.inverse(0) == 2); REQUIRE(ip.inverse(1) == 1); REQUIRE(ip.inverse(2) == 0); + ip.validate(); } } // namespace @@ -2838,6 +2840,7 @@ namespace libsemigroups { REQUIRE(ip.rules.size() == 2); presentation::add_rule(ip, {0, 0, 0}, {0}); REQUIRE_THROWS_AS(ip.validate(), LibsemigroupsException); + REQUIRE_EXCEPTION_MSG(ip.inverse(0), "no inverses have been defined"); ip.inverses_no_checks({2, 1, 0}); ip.validate(); check_inverse_constructors(ip); @@ -2854,6 +2857,7 @@ namespace libsemigroups { REQUIRE(ip.rules.size() == 2); presentation::add_rule(ip, {0, 0, 0}, {0}); REQUIRE_THROWS_AS(ip.validate(), LibsemigroupsException); + REQUIRE_EXCEPTION_MSG(ip.inverse(0), "no inverses have been defined"); ip.inverses_no_checks({2, 1, 0}); ip.validate(); check_inverse_constructors(ip); @@ -2870,6 +2874,7 @@ namespace libsemigroups { REQUIRE(ip.rules.size() == 2); presentation::add_rule(ip, {0, 0, 0}, {0}); REQUIRE_THROWS_AS(ip.validate(), LibsemigroupsException); + REQUIRE_EXCEPTION_MSG(ip.inverse(0), "no inverses have been defined"); ip.inverses_no_checks({2, 1, 0}); ip.validate(); check_inverse_constructors(ip); diff --git a/tests/test-to-presentation.cpp b/tests/test-to-presentation.cpp index ed66588c2..d81807e67 100644 --- a/tests/test-to-presentation.cpp +++ b/tests/test-to-presentation.cpp @@ -66,22 +66,165 @@ namespace libsemigroups { template void check_to_presentation_from_presentation() { Presentation p; - p.alphabet(2); - p.contains_empty_word(false); - presentation::add_rule_no_checks(p, {0, 1, 2}, {0, 1}); - presentation::add_rule_no_checks(p, {0, 1, 2}, {}); - // intentionally bad - REQUIRE_THROWS_AS(p.validate(), LibsemigroupsException); - REQUIRE_THROWS_AS(to_presentation(p), LibsemigroupsException); - - p.alphabet_from_rules(); - REQUIRE(p.alphabet() == W1({0, 1, 2})); + p.alphabet(3); + p.contains_empty_word(true); + if constexpr (std::is_same_v) { + presentation::add_rule_no_checks(p, "abc", "ab"); + presentation::add_rule_no_checks(p, "abc", ""); + } else { + presentation::add_rule_no_checks(p, {0, 1, 2}, {0, 1}); + presentation::add_rule_no_checks(p, {0, 1, 2}, {}); + } p.validate(); + + Presentation q = to_presentation(p); + REQUIRE(q.contains_empty_word()); + + if constexpr (std::is_same_v) { + REQUIRE(q.alphabet() == "abc"); + REQUIRE(q.rules == std::vector({"abc", "ab", "abc", ""})); + } else { + REQUIRE(q.alphabet() == W2({0, 1, 2})); + REQUIRE(q.rules == std::vector({{0, 1, 2}, {0, 1}, {0, 1, 2}, {}})); + } + q.validate(); + + // Check p hasn't been destroyed REQUIRE(p.contains_empty_word()); - auto q = to_presentation(p); + if constexpr (std::is_same_v) { + REQUIRE(p.alphabet() == "abc"); + REQUIRE(p.rules == std::vector({"abc", "ab", "abc", ""})); + } else { + REQUIRE(p.alphabet() == W1({0, 1, 2})); + REQUIRE(p.rules == std::vector({{0, 1, 2}, {0, 1}, {0, 1, 2}, {}})); + } + p.validate(); + + // Check two conversions gets you back to where you started + REQUIRE(p == to_presentation(q)); + } + + template + void check_to_presentation_from_presentation_with_function() { + Presentation p; + p.alphabet(3); + p.contains_empty_word(true); + if constexpr (std::is_same_v) { + presentation::add_rule_no_checks(p, "abc", "ab"); + presentation::add_rule_no_checks(p, "abc", ""); + } else { + presentation::add_rule_no_checks(p, {0, 1, 2}, {0, 1}); + presentation::add_rule_no_checks(p, {0, 1, 2}, {}); + } + auto f1 = [&p](auto val) { + return presentation::human_readable_letter(p.index(val) + 7); + }; + Presentation q = to_presentation(p, f1); REQUIRE(q.contains_empty_word()); + if constexpr (std::is_same_v) { + REQUIRE(q.alphabet() == "hij"); + REQUIRE(q.rules == std::vector({"hij", "hi", "hij", ""})); + } else { + REQUIRE(q.alphabet() == W2({7, 8, 9})); + REQUIRE(q.rules == std::vector({{7, 8, 9}, {7, 8}, {7, 8, 9}, {}})); + } q.validate(); + + auto f2 = [&p](auto val) { return p.index(val); }; + Presentation r = to_presentation(p, f2); + REQUIRE(r.contains_empty_word()); + REQUIRE(r.alphabet() == W2({0, 1, 2})); + REQUIRE(r.rules == std::vector({{0, 1, 2}, {0, 1}, {0, 1, 2}, {}})); + + r.validate(); + } + + template + void check_to_inverse_presentation() { + InversePresentation ip; + ip.alphabet(3); + ip.contains_empty_word(true); + if constexpr (std::is_same_v) { + presentation::add_rule_no_checks(ip, "abc", "ab"); + presentation::add_rule_no_checks(ip, "abc", ""); + ip.inverses_no_checks("cba"); + } else { + presentation::add_rule_no_checks(ip, {0, 1, 2}, {0, 1}); + presentation::add_rule_no_checks(ip, {0, 1, 2}, {}); + ip.inverses_no_checks({2, 1, 0}); + } + ip.validate(); + + auto iq = to_inverse_presentation(ip); + REQUIRE(iq.contains_empty_word()); + + if constexpr (std::is_same_v) { + REQUIRE(iq.alphabet() == "abc"); + REQUIRE(iq.rules == std::vector({"abc", "ab", "abc", ""})); + REQUIRE(iq.inverses() == "cba"); + } else { + REQUIRE(iq.alphabet() == W2({0, 1, 2})); + REQUIRE(iq.rules + == std::vector({{0, 1, 2}, {0, 1}, {0, 1, 2}, {}})); + REQUIRE(iq.inverses() == W2({2, 1, 0})); + } + iq.validate(); + + // Check p hasn't been destroyed + REQUIRE(ip.contains_empty_word()); + if constexpr (std::is_same_v) { + REQUIRE(ip.alphabet() == "abc"); + REQUIRE(ip.rules == std::vector({"abc", "ab", "abc", ""})); + REQUIRE(ip.inverses() == "cba"); + } else { + REQUIRE(ip.alphabet() == W1({0, 1, 2})); + REQUIRE(ip.rules + == std::vector({{0, 1, 2}, {0, 1}, {0, 1, 2}, {}})); + REQUIRE(ip.inverses() == W1({2, 1, 0})); + } + ip.validate(); + + // Check two conversions gets you back to where you started + REQUIRE(ip == to_inverse_presentation(iq)); + + auto f = [&ip](auto val) { return ip.index(val) + 3; }; + InversePresentation ir = to_inverse_presentation(ip, f); + REQUIRE(ir.contains_empty_word()); + REQUIRE(ir.alphabet() == W2({3, 4, 5})); + REQUIRE(ir.rules == std::vector({{3, 4, 5}, {3, 4}, {3, 4, 5}, {}})); + REQUIRE(ir.inverses() == W2({5, 4, 3})); + + ir.validate(); + } + + template + void check_to_inverse_presentation_from_presentation() { + Presentation p; + p.alphabet(3); + if constexpr (std::is_same_v) { + presentation::add_rule_no_checks(p, "abc", "ab"); + presentation::add_rule_no_checks(p, "acb", "c"); + } else { + presentation::add_rule_no_checks(p, {0, 1, 2}, {0, 1}); + presentation::add_rule_no_checks(p, {0, 2, 1}, {2}); + } + p.validate(); + + InversePresentation ip = to_inverse_presentation(p); + REQUIRE(!ip.contains_empty_word()); + if constexpr (std::is_same_v) { + REQUIRE(ip.alphabet() == "abcdef"); + REQUIRE(ip.rules == std::vector({"abc", "ab", "acb", "c"})); + REQUIRE(ip.inverses() == "defabc"); + } else { + REQUIRE(ip.alphabet() == Word({0, 1, 2, 3, 4, 5})); + REQUIRE(ip.rules + == std::vector({{0, 1, 2}, {0, 1}, {0, 2, 1}, {2}})); + REQUIRE(ip.inverses() == Word({3, 4, 5, 0, 1, 2})); + } + + REQUIRE(ip == to_inverse_presentation(ip)); } } // namespace @@ -140,10 +283,37 @@ namespace libsemigroups { word_type>(); check_to_presentation_from_presentation, std::string>(); + // The function calls below correctly cause compile errors + // check_to_presentation_from_presentation(); + // check_to_presentation_from_presentation(); + // check_to_presentation_from_presentation, + // StaticVector1>(); } LIBSEMIGROUPS_TEST_CASE("to_presentation", "003", + "presentation from presentation with function", + "[quick][to_presentation]") { + check_to_presentation_from_presentation_with_function(); + check_to_presentation_from_presentation_with_function< + std::string, + StaticVector1>(); + check_to_presentation_from_presentation_with_function(); + check_to_presentation_from_presentation_with_function< + word_type, + StaticVector1>(); + check_to_presentation_from_presentation_with_function< + StaticVector1, + word_type>(); + check_to_presentation_from_presentation_with_function< + StaticVector1, + std::string>(); + } + + LIBSEMIGROUPS_TEST_CASE("to_presentation", + "004", "presentation from presentation and alphabet", "[quick][to_presentation]") { Presentation p; @@ -168,7 +338,7 @@ namespace libsemigroups { } LIBSEMIGROUPS_TEST_CASE("to_presentation", - "004", + "005", "use human readable alphabet for to_presentation", "[quick][presentation]") { Presentation p; @@ -185,4 +355,37 @@ namespace libsemigroups { REQUIRE(q.rules == std::vector({"xy", ""})); } + LIBSEMIGROUPS_TEST_CASE("to_inverse_presentation", + "006", + "inverse presentation from inverse presentation", + "[quick][to_presentation]") { + check_to_inverse_presentation(); + check_to_inverse_presentation>(); + check_to_inverse_presentation(); + check_to_inverse_presentation>(); + check_to_inverse_presentation, word_type>(); + check_to_inverse_presentation, std::string>(); + // The function calls below correctly cause compile errors + // check_to_inverse_presentation(); + // check_to_inverse_presentation(); + // check_to_inverse_presentation, + // StaticVector1>(); + } + + LIBSEMIGROUPS_TEST_CASE("to_inverse_presentation", + "007", + "inverse presentation from presentation", + "[quick][to_presentation]") { + check_to_inverse_presentation_from_presentation(); + check_to_inverse_presentation_from_presentation(); + check_to_inverse_presentation_from_presentation< + StaticVector1>(); + + Presentation> p; + p.alphabet(32767); + REQUIRE_NOTHROW(to_inverse_presentation(p)); + p.alphabet(32768); + REQUIRE_THROWS(to_inverse_presentation(p)); + } + } // namespace libsemigroups