From e21c294fd82d8621a79374461d3da8db9f38b6ae Mon Sep 17 00:00:00 2001 From: Joseph Edwards Date: Wed, 14 Aug 2024 17:49:15 +0100 Subject: [PATCH] Merge human_readable_char and human_readable_letter --- include/libsemigroups/knuth-bendix.tpp | 1 + include/libsemigroups/presentation.hpp | 4 +- include/libsemigroups/presentation.tpp | 20 +----- include/libsemigroups/to-presentation.hpp | 12 ++-- include/libsemigroups/to-presentation.tpp | 8 +-- include/libsemigroups/words.hpp | 43 +++++++++--- src/presentation.cpp | 8 +-- src/words.cpp | 24 ++----- tests/test-presentation.cpp | 85 ++++++++++------------- tests/test-to-presentation.cpp | 2 +- tests/test-todd-coxeter.cpp | 2 +- tests/test-words.cpp | 6 +- 12 files changed, 92 insertions(+), 123 deletions(-) diff --git a/include/libsemigroups/knuth-bendix.tpp b/include/libsemigroups/knuth-bendix.tpp index 3f1475c67..f0b02f562 100644 --- a/include/libsemigroups/knuth-bendix.tpp +++ b/include/libsemigroups/knuth-bendix.tpp @@ -798,6 +798,7 @@ namespace libsemigroups { return detail::internal_string_type({uint_to_internal_char(i)}); } + // TODO (later) replace with ToWord somehow? template word_type KnuthBendix::internal_string_to_word( detail::internal_string_type const& s) { diff --git a/include/libsemigroups/presentation.hpp b/include/libsemigroups/presentation.hpp index 010db0cb5..ba33ab265 100644 --- a/include/libsemigroups/presentation.hpp +++ b/include/libsemigroups/presentation.hpp @@ -1694,8 +1694,8 @@ namespace libsemigroups { //! \throws LibsemigroupsException if `i` exceeds the number of letters in //! supported by `letter_type`. // TODO(later) move to words.*pp - template - typename Presentation::letter_type human_readable_letter(size_t i); + // template + // typename Presentation::letter_type human_readable_letter(size_t i); //! \brief Return the first letter **not** in the alphabet of a //! presentation. diff --git a/include/libsemigroups/presentation.tpp b/include/libsemigroups/presentation.tpp index 8d7b8051c..88fc49510 100644 --- a/include/libsemigroups/presentation.tpp +++ b/include/libsemigroups/presentation.tpp @@ -88,9 +88,7 @@ namespace libsemigroups { n); } word_type lphbt(n, 0); - std::iota(lphbt.begin(), - lphbt.end(), - presentation::human_readable_letter(0)); + std::iota(lphbt.begin(), lphbt.end(), human_readable_letter(0)); return alphabet(lphbt); } @@ -772,22 +770,6 @@ namespace libsemigroups { remove_trivial_rules(p); } - template - typename Presentation::letter_type human_readable_letter(size_t i) { - if constexpr (!std::is_same_v) { - using letter_type = typename Presentation::letter_type; - if (i >= std::numeric_limits::max()) { - LIBSEMIGROUPS_EXCEPTION( - "expected the argument to be in the range [0, {}), found {}", - std::numeric_limits::max(), - i); - } - return static_cast(i); - } else { - return human_readable_char(i); - } - } - template typename Presentation::letter_type first_unused_letter(Presentation const& p) { diff --git a/include/libsemigroups/to-presentation.hpp b/include/libsemigroups/to-presentation.hpp index 03b948a88..0292bbfb4 100644 --- a/include/libsemigroups/to-presentation.hpp +++ b/include/libsemigroups/to-presentation.hpp @@ -108,10 +108,8 @@ namespace libsemigroups { //! //! If the alphabet of of \p p is \f$\{a_0, a_1, \dots a_{n-1}\}\f$, then the //! conversion from `Presentation::letter_type` to - //! `Presentation::letter_type` is either: - //! * \f$a_i \mapsto\f$ `human_readable_char(size_t i)` if `WordOutput` is - //! `std::string`; or - //! * \f$a_i \mapsto\f$ `i` otherwise. + //! `Presentation::letter_type` is \f$a_i \mapsto\f$ + //! `human_readable_letter(size_t i)`. //! //! \tparam WordOutput the type of the words in the returned presentation. //! \tparam WordInput the type of the words in the input presentation. @@ -215,10 +213,8 @@ namespace libsemigroups { //! //! If the alphabet of of \p ip is \f$\{a_0, a_1, \dots a_{n-1}\}\f$, then the //! conversion from `InversePresentation::letter_type` to - //! `InversePresentation::letter_type` is either: - //! * \f$a_i \mapsto\f$ `human_readable_char(size_t i)` if `WordOutput` is - //! `std::string`; or - //! * \f$a_i \mapsto\f$ `i` otherwise. + //! `InversePresentation::letter_type` is \f$a_i \mapsto\f$ + //! `human_readable_letter(size_t i)`. //! //! \tparam WordOutput the type of the words in the returned inverse //! presentation. diff --git a/include/libsemigroups/to-presentation.tpp b/include/libsemigroups/to-presentation.tpp index 00c92a0cd..349841d6c 100644 --- a/include/libsemigroups/to-presentation.tpp +++ b/include/libsemigroups/to-presentation.tpp @@ -25,9 +25,7 @@ namespace libsemigroups { Presentation p; p.alphabet(fp.number_of_generators()); WordOutput lhs, rhs; - auto f = [](auto val) { - return presentation::human_readable_letter(val); - }; + auto f = [](auto val) { return human_readable_letter(val); }; for (auto it = fp.cbegin_rules(); it != fp.cend_rules(); ++it) { lhs.resize(it->first.size()); @@ -77,7 +75,7 @@ namespace libsemigroups { -> std::enable_if_t, Presentation> { return to_presentation(p, [&p](auto val) { - return presentation::human_readable_letter(p.index(val)); + return human_readable_letter(p.index(val)); }); } @@ -118,7 +116,7 @@ namespace libsemigroups { -> std::enable_if_t, InversePresentation> { return to_inverse_presentation(ip, [&ip](auto val) { - return presentation::human_readable_letter(ip.index(val)); + return human_readable_letter(ip.index(val)); }); } } // namespace libsemigroups diff --git a/include/libsemigroups/words.hpp b/include/libsemigroups/words.hpp index 7dd286d57..a95aa7819 100644 --- a/include/libsemigroups/words.hpp +++ b/include/libsemigroups/words.hpp @@ -711,7 +711,7 @@ namespace libsemigroups { //! //! Defined in `words.hpp`. //! - //! This function is the inverse of \ref human_readable_char, see the + //! This function is the inverse of \ref human_readable_letter, see the //! documentation of that function for more details. //! //! \param c character whose index is sought. @@ -721,7 +721,7 @@ namespace libsemigroups { //! \exception //! \no_libsemigroups_except //! - //! \sa human_readable_char + //! \sa human_readable_letter [[nodiscard]] letter_type human_readable_index(char c); //! \ingroup words_group @@ -1003,6 +1003,10 @@ namespace libsemigroups { // Words -> Strings //////////////////////////////////////////////////////////////////////// + namespace detail { + std::string const& chars_in_human_readable_order(); + } + //! \ingroup words_group //! \brief Returns a character by index in human readable order. //! @@ -1020,7 +1024,25 @@ namespace libsemigroups { //! \returns A value of type \c char. //! //! \throws LibsemigroupsException if \p i exceeds the number of characters. - [[nodiscard]] char human_readable_char(size_t i); + template + typename Word::value_type human_readable_letter(size_t i) { + if (i >= std::numeric_limits::max() + - std::numeric_limits::min()) { + LIBSEMIGROUPS_EXCEPTION( + "expected the argument to be in the range [0, {}), found {}", + std::numeric_limits::max(), + i); + } + if constexpr (!std::is_same_v) { + return static_cast(i); + } else { + // Choose visible characters a-zA-Z0-9 first before anything else + // The ascii ranges for these characters are: [97, 123), [65, 91), + // [48, 58) so the remaining range of chars that are appended to the end + // after these chars are [0,48), [58, 65), [91, 97), [123, 255) + return detail::chars_in_human_readable_order()[i]; + } + } //! \ingroup words_group //! \brief Class for converting \ref word_type into std::string with specified @@ -1031,7 +1053,8 @@ namespace libsemigroups { //! An instance of this class is used to convert from \ref word_type to //! std::string. The letters in the word are converted to characters //! according to their position in alphabet used to construct a ToString - //! instance if one is provided, or using \ref human_readable_char otherwise. + //! instance if one is provided, or using \ref human_readable_letter + //! otherwise. //! //! \par Example //! \code @@ -1138,7 +1161,7 @@ namespace libsemigroups { //! This function converts its second argument \p input into a std::string //! and stores the result in the first argument \p output. The characters of //! \p input are converted using the alphabet used to construct the object - //! or set via init(), or with \ref human_readable_char if \ref empty + //! or set via init(), or with \ref human_readable_letter if \ref empty //! returns `true`. //! //! The contents of the first argument \p output, if any, is removed. @@ -1159,8 +1182,8 @@ namespace libsemigroups { //! //! This function converts its argument \p input into a std::string. The //! characters of \p input are converted using the alphabet used to - //! construct the object or set via init(), or with \ref human_readable_char - //! if \ref empty returns `true`. + //! construct the object or set via init(), or with \ref + //! human_readable_letter if \ref empty returns `true`. //! //! \param input the \ref word_type to convert. //! @@ -1182,7 +1205,7 @@ namespace libsemigroups { //! This function converts its second argument \p input into a std::string //! and stores the result in the first argument \p output. The characters of //! \p input are converted using the alphabet used to construct the object - //! or set via init(), or with \ref human_readable_char if \ref empty + //! or set via init(), or with \ref human_readable_letter if \ref empty //! returns `true`. //! //! The contents of the first argument \p output, if any, is removed. @@ -1202,8 +1225,8 @@ namespace libsemigroups { //! //! This function converts its argument \p input into a std::string. The //! characters of \p input are converted using the alphabet used to - //! construct the object or set via init(), or with \ref human_readable_char - //! if \ref empty returns `true`. + //! construct the object or set via init(), or with \ref + //! human_readable_letter if \ref empty returns `true`. //! //! \param input the string to convert. //! diff --git a/src/presentation.cpp b/src/presentation.cpp index a72caa0eb..0a8f8efc1 100644 --- a/src/presentation.cpp +++ b/src/presentation.cpp @@ -28,9 +28,9 @@ #include "libsemigroups/exception.hpp" // for LIBSEMIGROUPS_EXCEPTION #include "libsemigroups/presentation.hpp" // for Presentation, to_string, to_word -#include "libsemigroups/to-presentation.hpp" // for human_readable_char +#include "libsemigroups/to-presentation.hpp" // for to_presentation #include "libsemigroups/types.hpp" // for word_type -#include "libsemigroups/words.hpp" // for human_readable_char +#include "libsemigroups/words.hpp" // for human_readable_letter #include "libsemigroups/detail/fmt.hpp" // for format @@ -77,7 +77,7 @@ namespace libsemigroups { std::string out; std::string sep = ""; for (auto it = w.cbegin(); it < w.cend(); ++it) { - out += sep + human_readable_char(*it); + out += sep + human_readable_letter<>(*it); sep = " * "; } return out; @@ -92,7 +92,7 @@ namespace libsemigroups { std::string sep = ""; for (auto it = p.alphabet().cbegin(); it != p.alphabet().cend(); ++it) { - out += fmt::format("{}\"{}\"", sep, human_readable_char(*it)); + out += fmt::format("{}\"{}\"", sep, human_readable_letter<>(*it)); sep = ", "; } out += ");\n"; diff --git a/src/words.cpp b/src/words.cpp index ae3e1abcc..4a1c9de3b 100644 --- a/src/words.cpp +++ b/src/words.cpp @@ -197,7 +197,7 @@ namespace libsemigroups { // 2. Strings -> Words //////////////////////////////////////////////////////////////////////// - namespace { + namespace detail { std::string const& chars_in_human_readable_order() { // Choose visible characters a-zA-Z0-9 first before anything else // The ascii ranges for these characters are: [97, 123), [65, 91), @@ -225,7 +225,7 @@ namespace libsemigroups { } return letters; } - } // namespace + } // namespace detail ToWord::ToWord(ToWord const&) = default; ToWord::ToWord(ToWord&&) = default; @@ -242,7 +242,7 @@ namespace libsemigroups { map; if (first_call) { first_call = false; - auto const& chars = chars_in_human_readable_order(); + auto const& chars = detail::chars_in_human_readable_order(); for (letter_type i = 0; i < chars.size(); ++i) { map.emplace(chars[i], i); } @@ -328,22 +328,6 @@ namespace libsemigroups { // 3. Words -> Strings //////////////////////////////////////////////////////////////////////// - char human_readable_char(size_t i) { - using letter_type_ = typename Presentation::letter_type; - // Choose visible characters a-zA-Z0-9 first before anything else - // The ascii ranges for these characters are: [97, 123), [65, 91), - // [48, 58) so the remaining range of chars that are appended to the end - // after these chars are [0,48), [58, 65), [91, 97), [123, 255) - if (i >= std::numeric_limits::max() - - std::numeric_limits::min()) { - LIBSEMIGROUPS_EXCEPTION("expected a value in the range [0, {}) found {}", - std::numeric_limits::max() - - std::numeric_limits::min(), - i); - } - return chars_in_human_readable_order()[i]; - } - ToString::ToString(ToString const&) = default; ToString::ToString(ToString&&) = default; ToString& ToString::operator=(ToString const&) = default; @@ -374,7 +358,7 @@ namespace libsemigroups { std::transform(input.cbegin(), input.cend(), output.begin(), - [](letter_type c) { return human_readable_char(c); }); + [](letter_type c) { return human_readable_letter<>(c); }); } else { // Non-empty alphabet implies conversion should use the alphabet. output.clear(); output.reserve(input.size()); diff --git a/tests/test-presentation.cpp b/tests/test-presentation.cpp index 5cb1cb25f..1524900cc 100644 --- a/tests/test-presentation.cpp +++ b/tests/test-presentation.cpp @@ -401,38 +401,37 @@ namespace libsemigroups { void check_remove_generator() { Presentation p; p.alphabet(10); - p.remove_generator_no_checks(presentation::human_readable_letter(4)); - p.remove_generator_no_checks(presentation::human_readable_letter(7)); - p.remove_generator_no_checks(presentation::human_readable_letter(9)); + p.remove_generator_no_checks(human_readable_letter(4)); + p.remove_generator_no_checks(human_readable_letter(7)); + p.remove_generator_no_checks(human_readable_letter(9)); if constexpr (std::is_same_v) { REQUIRE(p.alphabet() == "abcdfgi"); } else { REQUIRE(p.alphabet() == W({0, 1, 2, 3, 5, 6, 8})); } - REQUIRE(p.index(presentation::human_readable_letter(0)) == 0); - REQUIRE(p.index(presentation::human_readable_letter(1)) == 1); - REQUIRE(p.index(presentation::human_readable_letter(2)) == 2); - REQUIRE(p.index(presentation::human_readable_letter(3)) == 3); - REQUIRE_THROWS_AS(p.index(presentation::human_readable_letter(4)), + REQUIRE(p.index(human_readable_letter(0)) == 0); + REQUIRE(p.index(human_readable_letter(1)) == 1); + REQUIRE(p.index(human_readable_letter(2)) == 2); + REQUIRE(p.index(human_readable_letter(3)) == 3); + REQUIRE_THROWS_AS(p.index(human_readable_letter(4)), LibsemigroupsException); - REQUIRE(p.index(presentation::human_readable_letter(5)) == 4); - REQUIRE(p.index(presentation::human_readable_letter(6)) == 5); - REQUIRE_THROWS_AS(p.index(presentation::human_readable_letter(7)), + REQUIRE(p.index(human_readable_letter(5)) == 4); + REQUIRE(p.index(human_readable_letter(6)) == 5); + REQUIRE_THROWS_AS(p.index(human_readable_letter(7)), LibsemigroupsException); - REQUIRE(p.index(presentation::human_readable_letter(8)) == 6); - REQUIRE_THROWS_AS(p.index(presentation::human_readable_letter(9)), + REQUIRE(p.index(human_readable_letter(8)) == 6); + REQUIRE_THROWS_AS(p.index(human_readable_letter(9)), + LibsemigroupsException); + REQUIRE(p.letter(0) == human_readable_letter(0)); + REQUIRE(p.letter(1) == human_readable_letter(1)); + REQUIRE(p.letter(2) == human_readable_letter(2)); + REQUIRE(p.letter(3) == human_readable_letter(3)); + REQUIRE(p.letter(4) == human_readable_letter(5)); + REQUIRE(p.letter(5) == human_readable_letter(6)); + REQUIRE(p.letter(6) == human_readable_letter(8)); + + REQUIRE_THROWS_AS(p.remove_generator(human_readable_letter(11)), LibsemigroupsException); - REQUIRE(p.letter(0) == presentation::human_readable_letter(0)); - REQUIRE(p.letter(1) == presentation::human_readable_letter(1)); - REQUIRE(p.letter(2) == presentation::human_readable_letter(2)); - REQUIRE(p.letter(3) == presentation::human_readable_letter(3)); - REQUIRE(p.letter(4) == presentation::human_readable_letter(5)); - REQUIRE(p.letter(5) == presentation::human_readable_letter(6)); - REQUIRE(p.letter(6) == presentation::human_readable_letter(8)); - - REQUIRE_THROWS_AS( - p.remove_generator(presentation::human_readable_letter(11)), - LibsemigroupsException); } template @@ -1484,12 +1483,9 @@ namespace libsemigroups { {"bb", "a", "bcb", "a", "abcb", "a", "bbcb", "a"})); REQUIRE(p.alphabet() == "abc"); presentation::normalize_alphabet(p); - REQUIRE(p.letter_no_checks(0) - == presentation::human_readable_letter(0)); - REQUIRE(p.letter_no_checks(1) - == presentation::human_readable_letter(1)); - REQUIRE(p.letter_no_checks(2) - == presentation::human_readable_letter(2)); + REQUIRE(p.letter_no_checks(0) == human_readable_letter<>(0)); + REQUIRE(p.letter_no_checks(1) == human_readable_letter<>(1)); + REQUIRE(p.letter_no_checks(2) == human_readable_letter<>(2)); p.validate(); presentation::add_rule_no_checks(p, "abcb", "ecb"); @@ -1780,26 +1776,18 @@ namespace libsemigroups { "letter", "[quick][presentation]") { Presentation> p; - REQUIRE_THROWS_AS( - presentation::human_readable_letter>(65536), - LibsemigroupsException); - REQUIRE(presentation::human_readable_letter>(10) - == 10); - REQUIRE_THROWS_AS(human_readable_char(65536), LibsemigroupsException); - REQUIRE(human_readable_char(0) == 'a'); - REQUIRE(human_readable_char(10) == 'k'); + REQUIRE_THROWS_AS(human_readable_letter>(65536), + LibsemigroupsException); + REQUIRE(human_readable_letter>(10) == 10); + REQUIRE(human_readable_letter<>(0) == 'a'); + REQUIRE(human_readable_letter<>(10) == 'k'); detail::IntRange ir(0, 255); Presentation q; - REQUIRE(std::all_of(ir.cbegin(), ir.cend(), [](size_t i) { - return human_readable_char(i) - == presentation::human_readable_letter(i); - })); - Presentation r; for (size_t i = 0; i < 1000; ++i) { - REQUIRE(presentation::human_readable_letter(i) == i); + REQUIRE(human_readable_letter(i) == i); } } @@ -1840,16 +1828,13 @@ namespace libsemigroups { = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; std::unordered_set set; for (size_t i = 0; i < letters.size(); ++i) { - REQUIRE(letters[i] - == presentation::human_readable_letter(i)); + REQUIRE(letters[i] == human_readable_letter<>(i)); REQUIRE(set.insert(letters[i]).second); } for (size_t i = letters.size(); i < 255; ++i) { - REQUIRE(set.insert(presentation::human_readable_letter(i)) - .second); + REQUIRE(set.insert(human_readable_letter<>(i)).second); } - REQUIRE_THROWS_AS(presentation::human_readable_letter(255), - LibsemigroupsException); + REQUIRE_THROWS_AS(human_readable_letter<>(255), LibsemigroupsException); p.alphabet(255); REQUIRE_THROWS_AS(presentation::first_unused_letter(p), LibsemigroupsException); diff --git a/tests/test-to-presentation.cpp b/tests/test-to-presentation.cpp index f5b3ba18d..90e04e0f0 100644 --- a/tests/test-to-presentation.cpp +++ b/tests/test-to-presentation.cpp @@ -122,7 +122,7 @@ namespace libsemigroups { } auto f1 = [&p](auto val) { - return presentation::human_readable_letter(p.index(val) + 7); + return human_readable_letter(p.index(val) + 7); }; Presentation q = to_presentation(p, f1); REQUIRE(q.contains_empty_word()); diff --git a/tests/test-todd-coxeter.cpp b/tests/test-todd-coxeter.cpp index fa1722838..b75db09aa 100644 --- a/tests/test-todd-coxeter.cpp +++ b/tests/test-todd-coxeter.cpp @@ -2411,7 +2411,7 @@ namespace libsemigroups { section_Cr_style(tc); REQUIRE(tc.number_of_classes() == 24); - REQUIRE(human_readable_char(0) == 'a'); + REQUIRE(human_readable_letter<>(0) == 'a'); REQUIRE(human_readable_index('a') == 0); REQUIRE(todd_coxeter::normal_form(tc, "aaaaaaaaaaaaaaaaaaa"_w) == "a"_w); auto S = to_froidure_pin(tc); diff --git a/tests/test-words.cpp b/tests/test-words.cpp index 86eec6c58..a71f24031 100644 --- a/tests/test-words.cpp +++ b/tests/test-words.cpp @@ -1168,19 +1168,19 @@ namespace libsemigroups { val = human_readable_index(val); }); std::for_each(result.begin(), result.end(), [](auto& val) { - val = human_readable_char(val); + val = human_readable_letter<>(val); }); REQUIRE(result == expected); std::for_each(result.begin(), result.end(), [](auto& val) { - val = human_readable_char(val); + val = human_readable_letter<>(val); }); std::for_each(result.begin(), result.end(), [](auto& val) { val = human_readable_index(val); }); REQUIRE(result == expected); - REQUIRE_THROWS_AS(human_readable_char(1'000), LibsemigroupsException); + REQUIRE_THROWS_AS(human_readable_letter<>(1'000), LibsemigroupsException); } LIBSEMIGROUPS_TEST_CASE("to_word", "038", "", "[quick]") {