From e258212a3e9cc87740bc36433c4dfe31acc8c86e Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Thu, 12 Dec 2024 15:46:19 +0000 Subject: [PATCH] Knuth bendix hpp (#623) * Refactor x 2 * Split NormalFormRange into sep. file * Refactor x3 * Add file to Makefile.am * Refactor x4 * Refactor x5 * Refactor x6 * Formatting * Refactor x7 * Add TODO * Fixes from python * Linting + formatting * Fix wrong arg order for non_trivial_classes * Use V3 test macro for ToddCoxeter * Format * Add missing full stops --- Makefile.am | 1 + docs/DoxygenLayout.xml | 13 +- include/libsemigroups/cong-intf.hpp | 7 +- .../libsemigroups/detail/knuth-bendix-nf.hpp | 82 ++ include/libsemigroups/knuth-bendix.hpp | 1073 +++++++++-------- include/libsemigroups/knuth-bendix.tpp | 373 ++++-- include/libsemigroups/to-presentation.hpp | 9 +- include/libsemigroups/todd-coxeter.hpp | 70 +- src/cong.cpp | 4 +- tests/test-cong.cpp | 8 +- tests/test-knuth-bendix-1.cpp | 281 +++-- tests/test-knuth-bendix-2.cpp | 201 +-- tests/test-knuth-bendix-3.cpp | 211 ++-- tests/test-knuth-bendix-4.cpp | 108 +- tests/test-knuth-bendix-5.cpp | 54 +- tests/test-knuth-bendix-6.cpp | 74 +- tests/test-todd-coxeter.cpp | 909 +++++++------- 17 files changed, 1896 insertions(+), 1582 deletions(-) create mode 100644 include/libsemigroups/detail/knuth-bendix-nf.hpp diff --git a/Makefile.am b/Makefile.am index bff551728..e11ec9622 100644 --- a/Makefile.am +++ b/Makefile.am @@ -124,6 +124,7 @@ detailinclude_HEADERS += include/libsemigroups/detail/kambites-nf.hpp detailinclude_HEADERS += include/libsemigroups/detail/kbe.hpp detailinclude_HEADERS += include/libsemigroups/detail/kbe.tpp detailinclude_HEADERS += include/libsemigroups/detail/ke.hpp +detailinclude_HEADERS += include/libsemigroups/detail/knuth-bendix-nf.hpp detailinclude_HEADERS += include/libsemigroups/detail/multi-string-view.hpp detailinclude_HEADERS += include/libsemigroups/detail/node-managed-graph.hpp detailinclude_HEADERS += include/libsemigroups/detail/node-managed-graph.tpp diff --git a/docs/DoxygenLayout.xml b/docs/DoxygenLayout.xml index 5ff21d7f8..5f8957c64 100644 --- a/docs/DoxygenLayout.xml +++ b/docs/DoxygenLayout.xml @@ -141,17 +141,8 @@ - - - - - - - - - - - + + diff --git a/include/libsemigroups/cong-intf.hpp b/include/libsemigroups/cong-intf.hpp index a123942c5..8ed2259c8 100644 --- a/include/libsemigroups/cong-intf.hpp +++ b/include/libsemigroups/cong-intf.hpp @@ -198,6 +198,7 @@ namespace libsemigroups { Iterator2 last1, Iterator3 first2, Iterator4 last2) { + LIBSEMIGROUPS_ASSERT(!started()); _generating_pairs.emplace_back(first1, last1); _generating_pairs.emplace_back(first2, last2); return static_cast(*this); @@ -1127,7 +1128,7 @@ namespace libsemigroups { typename Range, typename OutputWord = std::decay_t, typename = std::enable_if_t>> - [[nodiscard]] std::vector> partition(Subclass& kb, + [[nodiscard]] std::vector> partition(Subclass& ci, Range r) { // Congruence + ToddCoxeter have their own overloads for this static_assert(!std::is_same_v @@ -1145,8 +1146,8 @@ namespace libsemigroups { while (!r.at_end()) { auto next = r.get(); - if (kb.presentation().contains_empty_word() || !next.empty()) { - auto next_nf = congruence_interface::reduce(kb, next); + if (ci.presentation().contains_empty_word() || !next.empty()) { + auto next_nf = congruence_interface::reduce(ci, next); auto [it, inserted] = map.emplace(next_nf, index); if (inserted) { result.emplace_back(); diff --git a/include/libsemigroups/detail/knuth-bendix-nf.hpp b/include/libsemigroups/detail/knuth-bendix-nf.hpp new file mode 100644 index 000000000..94cf8cbdc --- /dev/null +++ b/include/libsemigroups/detail/knuth-bendix-nf.hpp @@ -0,0 +1,82 @@ +// +// libsemigroups - C++ library for semigroups and monoids +// Copyright (C) 2024 James D. Mitchell +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +// This file contains an implementation of a range object for producing normal +// forms for a KnuthBendix object. + +#ifndef LIBSEMIGROUPS_DETAIL_KNUTH_BENDIX_NF_HPP_ +#define LIBSEMIGROUPS_DETAIL_KNUTH_BENDIX_NF_HPP_ + +namespace detail { + + template + class KnuthBendixNormalFormRange : public Paths { + using Paths_ = Paths; + + mutable Word _current; + KnuthBendix* _kb; + + public: + using size_type = typename Paths_::size_type; + using output_type = Word const&; + + explicit KnuthBendixNormalFormRange( + KnuthBendix& kb) + : Paths(kb.gilman_graph()), _current(), _kb(&kb) { + // It's possible that the gilman graph is empty, so the call to + // source_no_checks(0) is technically invalid, but nothing goes wrong, + // so we just go with it. This is slightly smelly. + Paths_::source_no_checks(0); + if (!kb.presentation().contains_empty_word()) { + Paths_::next(); + } + } + + output_type get() const { + word_type const& w = Paths_::get(); + _current.clear(); + for (auto c : w) { + _current.push_back(_kb->presentation().letter_no_checks(c)); + } + return _current; + } + + KnuthBendixNormalFormRange& min(size_type val) noexcept { + // TODO(0) should not allow 0 unless contains_empty_word + Paths_::min(val); + return *this; + } + + KnuthBendixNormalFormRange& max(size_type val) noexcept { + Paths_::max(val); + return *this; + } + + using Paths_::at_end; + using Paths_::count; + using Paths_::max; + using Paths_::min; + using Paths_::next; + using Paths_::size_hint; + + static constexpr bool is_finite = true; // this isn't always true! + static constexpr bool is_idempotent = true; + }; // class KnuthBendixNormalFormRange + +} // namespace detail +#endif // LIBSEMIGROUPS_DETAIL_KNUTH_BENDIX_NF_HPP_ diff --git a/include/libsemigroups/knuth-bendix.hpp b/include/libsemigroups/knuth-bendix.hpp index 2b5e7bd5e..74e4ee48f 100644 --- a/include/libsemigroups/knuth-bendix.hpp +++ b/include/libsemigroups/knuth-bendix.hpp @@ -22,8 +22,6 @@ // TODO(1) // * noexcept // * separate rule container from Rules -// TODO(0) -// * fix doc // * nodiscard #ifndef LIBSEMIGROUPS_KNUTH_BENDIX_HPP_ @@ -73,21 +71,24 @@ namespace libsemigroups { class KBE; } // namespace detail - //! \defgroup knuth_bendix_class_group The Knuth-Bendix class + //! \defgroup knuth_bendix_group Knuth-Bendix //! - //! This page TODO + //! This page contains links to the documentation related to the + //! implementation of the Knuth-Bendix algorithm in ``libsemigroups``. - // TODO(0) update the description + //! \ingroup knuth_bendix_group + //! + //! \brief Class containing an implementation of the Knuth-Bendix Algorithm. + //! //! Defined in \c knuth-bendix.hpp. //! //! On this page we describe the functionality relating to the Knuth-Bendix - //! algorithm for semigroups and monoids that is available in - //! \c libsemigroups. This page contains details of the member functions - //! of the class KnuthBendix. + //! algorithm for semigroups and monoids in \c libsemigroups. This page + //! contains details of the member functions of the class KnuthBendix. //! - //! This class is used to represent a - //! [string rewriting system](https://w.wiki/9Re) - //! defining a finitely presented monoid or semigroup. + //! This class is used to represent a [string rewriting + //! system](https://w.wiki/9Re) defining a 1- or 2-sided congruence on a + //! finitely presented monoid or semigroup. //! //! \par Example //! \code @@ -114,15 +115,6 @@ namespace libsemigroups { // defined in detail/kbe.hpp friend class ::libsemigroups::detail::KBE; - //////////////////////////////////////////////////////////////////////// - // KnuthBendix - typedefs/aliases - private - //////////////////////////////////////////////////////////////////////// - - // using external_string_type = std::string; - // using internal_string_type = std::string; - // using external_char_type = char; - // using internal_char_type = char; - //////////////////////////////////////////////////////////////////////// // KnuthBendix - nested subclasses - private //////////////////////////////////////////////////////////////////////// @@ -146,18 +138,43 @@ namespace libsemigroups { // Interface requirements - native-types //////////////////////////////////////////////////////////////////////// - using native_letter_type = char; - using native_word_type = std::string; + //! Type of the rules in the system. + using rule_type = std::pair; + + //! \brief Type of the letters in the relations of the presentation stored + //! in a \ref KnuthBendix instance. + //! + //! A \ref KnuthBendix instance can be constructed or initialised from a + //! presentation of arbitrary types of letters and words. Internally the + //! letters are converted to \ref native_letter_type. + using native_letter_type = char; + + //! \brief Type of the words in the relations of the presentation stored in + //! a \ref KnuthBendix instance. + //! + //! A \ref KnuthBendix instance can be constructed or initialised from a + //! presentation with arbitrary types of letters and words. Internally the + //! words are converted to \ref native_word_type. + using native_word_type = std::string; + + //! \brief Type of the presentation stored in a \ref KnuthBendix instance. + //! + //! A \ref KnuthBendix instance can be constructed or initialised from a + //! presentation of arbitrary types of letters and words. Internally the + //! presentation is stored as a \ref native_presentation_type. using native_presentation_type = Presentation; ////////////////////////////////////////////////////////////////////////// // KnuthBendix - types - public ////////////////////////////////////////////////////////////////////////// - //! This type contains various enums for specifying certain options to a - //! KnuthBendix instance. + //! \brief Struct containing various options that can be used to control the + //! behaviour of Knuth-Bendix. + //! + //! This struct containing various options that can be used to control the + //! behaviour of Knuth-Bendix. struct options { - //! Values for specifying how to measure the length of an overlap. + //! \brief Values for specifying how to measure the length of an overlap. //! //! The values in this enum determine how a KnuthBendix instance //! measures the length \f$d(AB, BC)\f$ of the overlap of two words @@ -184,7 +201,7 @@ namespace libsemigroups { Settings& operator=(Settings const&) noexcept = default; Settings& operator=(Settings&&) noexcept = default; - size_t batch_size; + size_t max_pending_rules; size_t check_confluence_interval; size_t max_overlap; size_t max_rules; @@ -232,21 +249,15 @@ namespace libsemigroups { //! Constructs a KnuthBendix instance with no rules, and the short-lex //! reduction ordering. //! - //! \param knd The kind of congruence to be used. Either \c left, \c right - //! or \c twosided. - //! - //! \complexity - //! Constant. + //! This function default constructs an uninitialised \ref + //! KnuthBendix instance. explicit KnuthBendix(); //! \brief Remove the presentation and rewriter data //! //! This function clears the rewriter, presentation, settings and stats from //! the KnuthBendix object, putting it back into the state it would be in if - //! it was newly constructed. - //! - //! \param knd The kind of congruence to be used. Either \c left, \c right - //! or \c twosided. + //! it was newly default constructed. //! //! \returns //! A reference to \c this. @@ -256,52 +267,114 @@ namespace libsemigroups { //! //! Copy constructor. //! - //! \param copy the KnuthBendix instance to copy. + //! \param that the KnuthBendix instance to copy. //! //! \complexity //! \f$O(n)\f$ where \f$n\f$ is the sum of the lengths of the words in - //! rules of \p copy. + //! rules of \p that. KnuthBendix(KnuthBendix const& that); - // TODO(0) doc + //! \brief Move constructor. + //! + //! Move constructor. KnuthBendix(KnuthBendix&&); - // TODO(0) doc + //! \brief Copy assignment operator. + //! + //! Copy assignment operator. KnuthBendix& operator=(KnuthBendix const&); - // TODO(0) doc + //! \brief Move assignment operator. + //! + //! Move assignment operator. KnuthBendix& operator=(KnuthBendix&&); ~KnuthBendix(); - // TODO(0) doc + //! \brief Construct from \ref congruence_kind and Presentation. + //! + //! This function constructs a \ref KnuthBendix instance representing a + //! congruence of kind \p knd over the semigroup or monoid defined by the + //! presentation \p p. + //! + //! \param knd the kind (onesided or twosided) of the congruence. + //! \param p the presentation. + //! + //! \throws LibsemigroupsException if \p p is not valid. KnuthBendix(congruence_kind knd, Presentation const& p); - // TODO(0) doc + //! \brief Re-initialize a \ref KnuthBendix instance. + //! + //! This function puts a \ref KnuthBendix instance back into the state that + //! it would have been in if it had just been newly constructed from \p knd + //! and \p p. + //! + //! \param knd the kind (onesided or twosided) of the congruence. + //! \param p the presentation. + //! + //! \returns A reference to `*this`. + //! + //! \throws LibsemigroupsException if \p p is not valid. KnuthBendix& init(congruence_kind knd, Presentation const& p); - // TODO(0) doc + //! \copydoc KnuthBendix(congruence_kind, Presentation const&) KnuthBendix(congruence_kind knd, Presentation&& p); - // TODO(0) doc + //! \copydoc init(congruence_kind, Presentation const&) KnuthBendix& init(congruence_kind knd, Presentation&& p); - // TODO(0) doc + //! \brief Construct from \ref congruence_kind and Presentation. + //! + //! This function constructs a \ref KnuthBendix instance representing a + //! congruence of kind \p knd over the semigroup or monoid defined by the + //! presentation \p p. The type of the words in \p p can be anything, but + //! will be converted in to \ref native_word_type. This means that if the + //! input presentation uses \ref word_type, for example, as the word type, + //! then this presentation is converted into a \ref + //! native_presentation_type. This converted presentation can be recovered + //! using \ref presentation. + //! + //! \tparam Word the type of the words in the presentation \p p. + //! \param knd the kind (onesided or twosided) of the congruence. + //! \param p the presentation. + //! + //! \throws LibsemigroupsException if \p p is not valid. // No rvalue ref version because we can't use it. template explicit KnuthBendix(congruence_kind knd, Presentation const& p) + // to_presentation throws in the next line if p isn't valid. + // The next line looks weird but we are usually taking in letter_type's + // and returning chars : KnuthBendix(knd, to_presentation(p, [](auto const& x) { return x; })) {} - // TODO(0) doc + //! \brief Re-initialize a \ref KnuthBendix + //! instance. + //! + //! This function re-initializes a \ref KnuthBendix instance as if it had + //! been newly constructed from \p knd and \p p. + //! + //! \tparam Word the type of the words in the presentation \p p. + //! \param knd the kind (onesided or twosided) of the congruence. + //! \param p the presentation. + //! + //! \returns A reference to `*this`. + //! + //! \throws LibsemigroupsException if \p p is not valid. template KnuthBendix& init(congruence_kind knd, Presentation const& p) { + // to_presentation throws in the next line if p isn't valid. + // The next line looks weird but we are usually taking in letter_type's + // and returning chars init(knd, to_presentation(p, [](auto const& x) { return x; })); return *this; } + // TODO(1) construct/init from kind and KnuthBendix const&, for consistency + // with ToddCoxeter + private: void init_from_generating_pairs(); void init_from_presentation(); @@ -311,6 +384,20 @@ namespace libsemigroups { ////////////////////////////////////////////////////////////////////////// public: + //! \brief Add generating pair via iterators. + //! + //! This function adds a generating pair to the congruence represented by a + //! \ref KnuthBendix instance. + //! + //! \cong_intf_params_contains + //! + //! \returns A reference to `*this`. + //! + //! \cong_intf_warn_assume_letters_in_bounds + //! + //! \warning It is assumed that \ref started returns \c false. Adding + //! generating pairs after \ref started is not permitted (but also not + //! checked by this function). // NOTE THAT this is not the same as in ToddCoxeter, because the generating // pairs contained in CongruenceInterface are word_types, and so we don't // require any conversion here (since chars can be converted implicitly to @@ -327,6 +414,18 @@ namespace libsemigroups { first1, last1, first2, last2); } + //! \brief Add generating pair via iterators. + //! + //! This function adds a generating pair to the congruence represented by a + //! \ref KnuthBendix instance. + //! + //! \cong_intf_params_contains + //! + //! \returns A reference to `*this`. + //! + //! \cong_intf_throws_if_letters_out_of_bounds + //! + //! \cong_intf_throws_if_started template OutputIterator reduce_no_run_no_checks(OutputIterator d_first, InputIterator1 first, - InputIterator2 last) const { - // TODO(1) improve this to not require _tmp_element1 - if constexpr (std::is_same_v) { - static_assert(std::is_same_v); - _tmp_element1.assign(first, std::distance(first, last)); - } else { - _tmp_element1.assign(first, last); - } - const_cast&>(*this).rewrite_inplace( - _tmp_element1); - return std::copy( - std::begin(_tmp_element1), std::end(_tmp_element1), d_first); - } + InputIterator2 last) const; - // TODO(0) should be const + //! \brief Reduce a word with no enumeration. + //! + //! This function writes a reduced word equivalent to the input word + //! described by the iterator \p first and \p last to the output iterator \p + //! d_first. This function triggers no enumeration. The word output by this + //! function is equivalent to the input word in the congruence defined by a + //! \ref KnuthBendix instance. If the \ref KnuthBendix instance is \ref + //! finished, then the output word is a normal form for the input word. If + //! the \ref KnuthBendix instance is not \ref finished, then it might be + //! that equivalent input words produce different output words. + //! + //! \cong_intf_params_reduce + //! + //! \returns An \p OutputIterator pointing one beyond the last letter + //! inserted into \p d_first. + //! + //! \cong_intf_throws_if_letters_out_of_bounds template @@ -453,6 +627,24 @@ namespace libsemigroups { return reduce_no_run_no_checks(d_first, first, last); } + //! \brief Reduce a word with no checks. + //! + //! This function triggers a full enumeration and then writes a reduced + //! word equivalent to the input word described by the iterator \p first and + //! \p last to the output iterator \p d_first. The word output by this + //! function is equivalent to the input word in the congruence defined by a + //! \ref KnuthBendix instance. In other words, the output word is a normal + //! form for the input word or equivalently a canconical representative of + //! its congruence class. + //! + //! \cong_intf_params_reduce + //! + //! \returns An \p OutputIterator pointing one beyond the last letter + //! inserted into \p d_first. + //! + //! \cong_intf_warn_assume_letters_in_bounds + //! + //! \cong_intf_warn_undecidable{Knuth-Bendix} template @@ -463,6 +655,24 @@ namespace libsemigroups { return reduce_no_run_no_checks(d_first, first, last); } + //! \brief Reduce a word. + //! + //! This function triggers a full enumeration and then writes a reduced + //! word equivalent to the input word described by the iterator \p first and + //! \p last to the output iterator \p d_first. The word output by this + //! function is equivalent to the input word in the congruence defined by a + //! \ref KnuthBendix instance. In other words, the output word is a normal + //! form for the input word or equivalently a canconical representative of + //! its congruence class. + //! + //! \cong_intf_params_reduce + //! + //! \returns An \p OutputIterator pointing one beyond the last letter + //! inserted into \p d_first. + //! + //! \cong_intf_throws_if_letters_out_of_bounds + //! + //! \cong_intf_warn_undecidable{Knuth-Bendix} template @@ -496,14 +706,12 @@ namespace libsemigroups { //! //! \complexity //! Constant. - //! - //! \sa \ref run and \ref process_pending_rules. - KnuthBendix& batch_size(size_t val) { - _settings.batch_size = val; + KnuthBendix& max_pending_rules(size_t val) { + _settings.max_pending_rules = val; return *this; } - //! \brief Return the number of rules to accumulate before processing. + //! \brief Get the current number of rules to accumulate before processing. //! //! This function can be used to return the number of pending rules that //! must accumulate before they are reduced, processed, and added to the @@ -519,24 +727,20 @@ namespace libsemigroups { //! //! \complexity //! Constant. - //! - //! \sa \ref run and \ref process_pending_rules. - [[nodiscard]] size_t batch_size() const noexcept { - return _settings.batch_size; + [[nodiscard]] size_t max_pending_rules() const noexcept { + return _settings.max_pending_rules; } //! \brief Set the interval at which confluence is checked. //! - //! The function \ref run periodically checks if - //! the system is already confluent. This function can be used to - //! set how frequently this happens, it is the number of new overlaps - //! that should be considered before checking confluence. Setting this - //! value too low can adversely affect the performance of - //! \ref run. + //! The function \ref run periodically checks if the system is already + //! confluent. This function can be used to set how frequently this happens, + //! it is the number of new overlaps that should be considered before + //! checking confluence. Setting this value too low can adversely affect the + //! performance of \ref run. //! - //! The default value is \c 4096, and should be set to - //! \ref LIMIT_MAX if \ref run should never - //! check if the system is already confluent. + //! The default value is \c 4096, and should be set to \ref LIMIT_MAX if + //! \ref run should never check if the system is already confluent. //! //! \param val the new value of the interval. //! @@ -552,7 +756,7 @@ namespace libsemigroups { return *this; } - //! \brief Return the interval at which confluence is checked. + //! \brief Get the current interval at which confluence is checked. //! //! The function \ref run periodically checks if //! the system is already confluent. This function can be used to @@ -597,7 +801,7 @@ namespace libsemigroups { return *this; } - //! \brief Return the maximum length of overlaps to be considered. + //! \brief Get the current maximum length of overlaps to be considered. //! //! This function returns the maximum length of the overlap of two left hand //! sides of rules that should be considered in \ref run. @@ -619,11 +823,10 @@ namespace libsemigroups { //! \brief Set the maximum number of rules. //! - //! This member function sets the (approximate) maximum number of rules - //! that the system should contain. If this is number is exceeded in - //! calls to \ref run or - //! knuth_bendix_by_overlap_length, then they - //! will terminate and the system may not be confluent. + //! This function sets the (approximate) maximum number of rules + //! that the system should contain. If this is number is exceeded in calls + //! to \ref run or knuth_bendix_by_overlap_length, then they will terminate + //! and the system may not be confluent. //! //! By default this value is \ref POSITIVE_INFINITY. //! @@ -641,14 +844,13 @@ namespace libsemigroups { return *this; } - //! \brief Return the maximum number of rules. + //! \brief Get the current maximum number of rules. //! - //! This member function returns the (approximate) maximum number of rules + //! This function returns the (approximate) maximum number of rules //! that the system should contain. If this is number is exceeded in //! calls to \ref run or \ref knuth_bendix::by_overlap_length, then they //! will terminate and the system may not be confluent. //! - //! //! \returns //! The maximum number of rules the system should contain, a value of type //! \c size_t. @@ -680,7 +882,7 @@ namespace libsemigroups { //! \sa options::overlap. KnuthBendix& overlap_policy(typename options::overlap val); - //! \brief Return the overlap policy. + //! \brief Get the current overlap policy. //! //! This function returns the way that the length of an overlap of two words //! in the system is measured. @@ -703,37 +905,34 @@ namespace libsemigroups { // KnuthBendix - member functions for rules and rewriting - public ////////////////////////////////////////////////////////////////////////// - //! \brief Check if every letter of a word is in the presentation's - //! alphabet. + //! \brief Throws if any letter in a range is out of bounds. //! - //! Check if every letter of a word is in the presentation's - //! alphabet. + //! This function throws a LibsemigroupsException if any value pointed + //! at by an iterator in the range \p first to \p last is out of bounds + //! (i.e. does not belong to the alphabet of the \ref presentation used + //! to construct the \ref Kambites instance). //! - //! \throws LibsemigroupsException if there is a letter of \p w not in the - //! presentations alphabet. + //! \tparam Iterator1 the type of first argument \p first. + //! \tparam Iterator2 the type of second argument \p last. //! - //! \param w word to validate. + //! \param first iterator pointing at the first letter of the word. + //! \param last iterator pointing one beyond the last letter of the + //! word. //! - //! \sa Presentation::validate_word. - // TODO(0) remove - void validate_word(word_type const& w) const { - ToString to_string(presentation().alphabet()); - std::string s = to_string(w); - presentation().validate_word(s.cbegin(), s.cend()); - } - + //! \throw LibsemigroupsException if any letter in the range from \p + //! first to \p last is out of bounds. template void throw_if_letter_out_of_bounds(Iterator1 first, Iterator2 last) const { presentation().validate_word(first, last); } - //! \brief Return the presentation defined by the rewriting system + //! \brief Return the presentation defined by the rewriting system. //! - //! Return the presentation defined by the rewriting system + //! This function returns the presentation defined by the rewriting system. //! //! \returns //! A const reference to the presentation, a value of type - //! Presentation const&. + //! ``Presentation const&``. //! //! \exceptions //! \noexcept @@ -745,58 +944,53 @@ namespace libsemigroups { return _presentation; } - // TODO(0) add note about empty active rules after init and non-const-ness - //! \brief Return the current number of active - //! rules in the KnuthBendix instance. + //! \brief Return the current number of active rules in the KnuthBendix + //! instance. //! - //! Return the current number of active rules in - //! the KnuthBendix instance. + //! This function returns the current number of active rules in the + //! KnuthBendix instance. //! //! \returns - //! The current number of active rules, a value - //! of type \c size_t. + //! The current number of active rules, a value of type \c size_t. //! //! \exceptions //! \noexcept //! //! \complexity //! Constant. + // TODO(1) this should be const + // TODO(1) add note about empty active rules after init and non-const-ness + // (this only applies if this becomes const) [[nodiscard]] size_t number_of_active_rules() noexcept; - //! \brief Return the current number of inactive - //! rules in the KnuthBendix instance. + //! \brief Return the current number of inactive rules in the KnuthBendix + //! instance. //! - //! Return the current number of inactive rules - //! in the KnuthBendix instance. + //! This function returns the current number of inactive rules in the + //! KnuthBendix instance. //! //! \returns - //! The current number of inactive rules, a - //! value of type \c size_t. + //! The current number of inactive rules, a value of type \c size_t. //! //! \exceptions //! \noexcept //! //! \complexity //! Constant. - //! [[nodiscard]] size_t number_of_inactive_rules() const noexcept { return _rewriter.number_of_inactive_rules(); } - //! \brief Return the number of rules that - //! KnuthBendix has created + //! \brief Return the number of rules that KnuthBendix has created //! - //! Return the total number of Rule instances - //! that have been created whilst whilst the - //! Knuth-Bendix algorithm has been running. - //! Note that this is not the sum of \ref - //! number_of_active_rules and \ref - //! number_of_inactive_rules, due to the - //! re-initialisation of rules where possible. + //! This function returns the total number of Rule instances that have been + //! created whilst whilst the Knuth-Bendix algorithm has been running. Note + //! that this is not the sum of \ref number_of_active_rules and \ref + //! number_of_inactive_rules, due to the re-initialisation of rules where + //! possible. //! //! \returns - //! The total number of rules, a value of type - //! \c size_t. + //! The total number of rules, a value of type \c size_t. //! //! \exceptions //! \noexcept @@ -807,81 +1001,27 @@ namespace libsemigroups { return _rewriter.stats().total_rules; } - // TODO(0) What do we do about doc-ing this? - //! Type of the rules in the system. - using rule_type = std::pair; - - // TODO(0) update the doc, now returns a Range - // TODO(0) add note about empty active rules after - // init - //! \brief Return a copy of the active rules. + //! \brief Return a range object containing the active rules. //! - //! This member function returns a vector consisting of the pairs of - //! strings which represent the rules of the KnuthBendix instance. The \c + //! This function returns a range object containing the pairs of + //! strings which represent the rules of a KnuthBendix instance. The \c //! first entry in every such pair is greater than the \c second according - //! to the reduction ordering of the KnuthBendix instance. The rules are - //! sorted according to the reduction ordering used by the rewriting system, - //! on the first entry. + //! to the reduction ordering of the KnuthBendix instance. //! //! \returns - //! A copy of the currently active rules, a - //! value of type - //! \c std::vector. - //! - //! \complexity - //! \f$O(n)\f$ where \f$n\f$ is the sum of the - //! lengths of the words in rules of \p copy. - [[nodiscard]] auto active_rules() { - using rx::iterator_range; - using rx::transform; - if (_rewriter.number_of_active_rules() == 0 - && _rewriter.number_of_pending_rules() != 0) { - _rewriter.process_pending_rules(); - } - return iterator_range(_rewriter.begin(), _rewriter.end()) - | transform([this](auto const& rule) { - // TODO(1) remove allocation - detail::internal_string_type lhs - = detail::internal_string_type(*rule->lhs()); - detail::internal_string_type rhs - = detail::internal_string_type(*rule->rhs()); - internal_to_external_string(lhs); - internal_to_external_string(rhs); - return std::make_pair(lhs, rhs); - }); - } + //! A range object containing the current active rules. + // TODO(1) should be const + // TODO(1) add note about empty active rules after, or better discuss that + // there are three kinds of rules in the system: active, inactive, and + // pending. + // TODO(1) allow type of words output to be specified + [[nodiscard]] auto active_rules(); private: - // TODO(0) recycle this doc or delete - // TODO add note about empty active rules after - // init and non-const-ness - //! \brief Rewrite a word in-place. - //! - //! The word \p w is rewritten in-place - //! according to the current active rules in the - //! KnuthBendix instance. - //! - //! \param w the word to rewrite. - //! - //! \returns - //! The argument \p w after it has been - //! rewritten. - // TODO update doc + // TODO(1) remove this ... void rewrite_inplace(std::string& w); - // TODO(0) recycle this doc or delete - // TODO add note about empty active rules after - // init and non-const-ness - //! \brief Rewrite a word. - //! - //! Rewrites a copy of the word \p w rewritten according to the current - //! rules in the KnuthBendix instance. - //! - //! \param w the word to rewrite. - //! - //! \returns - //! A copy of the argument \p w after it has - //! been rewritten. + // TODO(1) remove this ... [[nodiscard]] std::string rewrite(std::string w) { rewrite_inplace(w); return w; @@ -910,11 +1050,9 @@ namespace libsemigroups { //! instance is known, and \c false if it is not. [[nodiscard]] bool confluent_known() const noexcept; - // REVIEW None of these \sa's exist anymore. Should it be \ref - // number_of_classes and \ref normal_forms? //! \brief Return the Gilman \ref WordGraph. //! - //! Return the Gilman WordGraph of the system. + //! This function returns the Gilman WordGraph of the system. //! //! The Gilman WordGraph is a digraph where the labels of the paths from //! the initial node (corresponding to the empty word) correspond to the @@ -931,19 +1069,17 @@ namespace libsemigroups { //! \warning This will terminate when the KnuthBendix instance is reduced //! and confluent, which might be never. //! - //! \sa \ref number_of_normal_forms, \ref cbegin_normal_forms, and \ref - //! cend_normal_forms. + //! \sa \ref number_of_classes, and \ref knuth_bendix::normal_forms. WordGraph const& gilman_graph(); - //! \brief Return the node labels of the Gilman - //! \ref WordGraph + //! \brief Return the node labels of the Gilman \ref WordGraph //! - //! Return the node labels of the Gilman \ref WordGraph, corresponding to - //! the unique prefixes of the left-hand sides of the rules of the rewriting - //! system. + //! This function returns the node labels of the Gilman \ref WordGraph, + //! corresponding to the unique prefixes of the left-hand sides of the rules + //! of the rewriting system. //! - //! \return The node labels of the Gilman \ref WordGraph, a value of type - //! \c std::vector. + //! \return The node labels of the Gilman \ref WordGraph, a const reference + //! to a ``std::vector``. //! //! \sa \ref gilman_graph. [[nodiscard]] std::vector const& gilman_graph_node_labels() { @@ -951,55 +1087,16 @@ namespace libsemigroups { return _gilman_graph_node_labels; } + private: ////////////////////////////////////////////////////////////////////////// - // KnuthBendix - attributes - public + // KnuthBendix - private member functions ////////////////////////////////////////////////////////////////////////// - // TODO(0) recycle or delete - //! \brief Check if two inputs are equivalent with respect to the system - //! - //! By first testing \c string equivalence, then by rewriting the inputs, - //! then by running the Knuth-Bendix algorithm and rewriting the inputs with - //! respect to the updated system again, check if \p u and \p v are - //! equivalent. - //! - //! \param u, v the words to test the - //! equivalence of. - //! - //! \returns \c true if \p u is equivalent to \p v, and \c false otherwise. - //! - //! \warning If the inputs don't rewrite to equivalent words with the - //! initial rewriting rules, then the Knuth-Bendix algorithm is run. This - //! terminates when the rewriting system is confluent, which may be never. - //! - //! \sa run. - - // TODO(0) recycle or delete - //! \brief Check containment - //! - //! Check if the pair of words \p u and \p v is - //! contained in within the congruence - //! corresponding to rewriting system. - //! - //! \param u, v the words to check containment - //! of. - //! - //! \returns \c true if the the pair consisting - //! of \p u and \p v is contained within the - //! congruence, and \c false otherwise. - //! - //! \sa \ref equal_to. - // No in-place version just use rewrite instead, - // this only exists so that run is called. - - private: void report_presentation(Presentation const&) const; void report_before_run(); void report_progress_from_thread(std::atomic_bool const&); void report_after_run(); - // TODO(0) remove this use the version in CongruenceInterface - void throw_if_started() const; void stats_check_point(); [[nodiscard]] static detail::internal_char_type @@ -1032,99 +1129,54 @@ namespace libsemigroups { return _rewriter.max_active_word_length(); } - ////////////////////////////////////////////////////////////////////////// - // Runner - pure virtual member functions - private - ////////////////////////////////////////////////////////////////////////// - - void run_impl() override; void run_real(std::atomic_bool&); - bool finished_impl() const override; [[nodiscard]] bool stop_running() const; - }; - //! This friend function allows a KnuthBendix object to be left shifted - //! into a std::ostream, such as std::cout. The currently active rules - //! of the system are represented in the output. - template - std::ostream& operator<<(std::ostream&, - KnuthBendix const&); + ////////////////////////////////////////////////////////////////////////// + // Runner - pure virtual member functions - private + ////////////////////////////////////////////////////////////////////////// - namespace detail { - // TODO put in separate file - template - class KnuthBendixNormalFormRange : public Paths { - using Paths_ = Paths; - - mutable Word _current; - KnuthBendix* _kb; - - public: - using size_type = typename Paths_::size_type; - using output_type = Word const&; - - explicit KnuthBendixNormalFormRange( - KnuthBendix& kb) - : Paths(kb.gilman_graph()), _current(), _kb(&kb) { - // It's possible that the gilman graph is empty, so the call to - // source_no_checks(0) is technically invalid, but nothing goes wrong, - // so we just go with it. This is slightly smelly. - Paths_::source_no_checks(0); - if (!kb.presentation().contains_empty_word()) { - Paths_::next(); - } - } - - output_type get() const { - word_type const& w = Paths_::get(); - _current.clear(); - for (auto c : w) { - _current.push_back(_kb->presentation().letter_no_checks(c)); - } - return _current; - } - - KnuthBendixNormalFormRange& min(size_type val) noexcept { - Paths_::min(val); - return *this; - } - - KnuthBendixNormalFormRange& max(size_type val) noexcept { - Paths_::max(val); - return *this; - } - - using Paths_::at_end; - using Paths_::count; - using Paths_::max; - using Paths_::min; - using Paths_::next; - using Paths_::size_hint; - - static constexpr bool is_finite = true; // this isn't always true! - static constexpr bool is_idempotent = true; - }; // class KnuthBendixNormalFormRange + void run_impl() override; + bool finished_impl() const override; + }; // class KnuthBendix - } // namespace detail +// Special include for the KnuthBendixNormalFormRange, just to avoid cluttering +// this file. +#include "detail/knuth-bendix-nf.hpp" + //! \ingroup knuth_bendix_group + //! + //! \brief Helper functions for the \ref KnuthBendix class. + //! + //! Defined in \c knuth-bendix.hpp. + //! + //! This page contains documentation for some helper functions for the \ref + //! KnuthBendix class. In particular, these functions include versions of + //! several of the member functions of \ref KnuthBendix (that accept + //! iterators) whose parameters are not iterators, but objects instead. The + //! helpers documented on this page all belong to the namespace + //! ``knuth_bendix``. + //! + //! \sa \ref cong_intf_helpers_group namespace knuth_bendix { - //! \defgroup knuth_bendix_helpers_group Knuth-Bendix specific helpers - //! - //! TODO - //! @{ - //////////////////////////////////////////////////////////////////////// // KnuthBendix specific helpers //////////////////////////////////////////////////////////////////////// - // TODO Should this have a param? //! \brief Run the Knuth-Bendix algorithm by considering all overlaps of //! a given length. //! //! This function runs the Knuth-Bendix algorithm on the rewriting //! system represented by a KnuthBendix instance by considering all //! overlaps of a given length \f$n\f$ (according to the \ref - //! options::overlap) before those overlaps of length \f$n + 1\f$. + //! KnuthBendix::options::overlap) before those overlaps of length \f$n + + //! 1\f$. + //! + //! \tparam Rewriter the first template parameter for KnuthBendix. + //! \tparam ReductionOrder the second template parameter for KnuthBendix. + //! + //! \param kb the KnuthBendix instance. //! //! \complexity //! See warning. @@ -1132,41 +1184,25 @@ namespace libsemigroups { //! \warning This will terminate when the KnuthBendix instance is //! confluent, which might be never. //! - //! \sa \ref run. + //! \sa \ref KnuthBendix::run. template - void by_overlap_length(KnuthBendix&); + void by_overlap_length(KnuthBendix& kb); //! \brief Check if the all rules are reduced with respect to each other. //! - //! This function is defined in \c knuth-bendix.hpp. + //! Defined in \c knuth-bendix.hpp. //! - //! \returns \c true if for each pair \f$(A, B)\f$ and \f$(C, D)\f$ of rules - //! stored within the KnuthBendix instance, \f$C\f$ is neither a subword of - //! \f$A\f$ nor \f$B\f$. Returns \c false otherwise. + //! \tparam Rewriter the first template parameter for KnuthBendix. + //! \tparam ReductionOrder the second template parameter for KnuthBendix. //! - //! \tparam Rewriter type of the rewriting system to be used in the - //! Knuth-Bendix algorithm. - //! \tparam ReductionOrder type of the reduction ordering used by the - //! Knuth-Bendix algorithm. //! \param kb the KnuthBendix instance defining the rules that are to be //! checked for being reduced. + //! + //! \returns \c true if for each pair \f$(A, B)\f$ and \f$(C, D)\f$ of rules + //! stored within the KnuthBendix instance, \f$C\f$ is neither a subword of + //! \f$A\f$ nor \f$B\f$. Returns \c false otherwise. template - [[nodiscard]] bool is_reduced(KnuthBendix& kb) { - for (auto const& test_rule : kb.active_rules()) { - auto const lhs = test_rule.first; - for (auto const& rule : kb.active_rules()) { - if (test_rule == rule) { - continue; - } - - if (rule.first.find(lhs) != detail::internal_string_type::npos - || rule.second.find(lhs) != detail::internal_string_type::npos) { - return false; - } - } - } - return true; - } + [[nodiscard]] bool is_reduced(KnuthBendix& kb); //////////////////////////////////////////////////////////////////////// // Interface helpers - add_generating_pair @@ -1197,36 +1233,29 @@ namespace libsemigroups { // Interface helpers - normal_forms //////////////////////////////////////////////////////////////////////// - //! \brief Return a forward iterator pointing at the first normal form with - //! length in a given range. + //! \brief Returns a range object containing the normal forms. //! - //! If incremented, the iterator will point to the next least short-lex - //! normal form (if it's less than \p max in length). Iterators of the - //! type returned by this function should only be compared with other - //! iterators created from the same KnuthBendix instance. + //! Defined in \c knuth-bendix.hpp. //! - //! \param lphbt the alphabet to use for the normal forms - //! \param min the minimum length of a normal form - //! \param max one larger than the maximum length of a normal form. + //! This function returns a range object containing normal forms of the + //! classes of the congruence represented by an instance of KnuthBendix. The + //! order of the classes, and the normal form that is returned, are + //! controlled by the reduction order used to construct \p kb. This function + //! triggers a full enumeration of \p kb. //! - //! \returns - //! A value of type \ref const_normal_form_iterator. + //! \tparam Word the type of the words contained in the output range + //! (default: std::string). + //! \tparam Rewriter the first template parameter for KnuthBendix. + //! \tparam ReductionOrder the second template parameter for KnuthBendix. //! - //! \exceptions - //! \no_libsemigroups_except + //! \param kb the \ref KnuthBendix instance. //! - //! \warning - //! Copying iterators of this type is relatively expensive. As a - //! consequence, prefix incrementing \c ++it the iterator \c it returned - //! by \c cbegin_normal_forms is significantly cheaper than postfix - //! incrementing \c it++. + //! \returns A range object. //! - //! \warning - //! If the finitely presented semigroup represented by \c this is - //! infinite, then \p max should be chosen with some care. + //! \exceptions + //! \no_libsemigroups_except //! - //! \sa \ref cend_normal_forms. - // TODO update doc + //! \cong_intf_warn_undecidable{Knuth-Bendix}. template @@ -1247,57 +1276,49 @@ namespace libsemigroups { using congruence_interface::non_trivial_classes; - // Compute non-trivial classes in kb1! - template + //! \brief Find the non-trivial classes of the quotient of one KnuthBendix + //! instance in another. + //! + //! This function returns the classes with size at least \f$2\f$ in the + //! normal forms of \p kb2 in \p kb1 (the greater congruence, with fewer + //! classes). This function triggers a full enumeration of both \p kb2 and + //! \p kb1. + //! + //! Note that this function does **not** compute the normal forms of \p kb2 + //! and try to compute the partition of these induced by \p kb1, before + //! filtering out the classes of size \f$1\f$. In particular, it is possible + //! to compute the non-trivial classes of \p kb1 in \p kb2 if there are only + //! finitely many finite such classes, regardless of whether or not \p kb2 + //! or \p kb1 has infinitely many classes. + //! + //! \tparam Word the type of the words contained in the output range + //! (default: std::string). + //! \tparam Rewriter the first template parameter for KnuthBendix. + //! \tparam ReductionOrder the second template parameter for KnuthBendix. + //! + //! \param kb1 the first \ref KnuthBendix instance. + //! \param kb2 the second \ref KnuthBendix instance. + //! + //! \returns The non-trivial classes of \p kb1 in \p kb2. + //! + //! \throws LibsemigroupsException if \p kb1 has infinitely many classes + //! and \p kb2 has finitely many classes (so that there is at least one + //! infinite non-trivial class). + //! + //! \throws LibsemigroupsException if the alphabets of the + //! presentations of \p kb1 and \p kb2 are not equal. + //! + //! \throws LibsemigroupsException if the \ref KnuthBendix::gilman_graph of + //! \p kb1 has fewer nodes than that of \p kb2. + //! + //! \cong_intf_warn_undecidable{Knuth-Bendix}. + template [[nodiscard]] std::vector> non_trivial_classes(KnuthBendix& kb1, KnuthBendix& kb2); - // TODO(0) move all of the functions from here to the end of the namespace - // knuth_bendix to before the interface helpers when they are out of lined. - - //////////////////////////////////////////////////////////////////////// - // Possible future interface helpers - try_equal_to - //////////////////////////////////////////////////////////////////////// - - // TODO Doc - template - inline tril try_equal_to(Presentation& p, - std::string const& lhs, - std::string const& rhs, - T t = std::chrono::seconds(1)) { - constexpr static congruence_kind twosided = congruence_kind::twosided; - - // TODO validate lhs and rhs - KnuthBendix kb(twosided, p); - std::string lphbt = p.alphabet(); - std::vector perm(lphbt.size(), 0); - std::iota(perm.begin(), perm.end(), 0); - - do { - detail::apply_permutation(lphbt, perm); - - p.alphabet(lphbt); - p.validate(); - - kb.init(twosided, p); - // TODO(0) no checks - if (reduce_no_run(kb, lhs) == reduce_no_run(kb, rhs)) { - return tril::TRUE; - } - kb.run_for(t); - // TODO(0) no checks - if (reduce_no_run(kb, lhs) == reduce_no_run(kb, rhs)) { - return tril::TRUE; - } else if (kb.finished()) { - return tril::FALSE; - } - } while (std::next_permutation(perm.begin(), perm.end())); - return tril::unknown; - } - //////////////////////////////////////////////////////////////////////// // Possible future interface helpers - redundant_rule //////////////////////////////////////////////////////////////////////// @@ -1305,7 +1326,7 @@ namespace libsemigroups { //! \brief Return an iterator pointing at the left hand side of a redundant //! rule. //! - //! This function is defined in \c knuth-bendix.hpp. + //! Defined in \c knuth-bendix.hpp. //! //! Starting with the last rule in the presentation, this function //! attempts to run the Knuth-Bendix algorithm on the rules of the @@ -1320,44 +1341,28 @@ namespace libsemigroups { //! iterator pointing to its left hand side is returned. //! //! If no rule can be shown to be redundant in this way, then an iterator - //! pointing to \c p.cend() is returned. + //! pointing to \c p.rules.cend() is returned. //! - //! \tparam T type of the 2nd parameter (time to try running - //! Knuth-Bendix). \param p the presentation \param t time to run - //! KnuthBendix for every omitted rule + //! \tparam Time type of the 2nd parameter (time to try running + //! Knuth-Bendix). + //! \param p the presentation. + //! \param t time to run KnuthBendix for every omitted rule. + //! + //! \returns An iterator pointing at the left-hand side of a redundant rule + //! of \c p.rules.cend(). //! //! \warning The progress of the Knuth-Bendix algorithm may differ between //! different calls to this function even if the parameters are identical. //! As such this is non-deterministic, and may produce different results //! with the same input. - template - [[nodiscard]] auto redundant_rule(Presentation const& p, T t) { - constexpr static congruence_kind twosided = congruence_kind::twosided; - - p.validate(); - Presentation q; - q.alphabet(p.alphabet()); - q.contains_empty_word(p.contains_empty_word()); - KnuthBendix kb; - - for (auto omit = p.rules.crbegin(); omit != p.rules.crend(); omit += 2) { - q.rules.clear(); - q.rules.insert(q.rules.end(), p.rules.crbegin(), omit); - q.rules.insert(q.rules.end(), omit + 2, p.rules.crend()); - kb.init(twosided, q); - kb.run_for(t); - // TODO no_checks - if (reduce_no_run(kb, *omit) == reduce_no_run(kb, *(omit + 1))) { - return (omit + 1).base() - 1; - } - } - return p.rules.cend(); - } + template + [[nodiscard]] std::vector::const_iterator + redundant_rule(Presentation const& p, Time t); //! \brief Return an iterator pointing at the left hand side of a redundant //! rule. //! - //! This function is defined in \c knuth-bendix.hpp. + //! Defined in \c knuth-bendix.hpp. //! //! Starting with the last rule in the presentation, this function //! attempts to run the Knuth-Bendix algorithm on the rules of the @@ -1374,75 +1379,99 @@ namespace libsemigroups { //! If no rule can be shown to be redundant in this way, then an iterator //! pointing to \c p.cend() is returned. //! - //! \tparam W type of words in the Presentation - //! \tparam T type of the 2nd parameter (time to try running - //! Knuth-Bendix). \param p the presentation \param t time to run - //! KnuthBendix for every omitted rule + //! \tparam Word type of words in the Presentation + //! \tparam Time type of the 2nd parameter (time to try running + //! Knuth-Bendix). + //! \param p the presentation. + //! \param t time to run KnuthBendix for every omitted rule. //! //! \warning The progress of the Knuth-Bendix algorithm may differ between //! different calls to this function even if the parameters are identical. //! As such this is non-deterministic, and may produce different results //! with the same input. - template - [[nodiscard]] auto redundant_rule(Presentation const& p, T t) { + template + [[nodiscard]] auto redundant_rule(Presentation const& p, Time t) { auto pp = to_presentation(p); return p.rules.cbegin() + std::distance(pp.rules.cbegin(), redundant_rule(pp, t)); } - //! @} - } // namespace knuth_bendix - // TODO to tpp file - // TODO to to_presentation file - template - Presentation - to_presentation(KnuthBendix& kb) { - if constexpr (std::is_same_v) { - auto const& p_orig = kb.presentation(); - Presentation p; - p.alphabet(p_orig.alphabet()) - .contains_empty_word(p_orig.contains_empty_word()); - - for (auto const& rule : kb.active_rules()) { - presentation::add_rule(p, rule.first, rule.second); - } - return p; - } else { - return to_presentation(to_presentation(kb)); - } - } + //////////////////////////////////////////////////////////////////////// + // Possible future interface helpers - try_equal_to + //////////////////////////////////////////////////////////////////////// + + // TODO(1) Doc + // TODO(1) template std::string + // TODO(1) re-include later + // template + // inline tril try_equal_to(Presentation& p, + // std::string const& lhs, + // std::string const& rhs, + // T t = std::chrono::seconds(1)); + } // namespace knuth_bendix //////////////////////////////////////////////////////////////////////// // global functions - to_human_readable_repr //////////////////////////////////////////////////////////////////////// - // TODO(0) What should the \param be? + //! \ingroup knuth_bendix_group + //! + //! \brief Insert into std::ostream. + //! + //! This function allows a KnuthBendix object to be left shifted + //! into a std::ostream, such as std::cout. The currently active rules + //! of the system are represented in the output. + //! + //! \param os the output stream to insert into. + //! \param kb the KnuthBendix object. + //! + //! \returns A reference to the first argument. + template + std::ostream& operator<<(std::ostream& os, + KnuthBendix const& kb); + + //! \ingroup knuth_bendix_group + //! //! \brief Return a string representation of a KnuthBendix instance //! - //! Return a string representation of a KnuthBendix instance, specifying the - //! size of the underlying alphabet and the number of active rules. + //! This function returns a string representation of a KnuthBendix instance, + //! specifying the size of the underlying alphabet and the number of active + //! rules. + //! + //! \tparam Rewriter the first template parameter for KnuthBendix. + //! \tparam ReductionOrder the second template parameter for KnuthBendix. + //! + //! \param kb the KnuthBendix instance. //! //! \returns The representation, a value of type \c std::string - // TODO(0) rename to_human_readable_repr + // TODO(1) preferably kb would be a const& template - std::string repr(KnuthBendix& kb) { - using str = std::string; - - str conf; - if (!kb.confluent_known()) { - conf = "KnuthBendix"; - } else if (kb.confluent()) { - conf = "confluent KnuthBendix"; - } else { - conf = "non-confluent KnuthBendix"; - } - str alphabet_size = std::to_string(kb.presentation().alphabet().size()); - str n_rules = std::to_string(kb.number_of_active_rules()); + std::string to_human_readable_repr(KnuthBendix& kb); - // TODO(JE) use fmt::format instead - return str("<") + conf + " on " + alphabet_size + " letters with " + n_rules - + " active rules>"; - } + //! \ingroup to_presentation_group + //! + //! \brief Make a presentation from a KnuthBendix object. + //! + //! This function constructs and returns a Presentation object using the + //! currently active rules of \p kb. + //! + //! No enumeration of the argument \p kb is performed, so it might be the + //! case that the resulting presentation does not define the same + //! semigroup/monoid as \p kb. To ensure that the resulting presentation + //! defines the same semigroup as \p kb, run KnuthBendix::run (or any other + //! function that fully enumerates \p kb) prior to calling this function. + //! + //! \tparam Word the type of the rules in the presentation being constructed. + //! + //! \param kb the KnuthBendix object from which to obtain the rules. + //! + //! \returns An object of type \c Presentation. + //! + //! \exceptions + //! \no_libsemigroups_except + // This cannot go into to-presentation.hpp since we include that here + template + Presentation to_presentation(KnuthBendix& kb); } // namespace libsemigroups #include "knuth-bendix.tpp" diff --git a/include/libsemigroups/knuth-bendix.tpp b/include/libsemigroups/knuth-bendix.tpp index 1cb1005bd..00b675aa7 100644 --- a/include/libsemigroups/knuth-bendix.tpp +++ b/include/libsemigroups/knuth-bendix.tpp @@ -91,8 +91,8 @@ namespace libsemigroups { template typename KnuthBendix::Settings& KnuthBendix::Settings::init() noexcept { - // TODO experiment with starting size to optimise speed. - batch_size = 128; + // TODO(1) experiment with starting size to optimise speed. + max_pending_rules = 128; check_confluence_interval = 4'096; max_overlap = POSITIVE_INFINITY; max_rules = POSITIVE_INFINITY; @@ -185,7 +185,7 @@ namespace libsemigroups { template KnuthBendix& KnuthBendix::operator=(KnuthBendix&& that) { - CongruenceInterface::operator=(std::move(that)); // TODO correct? + CongruenceInterface::operator=(std::move(that)); _gen_pairs_initted = std::move(that._gen_pairs_initted); _gilman_graph = std::move(that._gilman_graph); _gilman_graph_node_labels = std::move(that._gilman_graph_node_labels); @@ -277,7 +277,6 @@ namespace libsemigroups { template uint64_t KnuthBendix::number_of_classes() { - // TODO uncomment if (is_obviously_infinite(*this)) { return POSITIVE_INFINITY; } @@ -291,13 +290,73 @@ namespace libsemigroups { } } - // template - // std::string - // KnuthBendix::normal_form(std::string const& w) { - // presentation().validate_word(w.cbegin(), w.cend()); - // run(); - // return rewrite(w); - // } + template + template + [[nodiscard]] tril + KnuthBendix::currently_contains_no_checks( + Iterator1 first1, + Iterator2 last1, + Iterator3 first2, + Iterator4 last2) const { + if (std::equal(first1, last1, first2, last2)) { + return tril::TRUE; + } + // TODO(1) remove allocations here + std::string w1, w2; + reduce_no_run_no_checks(std::back_inserter(w1), first1, last1); + reduce_no_run_no_checks(std::back_inserter(w2), first2, last2); + if (w1 == w2) { + return tril::TRUE; + } else if (finished()) { + return tril::FALSE; + } + return tril::unknown; + } + + template + template + OutputIterator KnuthBendix::reduce_no_run_no_checks( + OutputIterator d_first, + InputIterator1 first, + InputIterator2 last) const { + // TODO(1) improve this to not require _tmp_element1 + if constexpr (std::is_same_v) { + static_assert(std::is_same_v); + _tmp_element1.assign(first, std::distance(first, last)); + } else { + _tmp_element1.assign(first, last); + } + const_cast&>(*this).rewrite_inplace( + _tmp_element1); + return std::copy( + std::begin(_tmp_element1), std::end(_tmp_element1), d_first); + } + + template + [[nodiscard]] auto KnuthBendix::active_rules() { + using rx::iterator_range; + using rx::transform; + if (_rewriter.number_of_active_rules() == 0 + && _rewriter.number_of_pending_rules() != 0) { + _rewriter.process_pending_rules(); + } + return iterator_range(_rewriter.begin(), _rewriter.end()) + | transform([this](auto const& rule) { + // TODO(1) remove allocation + detail::internal_string_type lhs + = detail::internal_string_type(*rule->lhs()); + detail::internal_string_type rhs + = detail::internal_string_type(*rule->rhs()); + internal_to_external_string(lhs); + internal_to_external_string(rhs); + return std::make_pair(lhs, rhs); + }); + } template void KnuthBendix::report_presentation( @@ -389,8 +448,6 @@ namespace libsemigroups { rc.min_width(12); // .divider("{:-<95}\n"); rc("KnuthBendix: RUN STATISTICS\n"); // rc.divider(); - // FIXME these are mostly 0, and should be obtained from the rewriter - // probably rc("KnuthBendix: max stack depth {}\n", group_digits(_rewriter.max_stack_depth())); rc("KnuthBendix: max rule length {}\n", @@ -444,15 +501,6 @@ namespace libsemigroups { // KnuthBendix - other methods - private ////////////////////////////////////////////////////////////////////////// - template - void KnuthBendix::throw_if_started() const { - if (started()) { - LIBSEMIGROUPS_EXCEPTION( - "the presentation cannot be changed after Knuth-Bendix has " - "started, maybe try `init` instead?"); - } - } - template void KnuthBendix::stats_check_point() { _stats.prev_active_rules = number_of_active_rules(); @@ -469,7 +517,6 @@ namespace libsemigroups { return _rewriter.confluence_known(); } - // TODO should this check for 0 active rules? template bool KnuthBendix::confluent() const { if (_rewriter.number_of_active_rules() == 0 @@ -517,8 +564,8 @@ namespace libsemigroups { } } - // TODO (When the rewriters have a pointer to the KB instance) move this into - // the rewriter + // TODO(1) (When the rewriters have a pointer to the KB instance) move this + // into the rewriter template void KnuthBendix::run_real(std::atomic_bool& pause) { @@ -552,14 +599,14 @@ namespace libsemigroups { if (nr > _settings.check_confluence_interval) { pause = true; - // Checking confluence requires there to be no pending rules which, in - // general, isn't the case at this point in the loop (other than when - // nr is a common multiple of batch_size and + // Checking confluence requires there to be no pending rules which, + // in general, isn't the case at this point in the loop (other than + // when nr is a common multiple of max_pending_rules and // confluence_check_interval). Therefore, it might make sense to // process any remaining rules before checking confluence. However, // this seems to worsen performance on the test cases, so it remains // to see what the best option is for default behaviour. - // TODO should we process rules here too? + // TODO(1) should we process rules here too? // _rewriter.process_pending_rules(); if (confluent()) { pause = false; @@ -753,7 +800,7 @@ namespace libsemigroups { KnuthBendix::uint_to_internal_char(size_t a) { // Ensure that the input value doesn't overflow the internal char type, // seems legit to me - // TODO should this be + // TODO(1) should this be // std::numeric_limits::max() - // std::numeric_limits::min()? LIBSEMIGROUPS_ASSERT( @@ -771,8 +818,8 @@ namespace libsemigroups { template typename detail::internal_string_type KnuthBendix::uint_to_internal_string(size_t i) { - // TODO What is this check for? - // TODO should this be + // TODO(1) What is this check for? + // TODO(1) should this be // std::numeric_limits::max() - // std::numeric_limits::min()? LIBSEMIGROUPS_ASSERT( @@ -852,7 +899,7 @@ namespace libsemigroups { // KnuthBendixImpl - methods for rules - private ////////////////////////////////////////////////////////////////////////// - // TODO move this to the single call site + // TODO(1) move this to the single call site template void KnuthBendix::init_from_presentation() { auto const& p = _presentation; @@ -911,7 +958,8 @@ namespace libsemigroups { vlhs.cend()); // rule = AQ_j -> Q_iC _rewriter.add_pending_rule(x, y); - if (_rewriter.number_of_pending_rules() >= _settings.batch_size) { + if (_rewriter.number_of_pending_rules() + >= _settings.max_pending_rules) { _rewriter.process_pending_rules(); } // It can be that the iterator `it` is invalidated by the call to @@ -922,95 +970,96 @@ namespace libsemigroups { // will be considered later, because when the rule `u` is reactivated it // is added to the end of the active rules list. - // TODO remove some of the above checks, since now rules don't get + // TODO(1) remove some of the above checks, since now rules don't get // processed after being added. } } } namespace knuth_bendix { + // We are computing non_trivial_classes with respect to kb2 (the greater // congruence, with fewer classes) // // This should work ok if kb1 and kb2 represent different kinds of // congruence. - template + template std::vector> non_trivial_classes(KnuthBendix& kb1, KnuthBendix& kb2) { using rx::operator|; - // It is intended that kb1 is defined using the same presentation as kb2 + // It is intended that kb2 is defined using the same presentation as kb1 // and some additional rules. The output might still be meaningful if // this is not the case. - if (kb2.number_of_classes() == POSITIVE_INFINITY - && kb1.number_of_classes() != POSITIVE_INFINITY) { + if (kb1.number_of_classes() == POSITIVE_INFINITY + && kb2.number_of_classes() != POSITIVE_INFINITY) { LIBSEMIGROUPS_EXCEPTION( "the 1st argument defines an infinite semigroup, and the 2nd " "argument defines a finite semigroup, so there is at least one " "infinite non-trivial class!"); - } else if (kb2.presentation().alphabet() - != kb1.presentation().alphabet()) { + } else if (kb1.presentation().alphabet() + != kb2.presentation().alphabet()) { // It might be possible to handle this case too, // but doesn't seem worth it at present LIBSEMIGROUPS_EXCEPTION("the arguments must have presentations with " "the same alphabets, found {} and {}", - kb2.presentation().alphabet(), - kb1.presentation().alphabet()); + kb1.presentation().alphabet(), + kb2.presentation().alphabet()); } // We construct the WordGraph `wg` obtained by subtracting all of the - // edges from the Gilman graph of kb1 from the Gilman graph of kb2. The + // edges from the Gilman graph of kb2 from the Gilman graph of kb1. The // non-trivial classes are finite if and only if `wg` is acyclic. It // would be possible to do this without actually constructing `wg` but // constructing `wg` is simpler, and so we do that for now. - auto g2 = kb2.gilman_graph(); auto g1 = kb1.gilman_graph(); + auto g2 = kb2.gilman_graph(); - LIBSEMIGROUPS_ASSERT(g2.number_of_nodes() > 0); LIBSEMIGROUPS_ASSERT(g1.number_of_nodes() > 0); + LIBSEMIGROUPS_ASSERT(g2.number_of_nodes() > 0); - if (g2.number_of_nodes() < g1.number_of_nodes()) { + if (g1.number_of_nodes() < g2.number_of_nodes()) { LIBSEMIGROUPS_EXCEPTION( - "the Gilman digraph of the 1st argument must have at least as many " - "nodes as the Gilman digraph of the 2nd argument, found {} nodes " + "the Gilman graph of the 1st argument must have strictly fewer " + "nodes than the Gilman graph of the 2nd argument, found {} nodes " "and {} nodes", - g2.number_of_nodes(), - g1.number_of_nodes()); + g1.number_of_nodes(), + g2.number_of_nodes()); } // We need to obtain a mappings from the nodes of - // g2 to g1 and vice versa. + // g1 to g2 and vice versa. - using node_type = typename decltype(g2)::node_type; + using node_type = typename decltype(g1)::node_type; - std::vector to_g1(g2.number_of_nodes(), - static_cast(UNDEFINED)); - to_g1[0] = 0; std::vector to_g2(g1.number_of_nodes(), static_cast(UNDEFINED)); to_g2[0] = 0; - for (auto v : g2.nodes()) { - for (auto e : g2.labels()) { - auto ve2 = g2.target_no_checks(v, e); - if (to_g1[v] != UNDEFINED && ve2 != UNDEFINED) { - auto ve1 = g1.target_no_checks(to_g1[v], e); - if (ve1 != UNDEFINED && to_g1[ve2] == UNDEFINED) { - to_g1[ve2] = ve1; + std::vector to_g1(g2.number_of_nodes(), + static_cast(UNDEFINED)); + to_g1[0] = 0; + for (auto v : g1.nodes()) { + for (auto e : g1.labels()) { + auto ve1 = g1.target_no_checks(v, e); + if (to_g2[v] != UNDEFINED && ve1 != UNDEFINED) { + auto ve2 = g2.target_no_checks(to_g2[v], e); + if (ve2 != UNDEFINED && to_g2[ve1] == UNDEFINED) { to_g2[ve1] = ve2; + to_g1[ve2] = ve1; } } } } // We do a depth first search simultaneously for cycles, and edges E in - // g2 not in g1. Pre order for cycle detection, post order for "can we + // g1 not in g2. Pre order for cycle detection, post order for "can we // reach a node incident to an edge in E" and "number of paths through a // node is infinite" - size_t const N = g2.number_of_nodes(); + size_t const N = g1.number_of_nodes(); // can_reach[v] == true if there is a path from v to a node incident to - // an edge in g2 that's not in g1. + // an edge in g1 that's not in g2. std::vector can_reach(N, false); std::vector inf_paths(N, false); std::vector seen(N, false); @@ -1024,8 +1073,8 @@ namespace libsemigroups { if (v >= N) { // post order v -= N; - for (auto e : g2.labels()) { - auto ve = g2.target_no_checks(v, e); + for (auto e : g1.labels()) { + auto ve = g1.target_no_checks(v, e); if (ve != UNDEFINED) { can_reach[v] = (can_reach[v] || can_reach[ve]); if (can_reach[ve]) { @@ -1042,49 +1091,49 @@ namespace libsemigroups { // so we can tell when all of the descendants of v have been // processed out of the stack stck.push(v + N); - if (to_g1[v] == UNDEFINED) { + if (to_g2[v] == UNDEFINED) { can_reach[v] = true; } - for (auto e : g2.labels()) { - auto ve2 = g2.target_no_checks(v, e); - if (ve2 != UNDEFINED) { - // Check if (v, e, ve2) corresponds to an edge in g1 + for (auto e : g1.labels()) { + auto ve1 = g1.target_no_checks(v, e); + if (ve1 != UNDEFINED) { + // Check if (v, e, ve1) corresponds to an edge in g2 if (!can_reach[v]) { - auto ve1 = g1.target_no_checks(to_g1[v], e); - if (ve1 != UNDEFINED) { - // edges (v, e, ve2) and (to_g1[v], e, ve1) exist, so - // there's an edge in g2 not in g1 if the targets of these + auto ve2 = g2.target_no_checks(to_g2[v], e); + if (ve2 != UNDEFINED) { + // edges (v, e, ve1) and (to_g2[v], e, ve2) exist, so + // there's an edge in g1 not in g2 if the targets of these // edges do not correspond to each other. - can_reach[v] = (ve2 != to_g2[ve1]); + can_reach[v] = (ve1 != to_g1[ve2]); } else { // There's no edge labelled by e incident to the node - // corresponding to v in g1, but there is such an edge in g2 - // and so (v, e, ve2) is in g2 but not g1. + // corresponding to v in g2, but there is such an edge in g1 + // and so (v, e, ve1) is in g1 but not g2. can_reach[v] = true; } } - if (seen[ve2]) { + if (seen[ve1]) { // cycle detected inf_paths[v] = true; } else { - stck.push(ve2); + stck.push(ve1); } } } } } - // If we reach here, then the appropriate portion of g2 is acyclic, and + // If we reach here, then the appropriate portion of g1 is acyclic, and // so all we do is enumerate the paths in that graph - // Construct the "can_reach" subgraph of g2, could use a WordGraphView - // here instead (but these don't yet exist) TODO(later) - WordGraph wg(g2.number_of_nodes(), g2.out_degree()); + // Construct the "can_reach" subgraph of g1, could use a WordGraphView + // here instead (but these don't yet exist) TODO(1) + WordGraph wg(g1.number_of_nodes(), g1.out_degree()); for (auto v : wg.nodes()) { if (can_reach[v]) { for (auto e : wg.labels()) { - auto ve = g2.target_no_checks(v, e); + auto ve = g1.target_no_checks(v, e); if (ve != UNDEFINED && can_reach[ve]) { wg.target_no_checks(v, e, ve); } @@ -1094,44 +1143,64 @@ namespace libsemigroups { Paths paths(wg); // We only want those paths that pass through at least one of the edges - // in g2 but not g1. Hence we require the `filter` in the next + // in g1 but not g2. Hence we require the `filter` in the next // expression. - auto words = (paths.source(0) | rx::filter([&g1](word_type const& path) { + auto words = (paths.source(0) | rx::filter([&g2](word_type const& path) { return word_graph::last_node_on_path( - g1, 0, path.cbegin(), path.cend()) + g2, 0, path.cbegin(), path.cend()) .second != path.cend(); })); // The check in the next loop could be put into the lambda passed to // filter above, but then we'd have to convert `path` to a string, and // then discard the string, so better to do it here. Note that the - // normal forms in `kb1` never contain an edge in g2 \ g1 and so we must + // normal forms in `kb2` never contain an edge in g1 \ g2 and so we must // add in every normal form. if constexpr (std::is_same_v) { auto ntc - = partition(kb1, words | ToString(kb2.presentation().alphabet())); - for (auto& klass : ntc) { - klass.push_back(reduce_no_checks(kb1, klass[0])); - } - return ntc; - } else if (!std::is_same_v) { - auto ntc - = partition(kb1, (words | rx::transform([](word_type const& w) { - return Word(w.begin(), w.end()); - }))); + = partition(kb2, words | ToString(kb1.presentation().alphabet())); for (auto& klass : ntc) { - klass.push_back(reduce_no_checks(kb1, klass[0])); + klass.push_back(reduce_no_checks(kb2, klass[0])); } return ntc; } else { - auto ntc = partition(kb1, words); + auto ntc = partition(kb2, + words | ToString(kb1.presentation().alphabet()) + | rx::transform([](auto const& w) { + return Word(w.begin(), w.end()); + })); for (auto& klass : ntc) { - klass.push_back(reduce_no_checks(kb1, klass[0])); + klass.push_back(reduce_no_checks(kb2, klass[0])); } return ntc; } } + template + [[nodiscard]] std::vector::const_iterator + redundant_rule(Presentation const& p, T t) { + constexpr static congruence_kind twosided = congruence_kind::twosided; + + p.validate(); + Presentation q; + q.alphabet(p.alphabet()); + q.contains_empty_word(p.contains_empty_word()); + KnuthBendix kb; + + for (auto omit = p.rules.crbegin(); omit != p.rules.crend(); omit += 2) { + q.rules.clear(); + q.rules.insert(q.rules.end(), p.rules.crbegin(), omit); + q.rules.insert(q.rules.end(), omit + 2, p.rules.crend()); + kb.init(twosided, q); + kb.run_for(t); + if (reduce_no_run_no_checks(kb, *omit) + == reduce_no_run_no_checks(kb, *(omit + 1))) { + return (omit + 1).base() - 1; + } + } + return p.rules.cend(); + } + template void by_overlap_length(KnuthBendix& kb) { size_t prev_max_overlap = kb.max_overlap(); @@ -1147,6 +1216,59 @@ namespace libsemigroups { kb.check_confluence_interval(prev_check_confluence_interval); } + template + [[nodiscard]] bool is_reduced(KnuthBendix& kb) { + for (auto const& test_rule : kb.active_rules()) { + auto const lhs = test_rule.first; + for (auto const& rule : kb.active_rules()) { + if (test_rule == rule) { + continue; + } + + if (rule.first.find(lhs) != detail::internal_string_type::npos + || rule.second.find(lhs) != detail::internal_string_type::npos) { + return false; + } + } + } + return true; + } + + // template + // tril try_equal_to(Presentation& p, + // std::string const& lhs, + // std::string const& rhs, + // T t) { + // constexpr static congruence_kind twosided = congruence_kind::twosided; + + // // TODO(1) validate lhs and rhs + // KnuthBendix kb(twosided, p); + // std::string lphbt = p.alphabet(); + // std::vector perm(lphbt.size(), 0); + // std::iota(perm.begin(), perm.end(), 0); + + // do { + // detail::apply_permutation(lphbt, perm); + + // p.alphabet(lphbt); + // p.validate(); + + // kb.init(twosided, p); + // // TODO(1) no checks + // if (reduce_no_run(kb, lhs) == reduce_no_run(kb, rhs)) { + // return tril::TRUE; + // } + // kb.run_for(t); + // // TODO(1) no checks + // if (reduce_no_run(kb, lhs) == reduce_no_run(kb, rhs)) { + // return tril::TRUE; + // } else if (kb.finished()) { + // return tril::FALSE; + // } + // } while (std::next_permutation(perm.begin(), perm.end())); + // return tril::unknown; + // } + } // namespace knuth_bendix template @@ -1155,4 +1277,47 @@ namespace libsemigroups { os << kb.active_rules(); return os; } + + template + std::string + to_human_readable_repr(KnuthBendix& kb) { + std::string conf, genpairs; + if (kb.confluent_known()) { + conf = "confluent"; + if (!kb.confluent()) { + conf = "non-" + conf; + } + } + if (kb.number_of_generating_pairs() != 0) { + genpairs = fmt::format("{} generating pairs + ", + kb.number_of_generating_pairs()); + } + + return fmt::format( + "<{}{} KnuthBendix over {} with {}{}/{} active/inactive rules>", + conf, + kb.kind() == congruence_kind::twosided ? " 2-sided" : " 1-sided", + to_human_readable_repr(kb.presentation()), + genpairs, + kb.number_of_active_rules(), + kb.number_of_inactive_rules()); + } + + template + Presentation + to_presentation(KnuthBendix& kb) { + if constexpr (std::is_same_v) { + auto const& p_orig = kb.presentation(); + Presentation p; + p.alphabet(p_orig.alphabet()) + .contains_empty_word(p_orig.contains_empty_word()); + + for (auto const& rule : kb.active_rules()) { + presentation::add_rule(p, rule.first, rule.second); + } + return p; + } else { + return to_presentation(to_presentation(kb)); + } + } } // namespace libsemigroups diff --git a/include/libsemigroups/to-presentation.hpp b/include/libsemigroups/to-presentation.hpp index 0292bbfb4..7b31678b8 100644 --- a/include/libsemigroups/to-presentation.hpp +++ b/include/libsemigroups/to-presentation.hpp @@ -47,17 +47,16 @@ namespace libsemigroups { //! semigroup as \p fp, run FroidurePin::run (or any other function that //! fully enumerates \p fp) prior to calling this function. //! - //! \tparam WordOutput the type of the presentation to construct (must be a - //! type of Presentation). + //! \tparam Word the type of the rules in the presentation being constructing. //! //! \param fp the FroidurePin object from which to obtain the rules. //! - //! \returns An object of type \c Presentation. + //! \returns An object of type \c Presentation. //! //! \exceptions //! \no_libsemigroups_except - template - Presentation to_presentation(FroidurePinBase& fp); + template + Presentation to_presentation(FroidurePinBase& fp); #ifdef PARSED_BY_DOXYGEN //! \ingroup to_presentation_group diff --git a/include/libsemigroups/todd-coxeter.hpp b/include/libsemigroups/todd-coxeter.hpp index 8c72526e1..8b7139493 100644 --- a/include/libsemigroups/todd-coxeter.hpp +++ b/include/libsemigroups/todd-coxeter.hpp @@ -1093,6 +1093,36 @@ namespace libsemigroups { make_citow(last2)); } + //! \brief Check containment of a pair of words via iterators. + //! + //! This function checks whether or not the words represented by the ranges + //! \p first1 to \p last1 and \p first2 to \p last2 are already known to be + //! contained in the congruence represented by a \ref + //! todd_coxeter_class_group "ToddCoxeter" instance. This function performs + //! no enumeration, so it is possible for the words to be contained in the + //! congruence, but that this is not currently known. + //! + //! \cong_intf_params_contains + //! + //! \returns + //! * tril::TRUE if the words are known to belong to the congruence; + //! * tril::FALSE if the words are known to not belong to the congruence; + //! * tril::unknown otherwise. + //! + //! \cong_intf_throws_if_letters_out_of_bounds + template + tril currently_contains(Iterator1 first1, + Iterator2 last1, + Iterator3 first2, + Iterator4 last2) const { + throw_if_letter_out_of_bounds(first1, last1); + throw_if_letter_out_of_bounds(first2, last2); + return currently_contains_no_checks(first1, last1, first2, last2); + } + //! \brief Check containment of a pair of words via iterators. //! //! This function checks whether or not the words represented by the ranges @@ -1108,6 +1138,7 @@ namespace libsemigroups { //! \cong_intf_warn_undecidable{Todd-Coxeter} //! //! \cong_intf_warn_assume_letters_in_bounds + // TODO(0) out of line this template - tril currently_contains(Iterator1 first1, - Iterator2 last1, - Iterator3 first2, - Iterator4 last2) const { - throw_if_letter_out_of_bounds(first1, last1); - throw_if_letter_out_of_bounds(first2, last2); - return currently_contains_no_checks(first1, last1, first2, last2); - } - //! \brief Check containment of a pair of words via iterators. //! //! This function checks whether or not the words represented by the ranges @@ -3433,7 +3434,7 @@ namespace libsemigroups { //! iterator pointing to its left hand side is returned. //! //! If no rule can be shown to be redundant in this way, then an iterator - //! pointing to \c p.cend() is returned. + //! pointing to \c p.rules.cend() is returned. //! //! \tparam Word type of words in the Presentation. //! \tparam Time type of the 2nd parameter (time to try running @@ -3442,7 +3443,8 @@ namespace libsemigroups { //! \param p the presentation. //! \param t time to run Todd-Coxeter for every omitted rule. //! - //! \returns An iterator. + //! \returns An iterator pointing at the left-hand side of a redundant rule + //! of \c p.rules.cend(). //! //! \warning The progress of the Todd-Coxeter algorithm may differ between //! different calls to this function even if the parameters are identical. @@ -3552,7 +3554,7 @@ namespace libsemigroups { //! //! This function returns a range object containing normal forms of the //! classes of the congruence represented by an instance of ToddCoxeter. The - //! order of the classes, and the normal form, that is returned are + //! order of the classes, and the normal form that is returned, are //! controlled by ToddCoxeter::standardize(Order). This function triggers a //! full enumeration of \p tc. //! @@ -3711,7 +3713,7 @@ namespace libsemigroups { //! libsemigroups::word_type "word_type"). //! //! \param tc1 the \ref todd_coxeter_class_group "ToddCoxeter" instance to - //! use for partition. + //! use for partitioning. //! \param tc2 the \ref todd_coxeter_class_group "ToddCoxeter" instance to //! be partitioned. //! diff --git a/src/cong.cpp b/src/cong.cpp index 74d41685f..917c8f847 100644 --- a/src/cong.cpp +++ b/src/cong.cpp @@ -139,7 +139,7 @@ namespace libsemigroups { && cong.get>()->finished()) { KnuthBendix<> kb(cong.kind(), p); auto strings = ::libsemigroups::knuth_bendix::non_trivial_classes( - *cong.get>(), kb); + kb, *cong.get>()); std::vector> result; for (auto const& klass : strings) { result.push_back(rx::iterator_range(klass.begin(), klass.end()) @@ -162,7 +162,7 @@ namespace libsemigroups { if (cong.has>() && cong.get>()->finished()) { KnuthBendix<> kb(cong.kind(), p); return ::libsemigroups::knuth_bendix::non_trivial_classes( - *cong.get>(), kb); + kb, *cong.get>()); } if (cong.has() && cong.get()->finished()) { ToddCoxeter tc(cong.kind(), p); diff --git a/tests/test-cong.cpp b/tests/test-cong.cpp index 2e4ed5157..bb8379371 100644 --- a/tests/test-cong.cpp +++ b/tests/test-cong.cpp @@ -210,7 +210,7 @@ namespace libsemigroups { REQUIRE(cong.has>()); KnuthBendix<> kb(twosided, p); - REQUIRE(knuth_bendix::non_trivial_classes(*cong.get>(), kb) + REQUIRE(knuth_bendix::non_trivial_classes(kb, *cong.get>()) == std::vector>( {{{1}, {0, 1}, {1, 1}, {0, 1, 1}, {0}}})); @@ -361,7 +361,7 @@ namespace libsemigroups { if (cong.has>()) { KnuthBendix<> kb(twosided, p); REQUIRE_THROWS_AS( - knuth_bendix::non_trivial_classes(*cong.get>(), kb), + knuth_bendix::non_trivial_classes(kb, *cong.get>()), LibsemigroupsException); } else if (cong.has()) { ToddCoxeter tc(twosided, p); @@ -468,7 +468,7 @@ namespace libsemigroups { KnuthBendix<> kb(twosided, p); auto ntc - = knuth_bendix::non_trivial_classes(*cong.get>(), kb); + = knuth_bendix::non_trivial_classes(kb, *cong.get>()); REQUIRE(ntc.size() == 1); REQUIRE(ntc[0].size() == 5); REQUIRE(ntc[0] @@ -580,7 +580,7 @@ namespace libsemigroups { KnuthBendix<> kb(twosided, p); REQUIRE(kb.number_of_classes() == 78); auto ntc - = knuth_bendix::non_trivial_classes(*cong.get>(), kb); + = knuth_bendix::non_trivial_classes(kb, *cong.get>()); REQUIRE(ntc.size() == 1); REQUIRE(ntc[0].size() == 78); } diff --git a/tests/test-knuth-bendix-1.cpp b/tests/test-knuth-bendix-1.cpp index 3ff3591fe..4b9a1f081 100644 --- a/tests/test-knuth-bendix-1.cpp +++ b/tests/test-knuth-bendix-1.cpp @@ -89,12 +89,13 @@ namespace libsemigroups { } } // namespace -#define KNUTH_BENDIX_TYPES \ - KnuthBendix, KnuthBendix + using RewriteTrie = detail::RewriteTrie; + using RewriteFromLeft = detail::RewriteFromLeft; - TEMPLATE_TEST_CASE("confluent fp semigroup 1 (infinite)", - "[000][quick][knuth-bendix][" __FILE__ - "][" STR(__LINE__) "]", +#define KNUTH_BENDIX_TYPES RewriteTrie, RewriteFromLeft + + TEMPLATE_TEST_CASE("KnuthBendix: confluent fp semigroup 1 (infinite)", + "[000][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -102,7 +103,7 @@ namespace libsemigroups { p.rules = {"ab", "ba", "ac", "ca", "aa", "a", "ac", "a", "ca", "a", "bb", "bb", "bc", "cb", "bbb", "b", "bc", "b", "cb", "b", "a", "b"}; - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); @@ -122,7 +123,7 @@ namespace libsemigroups { // REQUIRE(knuth_bendix::is_reduced(kb)); } - TEMPLATE_TEST_CASE("confluent fp semigroup 2 (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: confluent fp semigroup 2 (infinite)", "[001][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -140,7 +141,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "cb", "b"); presentation::add_rule_no_checks(p, "a", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); @@ -154,7 +155,7 @@ namespace libsemigroups { REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); } - TEMPLATE_TEST_CASE("confluent fp semigroup 3 (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: confluent fp semigroup 3 (infinite)", "[002][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -173,7 +174,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "21", "1"); presentation::add_rule_no_checks(p, "0", "1"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); @@ -201,9 +202,10 @@ namespace libsemigroups { "22222222222"})); } - TEMPLATE_TEST_CASE("non-confluent fp semigroup from wikipedia (infinite)", - "[003][quick][knuth-bendix]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: non-confluent fp semigroup from wikipedia (infinite)", + "[003][quick][knuth-bendix]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -213,7 +215,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "111", ""); presentation::add_rule_no_checks(p, "010101", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(kb.presentation().alphabet() == "01"); REQUIRE(!kb.confluent()); kb.run(); @@ -233,7 +235,7 @@ namespace libsemigroups { }))); } - TEMPLATE_TEST_CASE("Example 5.1 in Sims (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: Example 5.1 in Sims (infinite)", "[004][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -247,7 +249,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "dc", ""); presentation::add_rule_no_checks(p, "ca", "ac"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -262,14 +264,15 @@ namespace libsemigroups { "ad", "bb", "bc", "bd", "cc", "dd", "aaa", "aac", "aad", "acc", "add", "bbb", "bbc", "bbd", "bcc", "bdd", "ccc", "ddd", "aaaa", "aaac", "aaad", - "aacc", "aadd", "accc", "addd", "bbbb", "bbbc", "bbbd", - "bbcc", "bbdd", "bccc", "bddd", "cccc", "dddd"})); + "aacc", "aadd", "accc", "addd", // codespell:ignore + "bbbb", "bbbc", "bbbd", "bbcc", "bbdd", "bccc", "bddd", + "cccc", "dddd"})); REQUIRE((nf.min(0).max(6) | all_of([&kb](auto const& w) { return knuth_bendix::reduce(kb, w) == w; }))); } - TEMPLATE_TEST_CASE("Example 5.1 in Sims (infinite) x 2", + TEMPLATE_TEST_CASE("KnuthBendix: Example 5.1 in Sims (infinite) x 2", "[005][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -280,7 +283,7 @@ namespace libsemigroups { presentation::add_inverse_rules(p, "AaBb"); presentation::add_rule_no_checks(p, "ba", "ab"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -302,7 +305,7 @@ namespace libsemigroups { }))); } - TEMPLATE_TEST_CASE("Example 5.3 in Sims", + TEMPLATE_TEST_CASE("KnuthBendix: Example 5.3 in Sims", "[006][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -314,7 +317,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "bbb", ""); presentation::add_rule_no_checks(p, "ababab", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -343,7 +346,7 @@ namespace libsemigroups { }))); } - TEMPLATE_TEST_CASE("Example 5.4 in Sims", + TEMPLATE_TEST_CASE("KnuthBendix: Example 5.4 in Sims", "[007][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -356,7 +359,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "bbb", ""); presentation::add_rule_no_checks(p, "ababab", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -380,7 +383,7 @@ namespace libsemigroups { "baB"})); } - TEMPLATE_TEST_CASE("Example 6.4 in Sims (size 168)", + TEMPLATE_TEST_CASE("KnuthBendix: Example 6.4 in Sims (size 168)", "[008][quick][knuth-bendix][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -395,7 +398,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "ababababababab", ""); presentation::add_rule_no_checks(p, "abacabacabacabac", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); REQUIRE(!is_obviously_infinite(kb)); @@ -418,7 +421,7 @@ namespace libsemigroups { REQUIRE(S.generator(2).string(kb) == "c"); } - TEMPLATE_TEST_CASE("random example", + TEMPLATE_TEST_CASE("KnuthBendix: random example", "[009][quick][knuth-bendix][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -431,24 +434,24 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "010101", "2"); presentation::add_identity_rules(p, '2'); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 9); REQUIRE(kb.confluent()); - auto& ad = kb.gilman_graph(); - REQUIRE(ad.number_of_nodes() == 9); - REQUIRE(ad.number_of_edges() == 13); - REQUIRE(!word_graph::is_acyclic(ad)); + auto& wg = kb.gilman_graph(); + REQUIRE(wg.number_of_nodes() == 9); + REQUIRE(wg.number_of_edges() == 13); + REQUIRE(!word_graph::is_acyclic(wg)); auto fp = to_froidure_pin(kb); fp.enumerate(100); auto expected = froidure_pin::current_normal_forms(fp); - Paths paths(ad); + Paths paths(wg); paths.source(0).min(1).max(fp.current_max_word_length() + 1); REQUIRE(equal(expected, paths)); @@ -462,7 +465,7 @@ namespace libsemigroups { } TEMPLATE_TEST_CASE( - "SL(2, 7) from Chapter 3, Proposition 1.5 in NR (size 336)", + "KnuthBendix: SL(2, 7) from Chapter 3, Proposition 1.5 in NR (size 336)", "[010][quick][knuth-bendix][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -479,7 +482,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "bB", ""); presentation::add_rule_no_checks(p, "Bb", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); @@ -497,18 +500,19 @@ namespace libsemigroups { // monoid presentation REQUIRE(S.number_of_generators() == 5); - auto& ad = kb.gilman_graph(); - REQUIRE(ad.number_of_nodes() == 232); - REQUIRE(ad.number_of_edges() == 265); - REQUIRE(word_graph::is_acyclic(ad)); - Paths paths(ad); + auto& wg = kb.gilman_graph(); + REQUIRE(wg.number_of_nodes() == 232); + REQUIRE(wg.number_of_edges() == 265); + REQUIRE(word_graph::is_acyclic(wg)); + Paths paths(wg); paths.source(0).min(0).max(13); REQUIRE(paths.count() == 336); } - TEMPLATE_TEST_CASE("F(2, 5) - Chapter 9, Section 1 in NR (size 11)", - "[011][knuth-bendix][quick]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: F(2, 5) - Chapter 9, Section 1 in NR (size 11)", + "[011][knuth-bendix][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcde"); @@ -518,7 +522,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "cd", "e"); presentation::add_rule_no_checks(p, "de", "a"); presentation::add_rule_no_checks(p, "ea", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -526,16 +530,16 @@ namespace libsemigroups { REQUIRE(kb.confluent()); REQUIRE(kb.number_of_classes() == 11); - auto& ad = kb.gilman_graph(); - REQUIRE(ad.number_of_nodes() == 8); - REQUIRE(ad.number_of_edges() == 11); - REQUIRE(word_graph::is_acyclic(ad)); - Paths paths(ad); + auto& wg = kb.gilman_graph(); + REQUIRE(wg.number_of_nodes() == 8); + REQUIRE(wg.number_of_edges() == 11); + REQUIRE(word_graph::is_acyclic(wg)); + Paths paths(wg); paths.source(0).min(0).max(5); REQUIRE(paths.count() == 12); } - TEMPLATE_TEST_CASE("Reinis example 1", + TEMPLATE_TEST_CASE("KnuthBendix: Reinis example 1", "[012][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -544,22 +548,22 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "a", "abb"); presentation::add_rule_no_checks(p, "b", "baa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 4); - auto& ad = kb.gilman_graph(); - REQUIRE(ad.number_of_nodes() == 7); - REQUIRE(ad.number_of_edges() == 17); - REQUIRE(!word_graph::is_acyclic(ad)); - Paths paths(ad); + auto& wg = kb.gilman_graph(); + REQUIRE(wg.number_of_nodes() == 7); + REQUIRE(wg.number_of_edges() == 17); + REQUIRE(!word_graph::is_acyclic(wg)); + Paths paths(wg); paths.source(0).min(0).max(10); REQUIRE(paths.count() == 13'044); } - TEMPLATE_TEST_CASE("redundant_rule (std::string)", + TEMPLATE_TEST_CASE("KnuthBendix: redundant_rule (std::string)", "[013][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -579,7 +583,7 @@ namespace libsemigroups { REQUIRE(*(it + 1) == "baa"); } - TEMPLATE_TEST_CASE("redundant_rule (word_type)", + TEMPLATE_TEST_CASE("KnuthBendix: redundant_rule (word_type)", "[014][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { using literals::operator""_w; @@ -601,7 +605,7 @@ namespace libsemigroups { REQUIRE(*(it + 1) == 100_w); } - TEMPLATE_TEST_CASE("constructors/init for finished", + TEMPLATE_TEST_CASE("KnuthBendix: constructors/init for finished", "[015][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -622,7 +626,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p2, "111", ""); presentation::add_rule_no_checks(p2, "010101", ""); - TestType kb1(twosided, p1); + KnuthBendix kb1(twosided, p1); REQUIRE(!kb1.confluent()); REQUIRE(!kb1.finished()); kb1.run(); @@ -648,7 +652,7 @@ namespace libsemigroups { REQUIRE(kb1.confluent_known()); REQUIRE(knuth_bendix::reduce(kb1, "abababbdbcbdbabdbdb") == "bbbbbbddd"); - TestType kb2(std::move(kb1)); + KnuthBendix kb2(std::move(kb1)); REQUIRE(kb2.confluent()); REQUIRE(kb2.confluent_known()); REQUIRE(kb2.finished()); @@ -670,7 +674,7 @@ namespace libsemigroups { REQUIRE(knuth_bendix::reduce(kb1, "abababbdbcbdbabdbdb") == "bbbbbbddd"); } - TEMPLATE_TEST_CASE("constructors/init for partially run", + TEMPLATE_TEST_CASE("KnuthBendix: constructors/init for partially run", "[016][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { using literals::operator""_w; @@ -687,7 +691,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "ababababababab", ""); presentation::add_rule_no_checks(p, "abacabacabacabacabacabacabacabac", ""); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); REQUIRE(!kb1.confluent()); REQUIRE(!kb1.finished()); kb1.run_for(std::chrono::milliseconds(10)); @@ -702,7 +706,7 @@ namespace libsemigroups { REQUIRE(!kb1.confluent()); REQUIRE(!kb1.finished()); - TestType kb2(kb1); + KnuthBendix kb2(kb1); REQUIRE(!kb2.confluent()); REQUIRE(!kb2.finished()); REQUIRE(kb2.presentation() == p); @@ -717,7 +721,7 @@ namespace libsemigroups { REQUIRE(!kb1.finished()); } - TEMPLATE_TEST_CASE("non-trivial classes", + TEMPLATE_TEST_CASE("KnuthBendix: non-trivial classes", "[017][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -733,36 +737,26 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "bc", "b"); presentation::add_rule_no_checks(p, "cb", "b"); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); presentation::add_rule_no_checks(p, "a", "b"); - TestType kb2(twosided, p); - - // TODO uncomment - - // REQUIRE(kb1.gilman_graph() - // == to_word_graph(5, - // {{3, 1, 2}, - // {UNDEFINED, 4}, - // {UNDEFINED, UNDEFINED, 2}, - // {UNDEFINED, 1}})); - - // REQUIRE(kb2.gilman_graph() - // == to_word_graph( - // 3, {{2, UNDEFINED, 1}, {UNDEFINED, UNDEFINED, 1}})); + KnuthBendix kb2(twosided, p); REQUIRE(knuth_bendix::contains(kb2, "a", "b")); REQUIRE(knuth_bendix::contains(kb2, "a", "ba")); REQUIRE(knuth_bendix::contains(kb2, "a", "bb")); REQUIRE(knuth_bendix::contains(kb2, "a", "bab")); - REQUIRE(knuth_bendix::non_trivial_classes(kb2, kb1) + REQUIRE(knuth_bendix::non_trivial_classes(kb1, kb2) == std::vector>( {{"b", "ab", "bb", "abb", "a"}})); + REQUIRE(knuth_bendix::non_trivial_classes(kb1, kb2) + == std::vector>( + {{{98}, {97, 98}, {98, 98}, {97, 98, 98}, {97}}})); } - TEMPLATE_TEST_CASE("non-trivial classes x 2", + TEMPLATE_TEST_CASE("KnuthBendix: non-trivial classes x 2", "[018][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -778,19 +772,19 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "bc", "b"); presentation::add_rule_no_checks(p, "cb", "b"); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); REQUIRE(kb1.number_of_classes() == POSITIVE_INFINITY); presentation::add_rule_no_checks(p, "b", "c"); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); REQUIRE(kb2.number_of_classes() == 2); - REQUIRE_THROWS_AS(knuth_bendix::non_trivial_classes(kb2, kb1), + REQUIRE_THROWS_AS(knuth_bendix::non_trivial_classes(kb1, kb2), LibsemigroupsException); } - TEMPLATE_TEST_CASE("non-trivial classes x 3", + TEMPLATE_TEST_CASE("KnuthBendix: non-trivial classes x 3", "[019][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -806,18 +800,18 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, "bc", "b"); presentation::add_rule_no_checks(p, "cb", "b"); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); presentation::add_rule_no_checks(p, "bb", "a"); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); - REQUIRE(knuth_bendix::non_trivial_classes(kb2, kb1) + REQUIRE(knuth_bendix::non_trivial_classes(kb1, kb2) == std::vector>( {{"ab", "b"}, {"bb", "abb", "a"}})); } - TEMPLATE_TEST_CASE("non-trivial classes x 4", + TEMPLATE_TEST_CASE("KnuthBendix: non-trivial classes x 4", "[020][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -839,19 +833,20 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, 23_w, 2_w); presentation::add_rule_no_checks(p, 32_w, 2_w); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); presentation::add_rule_no_checks(p, 0_w, 1_w); - TestType kb2(twosided, p); - REQUIRE(knuth_bendix::non_trivial_classes(kb2, kb1) + KnuthBendix kb2(twosided, p); + REQUIRE(knuth_bendix::non_trivial_classes(kb1, kb2) == std::vector>( {{{1}, {0, 1}, {1, 1}, {0, 1, 1}, {0}}})); } - TEMPLATE_TEST_CASE("non-trivial congruence on an infinite fp semigroup ", - "[021][quick][knuth-bendix][no-valgrind]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: non-trivial congruence on an infinite fp semigroup ", + "[021][quick][knuth-bendix][no-valgrind]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet(5); @@ -880,7 +875,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, 24_w, 2_w); presentation::add_rule_no_checks(p, 34_w, 3_w); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); WordGraph test_wg1 = to_word_graph( 6, @@ -897,7 +892,7 @@ namespace libsemigroups { (normal_forms_from_word_graph(kb1, test_wg1) | rx::take(1000)))); presentation::add_rule_no_checks(p, 1_w, 2_w); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); WordGraph test_wg2 = to_word_graph( 5, @@ -914,15 +909,16 @@ namespace libsemigroups { REQUIRE(knuth_bendix::contains(kb2, 1_w, 2_w)); - auto ntc = knuth_bendix::non_trivial_classes(kb2, kb1); + auto ntc = knuth_bendix::non_trivial_classes(kb1, kb2); REQUIRE(ntc.size() == 1); REQUIRE(ntc[0].size() == 2); REQUIRE(ntc == decltype(ntc)({{{2}, {1}}})); } - TEMPLATE_TEST_CASE("non-trivial congruence on an infinite fp semigroup", - "[022][quick][kbp]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: non-trivial congruence on an infinite fp semigroup", + "[022][quick][kbp]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet(5); @@ -951,20 +947,18 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, 24_w, 3_w); presentation::add_rule_no_checks(p, 34_w, 1_w); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); presentation::add_rule_no_checks(p, 2_w, 3_w); - TestType kb2(twosided, p); - // TODO(0) be good to be able to specify the output type of - // non_trivial_classes - auto ntc = knuth_bendix::non_trivial_classes(kb2, kb1); + KnuthBendix kb2(twosided, p); + auto ntc = knuth_bendix::non_trivial_classes(kb1, kb2); REQUIRE(ntc.size() == 1); REQUIRE(ntc[0].size() == 3); REQUIRE(ntc == decltype(ntc)({{{2}, {3}, {1}}})); } - TEMPLATE_TEST_CASE("trivial congruence on a finite fp semigroup", + TEMPLATE_TEST_CASE("KnuthBendix: trivial congruence on a finite fp semigroup", "[023][quick][kbp]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -980,19 +974,20 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, 01010_w, 0100_w); presentation::add_rule_no_checks(p, 01011_w, 0101_w); - TestType kb1(twosided, p); - TestType kb2(twosided, p); + KnuthBendix kb1(twosided, p); + KnuthBendix kb2(twosided, p); REQUIRE(!p.contains_empty_word()); REQUIRE(kb1.number_of_classes() == 27); REQUIRE(kb2.number_of_classes() == 27); - auto ntc = knuth_bendix::non_trivial_classes(kb2, kb1); + auto ntc = knuth_bendix::non_trivial_classes(kb1, kb2); REQUIRE(ntc.empty()); } - TEMPLATE_TEST_CASE("universal congruence on a finite fp semigroup", - "[024][quick][kbp]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: universal congruence on a finite fp semigroup", + "[024][quick][kbp]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -1007,16 +1002,16 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, 01010_w, 0100_w); presentation::add_rule_no_checks(p, 01011_w, 0101_w); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); presentation::add_rule_no_checks(p, 0_w, 1_w); presentation::add_rule_no_checks(p, 00_w, 0_w); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); REQUIRE(kb2.number_of_classes() == 1); - auto ntc = knuth_bendix::non_trivial_classes(kb2, kb1); + auto ntc = knuth_bendix::non_trivial_classes(kb1, kb2); REQUIRE(ntc.size() == 1); REQUIRE(ntc[0].size() == 27); @@ -1052,7 +1047,7 @@ namespace libsemigroups { REQUIRE(ntc[0] == expected); } - TEMPLATE_TEST_CASE("finite fp semigroup, size 16", + TEMPLATE_TEST_CASE("KnuthBendix: finite fp semigroup, size 16", "[025][quick][kbp]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1110,7 +1105,7 @@ namespace libsemigroups { presentation::add_rule_no_checks(p, {3, 0, 1, 0}, {3, 0, 1}); presentation::add_rule_no_checks(p, {3, 0, 3, 0}, {3, 0, 3}); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); REQUIRE(kb1.gilman_graph().number_of_nodes() == 16); WordGraph test_wg1 = to_word_graph(16, @@ -1142,7 +1137,7 @@ namespace libsemigroups { normal_forms_from_word_graph(kb1, test_wg1))); presentation::add_rule_no_checks(p, {1}, {3}); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); WordGraph test_wg2 = to_word_graph(4, {{2, @@ -1162,7 +1157,7 @@ namespace libsemigroups { REQUIRE(equal(knuth_bendix::normal_forms(kb2), normal_forms_from_word_graph(kb2, test_wg2))); - auto ntc = knuth_bendix::non_trivial_classes(kb2, kb1); + auto ntc = knuth_bendix::non_trivial_classes(kb1, kb2); std::vector expected = {{1}, {3}, @@ -1183,18 +1178,18 @@ namespace libsemigroups { REQUIRE(ntc[0] == expected); } - TEMPLATE_TEST_CASE("non_trivial_classes exceptions", + TEMPLATE_TEST_CASE("KnuthBendix: non_trivial_classes exceptions", "[026][quick][kbp]", KNUTH_BENDIX_TYPES) { Presentation p; p.alphabet(1); - TestType kbp(twosided, p); + KnuthBendix kbp(twosided, p); { Presentation q; q.alphabet(2); - TestType kbq(twosided, q); - REQUIRE_THROWS_AS(knuth_bendix::non_trivial_classes(kbq, kbp), + KnuthBendix kbq(twosided, q); + REQUIRE_THROWS_AS(knuth_bendix::non_trivial_classes(kbp, kbq), LibsemigroupsException); REQUIRE(kbq.number_of_inactive_rules() == 0); } @@ -1206,8 +1201,8 @@ namespace libsemigroups { q.alphabet(1); presentation::add_rule_no_checks(q, 00_w, 0_w); - TestType kbq(twosided, q); - REQUIRE_THROWS_AS(knuth_bendix::non_trivial_classes(kbp, kbq), + KnuthBendix kbq(twosided, q); + REQUIRE_THROWS_AS(knuth_bendix::non_trivial_classes(kbq, kbp), LibsemigroupsException); } } @@ -1228,7 +1223,7 @@ namespace libsemigroups { // "(from kbmag/standalone/kb_data/verifynilp)", // "[000][quick][knuth-bendix]"[kbmag][recursive], // KNUTH_BENDIX_TYPES){} - // TestType kb(new RECURSIVE(), "hHgGfFyYdDcCbBaA"); + // KnuthBendix kb(new RECURSIVE(), "hHgGfFyYdDcCbBaA"); // presentation::add_rule_no_checks(p, "BAba", "c"); // presentation::add_rule_no_checks(p, "CAca", "d"); // presentation::add_rule_no_checks(p, "DAda", "y"); @@ -1261,8 +1256,8 @@ namespace libsemigroups { // TODO(later): temporarily commented out to because of change to // FpSemigroupInterface that forbids adding rules after started(), and - // because the copy constructors for TestType et al. don't currently - // work TEMPLATE_TEST_CASE( + // because the copy constructors for KnuthBendix et al. don't + // currently work TEMPLATE_TEST_CASE( // "(cong) finite transformation semigroup " // "congruence (21 classes)", // "[000][quick][congruence][knuth-bendix]"[cong], KNUTH_BENDIX_TYPES){ @@ -1274,7 +1269,7 @@ namespace libsemigroups { // REQUIRE(S.size() == 88); // REQUIRE(S.number_of_rules() == 18); - // TestType kb(twosided, S); + // KnuthBendix kb(twosided, S); // auto& P = kb.quotient_froidure_pin(); // REQUIRE(P.size() == 88); // kb.add_generating_pair(S.factorisation(Transf({3, 4, 4, 4, 4})), @@ -1331,7 +1326,7 @@ namespace libsemigroups { // TEMPLATE_TEST_CASE( // "(from kbmag/standalone/kb_data/nonhopf)", // "[027][quick][knuth-bendix]"[kbmag][recursive], KNUTH_BENDIX_TYPES){ - // TestType kb(new RECURSIVE(), "aAbB"); + // KnuthBendix kb(new RECURSIVE(), "aAbB"); // presentation::add_rule_no_checks(p, "Baab", "aaa"); // auto rg = ReportGuard(false); @@ -1349,11 +1344,11 @@ namespace libsemigroups { // TEMPLATE_TEST_CASE( // "(from kbmag/standalone/kb_data/freenilpc3)", // "[028][quick][knuth-bendix]"[kbmag][recursive], KNUTH_BENDIX_TYPES){ - // TestType kb(new RECURSIVE(), "yYdDcCbBaA"); + // KnuthBendix kb(new RECURSIVE(), "yYdDcCbBaA"); // presentation::add_rule_no_checks(p, "BAba", "c"); // presentation::add_rule_no_checks(p, "CAca", "d"); // presentation::add_rule_no_checks(p, "CBcb", "y"); - // presentation::add_rule_no_checks(p, "da", "ad"); + // presentation::add_rule_no_checks(p, "da", "wg"); // presentation::add_rule_no_checks(p, "ya", "ay"); // presentation::add_rule_no_checks(p, "db", "bd"); // presentation::add_rule_no_checks(p, "yb", "by"); @@ -1368,7 +1363,7 @@ namespace libsemigroups { // REQUIRE(knuth_bendix::contains(kb, "BAba", "c")); // REQUIRE(knuth_bendix::contains(kb, "CAca", "d")); // REQUIRE(knuth_bendix::contains(kb, "CBcb", "y")); - // REQUIRE(knuth_bendix::contains(kb, "da", "ad")); + // REQUIRE(knuth_bendix::contains(kb, "da", "wg")); // REQUIRE(knuth_bendix::contains(kb, "ya", "ay")); // REQUIRE(knuth_bendix::contains(kb, "db", "bd")); // REQUIRE(knuth_bendix::contains(kb, "yb", "by")); @@ -1378,13 +1373,13 @@ namespace libsemigroups { // TODO(later): temporarily commented out to because of change to // FpSemigroupInterface that forbids adding rules after started(), and - // because the copy constructors for TestType et al. don't currently - // work TEMPLATE_TEST_CASE( + // because the copy constructors for KnuthBendix et al. don't + // currently work TEMPLATE_TEST_CASE( // "add_rule after knuth_bendix", // "[029][quick][knuth-bendix]", // KNUTH_BENDIX_TYPES){ // auto rg = ReportGuard(false); - // TestType kb; + // KnuthBendix kb; // Presentation p; // //p.alphabet("Bab"); // presentation::add_rule_no_checks(p, "aa", ""); @@ -1402,7 +1397,7 @@ namespace libsemigroups { // REQUIRE(knuth_bendix::contains(kb, "aa", "")); // REQUIRE(!knuth_bendix::contains(kb, "a", "b")); - // TestType kb2(&kb); + // KnuthBendix kb2(&kb); // REQUIRE(kb2.number_of_active_rules() == 11); // kb2.add_rule("a", "b"); // REQUIRE(kb2.number_of_rules() == 5); @@ -1432,7 +1427,7 @@ namespace libsemigroups { // TEMPLATE_TEST_CASE( // "(from kbmag/standalone/kb_data/nilp2)", // "[030][quick][knuth-bendix]"[kbmag][recursive], KNUTH_BENDIX_TYPES){ - // TestType kb(new RECURSIVE(), "cCbBaA"); + // KnuthBendix kb(new RECURSIVE(), "cCbBaA"); // presentation::add_rule_no_checks(p, "ba", "abc"); // presentation::add_rule_no_checks(p, "ca", "ac"); // presentation::add_rule_no_checks(p, "cb", "bc"); @@ -1455,7 +1450,7 @@ namespace libsemigroups { // "(from kbmag/standalone/kb_data/f27monoid)", // "[fail][knuth-bendix]"[kbmag][recursive], // KNUTH_BENDIX_TYPES){ - // TestType kb(new RECURSIVE(), "abcdefg"); + // KnuthBendix kb(new RECURSIVE(), "abcdefg"); // presentation::add_rule_no_checks(p, "ab", "c"); // presentation::add_rule_no_checks(p, "bc", "d"); // presentation::add_rule_no_checks(p, "cd", "e"); @@ -1483,8 +1478,8 @@ namespace libsemigroups { // "(from kbmag/standalone/kb_data/heinnilp)", // "[fail][knuth-bendix]"[kbmag][recursive], KNUTH_BENDIX_TYPES){ // // TODO(later) fails because internal_rewrite expect rules to be - // length reducing TestType kb(new RECURSIVE(), "fFyYdDcCbBaA"); - // presentation::add_rule_no_checks(p, "BAba", "c"); + // length reducing KnuthBendix kb(new RECURSIVE(), + // "fFyYdDcCbBaA"); presentation::add_rule_no_checks(p, "BAba", "c"); // presentation::add_rule_no_checks(p, "CAca", "d"); // presentation::add_rule_no_checks(p, "CBcb", "y"); // presentation::add_rule_no_checks(p, "DBdb", "f"); diff --git a/tests/test-knuth-bendix-2.cpp b/tests/test-knuth-bendix-2.cpp index 638624641..4a1c51336 100644 --- a/tests/test-knuth-bendix-2.cpp +++ b/tests/test-knuth-bendix-2.cpp @@ -68,11 +68,12 @@ namespace libsemigroups { struct LibsemigroupsException; - // TODO change from default if needed? using rule_type = KnuthBendix<>::rule_type; -#define KNUTH_BENDIX_TYPES \ - KnuthBendix, KnuthBendix + using RewriteTrie = detail::RewriteTrie; + using RewriteFromLeft = detail::RewriteFromLeft; + +#define KNUTH_BENDIX_TYPES RewriteTrie, RewriteFromLeft namespace { struct weird_cmp { @@ -85,7 +86,7 @@ namespace libsemigroups { // Fibonacci group F(2,5) - monoid presentation - has order 12 (group // elements + empty word) - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/f25monoid)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/f25monoid)", "[031][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -99,7 +100,7 @@ namespace libsemigroups { presentation::add_rule(p, "de", "a"); presentation::add_rule(p, "ea", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -152,7 +153,7 @@ namespace libsemigroups { } // trivial group - BHN presentation - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/degen4a)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/degen4a)", "[032][quick][knuth-bendix][kbmag][shortlex][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -166,7 +167,7 @@ namespace libsemigroups { presentation::add_rule(p, "Bcb", "cc"); presentation::add_rule(p, "Cac", "aa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); @@ -190,7 +191,7 @@ namespace libsemigroups { } // Torus group - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/torus)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/torus)", "[033][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -201,7 +202,7 @@ namespace libsemigroups { presentation::add_inverse_rules(p, "AaCcBbDd"); presentation::add_rule(p, "ABab", "DCdc"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.confluent()); @@ -240,7 +241,7 @@ namespace libsemigroups { } // 3-fold cover of A_6 - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/3a6)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/3a6)", "[034][quick][knuth-bendix][kbmag][shortlex][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -256,7 +257,7 @@ namespace libsemigroups { presentation::add_rule(p, "abababab", ""); presentation::add_rule(p, "aBaBaBaBaB", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -297,7 +298,7 @@ namespace libsemigroups { } // Free group on 2 generators - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/f2)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/f2)", "[035][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -307,7 +308,7 @@ namespace libsemigroups { p.contains_empty_word(true); presentation::add_inverse_rules(p, "AaBb"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); kb.run(); @@ -339,7 +340,7 @@ namespace libsemigroups { } // Symmetric group S_16 - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/s16)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/s16)", "[036][quick][knuth-bendix][kbmag][shortlex][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -454,7 +455,7 @@ namespace libsemigroups { presentation::add_rule(p, "nmn", "mnm"); presentation::add_rule(p, "om", "mo"); presentation::add_rule(p, "ono", "non"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); @@ -603,7 +604,7 @@ namespace libsemigroups { // Presentation of group A_4 regarded as monoid presentation - gives // infinite monoid. - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/a4monoid)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/a4monoid)", "[037][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -614,7 +615,7 @@ namespace libsemigroups { presentation::add_rule(p, "bb", "B"); presentation::add_rule(p, "BaB", "aba"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -637,7 +638,7 @@ namespace libsemigroups { } // fairly clearly the trivial group - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/degen3)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/degen3)", "[038][quick][knuth-bendix][kbmag][shortlex][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -648,7 +649,7 @@ namespace libsemigroups { presentation::add_rule(p, "ab", ""); presentation::add_rule(p, "abb", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE((kb.active_rules() | sort(weird_cmp()) | to_vector()) == std::vector({{"a", ""}, {"b", ""}})); @@ -666,7 +667,7 @@ namespace libsemigroups { } // infinite cyclic group - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/ab1)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/ab1)", "[039][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -675,7 +676,7 @@ namespace libsemigroups { p.contains_empty_word(true); presentation::add_inverse_rules(p, "Aa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); @@ -686,7 +687,7 @@ namespace libsemigroups { } // A generator, but trivial. - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/degen2)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/degen2)", "[040][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -696,7 +697,7 @@ namespace libsemigroups { p.contains_empty_word(true); presentation::add_rule(p, "a", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); @@ -710,7 +711,7 @@ namespace libsemigroups { } // Fibonacci group F(2,5) - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/f25)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/f25)", "[041][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -724,7 +725,7 @@ namespace libsemigroups { presentation::add_rule(p, "dy", "a"); presentation::add_rule(p, "ya", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -766,7 +767,7 @@ namespace libsemigroups { } // Von Dyck (2,3,7) group - infinite hyperbolic - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/237)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/237)", "[042][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -780,7 +781,7 @@ namespace libsemigroups { presentation::add_rule(p, "bb", "B"); presentation::add_rule(p, "BA", "c"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -823,7 +824,7 @@ namespace libsemigroups { } // Cyclic group of order 2. - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/c2)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/c2)", "[043][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -833,7 +834,7 @@ namespace libsemigroups { p.contains_empty_word(true); presentation::add_rule(p, "aa", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); @@ -847,7 +848,7 @@ namespace libsemigroups { // The group is S_4, and the subgroup H of order 4. There are 30 reduced // words - 24 for the group elements, and 6 for the 6 cosets Hg. - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/cosets)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/cosets)", "[044][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -863,7 +864,7 @@ namespace libsemigroups { presentation::add_rule(p, "aH", "H"); presentation::add_rule(p, "bH", "H"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -901,7 +902,7 @@ namespace libsemigroups { {"bbaabb", "abba"}}})); } - TEMPLATE_TEST_CASE("Example 5.1 in Sims (KnuthBendix 09 again)", + TEMPLATE_TEST_CASE("KnuthBendix: Example 5.1 in Sims (KnuthBendix 09 again)", "[045][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -916,7 +917,7 @@ namespace libsemigroups { presentation::add_rule(p, "Bb", ""); presentation::add_rule(p, "ba", "ab"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -924,7 +925,7 @@ namespace libsemigroups { REQUIRE(kb.confluent()); } - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/nilp2)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/nilp2)", "[046][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -938,11 +939,11 @@ namespace libsemigroups { presentation::add_rule(p, "ca", "ac"); presentation::add_rule(p, "cb", "bc"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); } - TEMPLATE_TEST_CASE("Example 6.4 in Sims", + TEMPLATE_TEST_CASE("KnuthBendix: Example 6.4 in Sims", "[047][quick][knuth-bendix][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -955,7 +956,7 @@ namespace libsemigroups { presentation::add_rule(p, "ababababababab", ""); presentation::add_rule(p, "abacabacabacabac", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.number_of_active_rules() == 5); REQUIRE(!kb.confluent()); @@ -981,7 +982,7 @@ namespace libsemigroups { } // Von Dyck (2,3,7) group - infinite hyperbolic - TEMPLATE_TEST_CASE("KnuthBendix 071 again", + TEMPLATE_TEST_CASE("KnuthBendix: KnuthBendix 071 again", "[no-valgrind][048][quick][knuth-bendix][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1034,7 +1035,7 @@ namespace libsemigroups { presentation::add_rule(p, "BaAaAAaAAaAAA", "cAAaAaAAaAAa"); presentation::add_rule(p, "BaAAaAAaAAaAAA", "cAAaAAaAAaAAa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.number_of_active_rules() == 9); REQUIRE(!kb.confluent()); @@ -1054,10 +1055,10 @@ namespace libsemigroups { "Baac", "BacA", "cAAb", "cAAB"})); } - TEMPLATE_TEST_CASE( - "Example 5.4 in Sims (KnuthBendix 11 again) (different overlap policy)", - "[049][quick][knuth-bendix]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE("KnuthBendix: Example 5.4 in Sims (KnuthBendix 11 again) " + "(different overlap policy)", + "[049][quick][knuth-bendix]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("Bab"); @@ -1067,8 +1068,8 @@ namespace libsemigroups { presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "ababab", ""); - TestType kb(twosided, p); - kb.overlap_policy(TestType::options::overlap::AB_BC); + KnuthBendix kb(twosided, p); + kb.overlap_policy(KnuthBendix::options::overlap::AB_BC); REQUIRE(!kb.confluent()); @@ -1095,10 +1096,11 @@ namespace libsemigroups { "baB"})); } - TEMPLATE_TEST_CASE("Example 5.4 in Sims (KnuthBendix 11 again) (different " - "overlap policy) x 2", - "[050][quick][knuth-bendix]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: Example 5.4 in Sims (KnuthBendix 11 again) (different " + "overlap policy) x 2", + "[050][quick][knuth-bendix]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -1109,11 +1111,11 @@ namespace libsemigroups { presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "ababab", ""); - TestType kb(twosided, p); - kb.overlap_policy(TestType::options::overlap::MAX_AB_BC); + KnuthBendix kb(twosided, p); + kb.overlap_policy(KnuthBendix::options::overlap::MAX_AB_BC); // The next line tests that we don't delete // the old OverlapMeasure. - kb.overlap_policy(TestType::options::overlap::MAX_AB_BC); + kb.overlap_policy(KnuthBendix::options::overlap::MAX_AB_BC); REQUIRE(!kb.confluent()); @@ -1122,7 +1124,7 @@ namespace libsemigroups { REQUIRE(kb.confluent()); } - TEMPLATE_TEST_CASE("operator<<", + TEMPLATE_TEST_CASE("KnuthBendix: operator<<", "[051][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { std::ostringstream os; @@ -1135,18 +1137,18 @@ namespace libsemigroups { presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "ababab", ""); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); os << kb1; // Does not do anything visible p.alphabet("cbaB"); presentation::add_rule(p, "aa", ""); presentation::add_rule(p, "bB", ""); presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "ababab", ""); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); os << kb2; // Does not do anything visible } - TEMPLATE_TEST_CASE("confluence_interval", + TEMPLATE_TEST_CASE("KnuthBendix: confluence_interval", "[052][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { Presentation p; @@ -1156,12 +1158,12 @@ namespace libsemigroups { presentation::add_rule(p, "bB", ""); presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "ababab", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.check_confluence_interval(LIMIT_MAX); kb.check_confluence_interval(10); } - TEMPLATE_TEST_CASE("max_overlap", + TEMPLATE_TEST_CASE("KnuthBendix: max_overlap", "[053][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { Presentation p; @@ -1173,14 +1175,15 @@ namespace libsemigroups { presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "ababab", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.max_overlap(10); kb.max_overlap(-11); } - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/d22) (2 / 3) (finite)", - "[054][quick][knuth-bendix][fpsemi][kbmag][shortlex]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: (from kbmag/standalone/kb_data/d22) (2 / 3) (finite)", + "[054][quick][knuth-bendix][fpsemi][kbmag][shortlex]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -1196,7 +1199,7 @@ namespace libsemigroups { presentation::add_rule(p, "ybYA", ""); presentation::add_rule(p, "fCFB", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -1211,9 +1214,10 @@ namespace libsemigroups { "ABD", "ABY", "ACY", "ADB"})); } - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/d22) (3 / 3) (finite)", - "[055][quick][knuth-bendix][fpsemi][kbmag][shortlex]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: (from kbmag/standalone/kb_data/d22) (3 / 3) (finite)", + "[055][quick][knuth-bendix][fpsemi][kbmag][shortlex]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("aAbBcCdDyYfF"); @@ -1227,7 +1231,7 @@ namespace libsemigroups { presentation::add_rule(p, "dFDa", ""); presentation::add_rule(p, "ybYA", ""); presentation::add_rule(p, "fCFB", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -1236,7 +1240,7 @@ namespace libsemigroups { REQUIRE(kb.number_of_classes() == 22); } - TEMPLATE_TEST_CASE("small example", + TEMPLATE_TEST_CASE("KnuthBendix: small example", "[056][quick][knuth-bendix][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1245,7 +1249,7 @@ namespace libsemigroups { presentation::add_rule(p, "aaa", "a"); presentation::add_rule(p, "bbbb", "b"); presentation::add_rule(p, "ababababab", "aa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.run(); REQUIRE(kb.confluent()); REQUIRE(kb.number_of_classes() == 243); @@ -1254,25 +1258,29 @@ namespace libsemigroups { == std::vector({"a", "b", "aa", "ab", "ba", "bb"})); } - TEMPLATE_TEST_CASE("code coverage", "[057][quick]", KNUTH_BENDIX_TYPES) { - TestType kb1; - TestType kb2(kb1); + TEMPLATE_TEST_CASE("KnuthBendix: code coverage", + "[057][quick]", + KNUTH_BENDIX_TYPES) { + KnuthBendix kb1; + KnuthBendix kb2(kb1); REQUIRE(kb1.number_of_classes() == 0); Presentation p; p.alphabet("ab"); presentation::add_rule(p, "aaa", "a"); - TestType kb3(twosided, p); + KnuthBendix kb3(twosided, p); REQUIRE(kb3.presentation().rules.size() / 2 == 1); } - TEMPLATE_TEST_CASE("small overlap 1", "[058][quick]", KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE("KnuthBendix: small overlap 1", + "[058][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("BCA"); presentation::add_rule(p, "AABC", "ACBA"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); REQUIRE(knuth_bendix::reduce(kb, "CBACBAABCAABCACBACBA") @@ -1297,7 +1305,7 @@ namespace libsemigroups { } // Symmetric group S_9 - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/s9)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/s9)", "[059][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1337,7 +1345,7 @@ namespace libsemigroups { presentation::add_rule(p, "hf", "fh"); presentation::add_rule(p, "hgh", "ghg"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.confluent()); @@ -1345,7 +1353,7 @@ namespace libsemigroups { REQUIRE(kb.number_of_classes() == 362'880); } - TEMPLATE_TEST_CASE("C(4) monoid", + TEMPLATE_TEST_CASE("KnuthBendix: C(4) monoid", "[060][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { Presentation p; @@ -1353,12 +1361,12 @@ namespace libsemigroups { presentation::add_rule(p, "bceac", "aeebbc"); presentation::add_rule(p, "aeebbc", "dabcd"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.run(); REQUIRE(kb.confluent()); } - TEMPLATE_TEST_CASE("1-relation hard case", + TEMPLATE_TEST_CASE("KnuthBendix: 1-relation hard case", "[061][fail][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -1367,14 +1375,14 @@ namespace libsemigroups { p.contains_empty_word(true); presentation::add_rule(p, "baaababaaa", "aaba"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // knuth_bendix::by_overlap_length(kb); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.confluent()); } - TEMPLATE_TEST_CASE("1-relation hard case x 2", + TEMPLATE_TEST_CASE("KnuthBendix: 1-relation hard case x 2", "[062][quick][knuth-bendix][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1414,7 +1422,7 @@ namespace libsemigroups { {"aa", "a", "ad", "d", "bb", "b", "ca", "ac", "cc", "c", "da", "d", "dc", "cd", "dd", "d", "aba", "a", "bab", "b", "bcb", "b", "bcd", "cd", "cbc", "c", "cdb", "cd"})); - TestType kb(congruence_kind::twosided, p); + KnuthBendix kb(congruence_kind::twosided, p); REQUIRE(kb.number_of_classes() == 24); REQUIRE(knuth_bendix::reduce(kb, "dcb") == "cd"); REQUIRE(knuth_bendix::reduce(kb, "dca") == "cd"); @@ -1435,7 +1443,7 @@ namespace libsemigroups { "bdb", "cba", "cbd", "dbc", "bacb", "bdbc", "cbdb", "cbdbc"})); } - TEMPLATE_TEST_CASE("search for a monoid that might not exist", + TEMPLATE_TEST_CASE("KnuthBendix: search for a monoid that might not exist", "[063][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1467,11 +1475,11 @@ namespace libsemigroups { presentation::add_rule(p, "ead", "ad"); presentation::add_rule(p, "ade", "ad"); // presentation::add_rule(p, "de", "ed"); - TestType kb(congruence_kind::twosided, p); + KnuthBendix kb(congruence_kind::twosided, p); REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); } - TEMPLATE_TEST_CASE("Chinese monoid", + TEMPLATE_TEST_CASE("KnuthBendix: Chinese monoid", "[064][knuth-bendix][quick][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1484,13 +1492,13 @@ namespace libsemigroups { for (size_t n = 2; n < 11; ++n) { auto p = fpsemigroup::chinese_monoid(n); p.contains_empty_word(true); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.run(); REQUIRE(knuth_bendix::normal_forms(kb).min(0).max(5).count() == num[n]); } } - TEMPLATE_TEST_CASE("hypostylic", + TEMPLATE_TEST_CASE("KnuthBendix: hypostylic", "[065][todd-coxeter][quick]", KNUTH_BENDIX_TYPES) { using namespace literals; @@ -1502,9 +1510,8 @@ namespace libsemigroups { p.contains_empty_word(true); presentation::add_idempotent_rules_no_checks( p, (seq() | take(n) | to_vector())); - TestType kb(congruence_kind::twosided, p); + KnuthBendix kb(congruence_kind::twosided, p); kb.run(); - // TODO implement knuth_bendix::idempotents REQUIRE(kb.presentation().alphabet() == std::string({0, 1})); REQUIRE((knuth_bendix::normal_forms(kb) | filter([&kb](auto const& w) { @@ -1526,7 +1533,7 @@ namespace libsemigroups { // == to_word_graph(5, {{1, 3}, {UNDEFINED, 2}, {}, {4}})); } - TEMPLATE_TEST_CASE("Chinese id monoid", + TEMPLATE_TEST_CASE("KnuthBendix: Chinese id monoid", "[066][todd-coxeter][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1535,7 +1542,7 @@ namespace libsemigroups { p.contains_empty_word(true); presentation::add_idempotent_rules_no_checks(p, p.alphabet()); - TestType kb(twosided, to_presentation(p)); + KnuthBendix kb(twosided, to_presentation(p)); kb.run(); REQUIRE(knuth_bendix::reduce(kb, "cbda") == "bcda"); @@ -1543,7 +1550,7 @@ namespace libsemigroups { REQUIRE(knuth_bendix::reduce(kb, "cadb") == "cadb"); } - TEMPLATE_TEST_CASE("sigma sylvester monoid", + TEMPLATE_TEST_CASE("KnuthBendix: sigma sylvester monoid", "[067][todd-coxeter][quick][no-valgrind]", KNUTH_BENDIX_TYPES) { using namespace literals; @@ -1673,12 +1680,12 @@ namespace libsemigroups { // 213023_w, 21302_w, 1032312_w, 103231_w, 2101323_w, 210132_w, // 2103123_w, 210312_w, 2130123_w, 213012_w})); // } - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.run(); REQUIRE(kb.number_of_classes() == 312); } - TEMPLATE_TEST_CASE("Reinis MFE", + TEMPLATE_TEST_CASE("KnuthBendix: Reinis MFE", "[027][todd-coxeter][quick]", KNUTH_BENDIX_TYPES) { using literals:: operator""_w; @@ -1691,7 +1698,7 @@ namespace libsemigroups { REQUIRE(knuth_bendix::contains(kb, "000"_w, "11"_w)); } - TEMPLATE_TEST_CASE("sigma sylvester monoid x 2", + TEMPLATE_TEST_CASE("KnuthBendix: sigma sylvester monoid x 2", "[068][todd-coxeter][quick]", KNUTH_BENDIX_TYPES) { using namespace literals; @@ -1738,7 +1745,7 @@ namespace libsemigroups { presentation::remove_trivial_rules(p); p.contains_empty_word(true); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); p = to_presentation(kb); auto S = to_froidure_pin(kb); diff --git a/tests/test-knuth-bendix-3.cpp b/tests/test-knuth-bendix-3.cpp index b2b56d964..9a75e2885 100644 --- a/tests/test-knuth-bendix-3.cpp +++ b/tests/test-knuth-bendix-3.cpp @@ -63,13 +63,15 @@ namespace libsemigroups { using namespace rx; using literals::operator""_w; - // TODO remove default? using rule_type = KnuthBendix<>::rule_type; struct LibsemigroupsException; -#define KNUTH_BENDIX_TYPES \ - KnuthBendix, KnuthBendix + using RewriteTrie = detail::RewriteTrie; + using RewriteFromLeft = detail::RewriteFromLeft; + +#define KNUTH_BENDIX_TYPES RewriteTrie, RewriteFromLeft + namespace { struct weird_cmp { bool operator()(rule_type const& x, rule_type const& y) const noexcept { @@ -79,9 +81,10 @@ namespace libsemigroups { }; } // namespace - TEMPLATE_TEST_CASE("Chapter 11, Lemma 1.8 (q = 6, r = 5) in NR (infinite)", - "[069][knuth-bendix][quick]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: Chapter 11, Lemma 1.8 (q = 6, r = 5) in NR (infinite)", + "[069][knuth-bendix][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("ABCabc"); @@ -97,7 +100,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "abaBaBabaBab", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 16); @@ -126,10 +129,10 @@ namespace libsemigroups { "cc"})); } - TEMPLATE_TEST_CASE( - "Chapter 11, Section 2 (q = 6, r = 2, alpha = abaabba) in NR (size 4)", - "[070][knuth-bendix][quick]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE("KnuthBendix: Chapter 11, Section 2 (q = 6, r = 2, alpha " + "= abaabba) in NR (size 4)", + "[070][knuth-bendix][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -137,7 +140,7 @@ namespace libsemigroups { presentation::add_rule(p, "aaa", "a"); presentation::add_rule(p, "bbbbbbb", "b"); presentation::add_rule(p, "abaabba", "bb"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -151,7 +154,7 @@ namespace libsemigroups { == std::vector({"a", "b", "aa", "ab"})); } - TEMPLATE_TEST_CASE("Chapter 8, Theorem 4.2 in NR (infinite) ", + TEMPLATE_TEST_CASE("KnuthBendix: Chapter 8, Theorem 4.2 in NR (infinite) ", "[071][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -163,7 +166,7 @@ namespace libsemigroups { presentation::add_rule(p, "bababababab", "b"); presentation::add_rule(p, "baab", "babbbab"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 8); @@ -189,7 +192,7 @@ namespace libsemigroups { "bbb"})); } - TEMPLATE_TEST_CASE("equal_to fp semigroup", + TEMPLATE_TEST_CASE("KnuthBendix: equal_to fp semigroup", "[072][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -208,7 +211,7 @@ namespace libsemigroups { presentation::add_rule(p, "cb", "b"); presentation::add_rule(p, "a", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(knuth_bendix::contains(kb, "aa", "a")); REQUIRE(knuth_bendix::contains(kb, "bb", "bb")); REQUIRE(knuth_bendix::contains(kb, "bc", "cb")); @@ -218,7 +221,7 @@ namespace libsemigroups { REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); } - TEMPLATE_TEST_CASE("equal_to free semigroup", + TEMPLATE_TEST_CASE("KnuthBendix: equal_to free semigroup", "[073][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -227,7 +230,7 @@ namespace libsemigroups { REQUIRE(p.alphabet() == "ab"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!knuth_bendix::contains(kb, "a", "b")); REQUIRE(knuth_bendix::contains(kb, "a", "a")); REQUIRE(knuth_bendix::contains(kb, "aaaaaaa", "aaaaaaa")); @@ -241,9 +244,10 @@ namespace libsemigroups { REQUIRE(equal(s, nf)); } - TEMPLATE_TEST_CASE("from GAP smalloverlap gap/test.gi (infinite)", - "[074][quick][knuth-bendix][smalloverlap]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: from GAP smalloverlap gap/test.gi (infinite)", + "[074][quick][knuth-bendix][smalloverlap]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcdefg"); @@ -251,7 +255,7 @@ namespace libsemigroups { presentation::add_rule(p, "abcd", "ce"); presentation::add_rule(p, "df", "dg"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(is_obviously_infinite(kb)); REQUIRE(!kb.confluent()); @@ -273,9 +277,10 @@ namespace libsemigroups { == std::vector({"a", "b", "c", "d", "e", "f", "g"})); } - TEMPLATE_TEST_CASE("from GAP smalloverlap gap/test.gi:49 (infinite)", - "[075][quick][knuth-bendix][smalloverlap]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: from GAP smalloverlap gap/test.gi:49 (infinite)", + "[075][quick][knuth-bendix][smalloverlap]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcdefgh"); @@ -283,7 +288,7 @@ namespace libsemigroups { presentation::add_rule(p, "abcd", "ce"); presentation::add_rule(p, "df", "hd"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(is_obviously_infinite(kb)); REQUIRE(kb.confluent()); @@ -304,9 +309,10 @@ namespace libsemigroups { == std::vector({"a", "b", "c", "d", "e", "f", "g", "h"})); } - TEMPLATE_TEST_CASE("from GAP smalloverlap gap/test.gi:63 (infinite)", - "[076][quick][knuth-bendix][smalloverlap]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: from GAP smalloverlap gap/test.gi:63 (infinite)", + "[076][quick][knuth-bendix][smalloverlap]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcdefgh"); @@ -314,7 +320,7 @@ namespace libsemigroups { presentation::add_rule(p, "afh", "bgh"); presentation::add_rule(p, "hc", "d"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(is_obviously_infinite(kb)); REQUIRE(!kb.confluent()); @@ -332,9 +338,10 @@ namespace libsemigroups { == std::vector({"a", "b", "c", "d", "e", "f", "g", "h"})); } - TEMPLATE_TEST_CASE("from GAP smalloverlap gap/test.gi:70 (infinite)", - "[077][quick][knuth-bendix][smalloverlap]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: from GAP smalloverlap gap/test.gi:70 (infinite)", + "[077][quick][knuth-bendix][smalloverlap]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); // The following permits a more complex test of case (6), which also // involves using the case (2) code to change the prefix being @@ -346,7 +353,7 @@ namespace libsemigroups { presentation::add_rule(p, "hc", "de"); presentation::add_rule(p, "ei", "j"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(is_obviously_infinite(kb)); REQUIRE(!kb.confluent()); @@ -365,9 +372,10 @@ namespace libsemigroups { {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"})); } - TEMPLATE_TEST_CASE("from GAP smalloverlap gap/test.gi:77 (infinite)", - "[078][quick][knuth-bendix][smalloverlap][no-valgrind]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: from GAP smalloverlap gap/test.gi:77 (infinite)", + "[078][quick][knuth-bendix][smalloverlap][no-valgrind]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcdefghijkl"); @@ -377,7 +385,7 @@ namespace libsemigroups { presentation::add_rule(p, "ei", "j"); presentation::add_rule(p, "fhk", "ghl"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(is_obviously_infinite(kb)); REQUIRE(!kb.confluent()); @@ -397,16 +405,17 @@ namespace libsemigroups { {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"})); } - TEMPLATE_TEST_CASE("from GAP smalloverlap gap/test.gi:85 (infinite)", - "[079][quick][knuth-bendix][smalloverlap]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: from GAP smalloverlap gap/test.gi:85 (infinite)", + "[079][quick][knuth-bendix][smalloverlap]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("cab"); // runs forever with a different order presentation::add_rule(p, "aabc", "acba"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(is_obviously_infinite(kb)); REQUIRE(kb.confluent()); // Confirmed with GAP @@ -422,7 +431,7 @@ namespace libsemigroups { REQUIRE(knuth_bendix::normal_forms(kb).min(1).max(6).count() == 356); } - TEMPLATE_TEST_CASE("Von Dyck (2,3,7) group (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: Von Dyck (2,3,7) group (infinite)", "[080][quick][knuth-bendix][kbmag]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -435,7 +444,7 @@ namespace libsemigroups { presentation::add_rule(p, "bb", "B"); presentation::add_rule(p, "BA", "c"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -454,7 +463,7 @@ namespace libsemigroups { == std::vector({"", "A", "B", "a", "b", "c"})); } - TEMPLATE_TEST_CASE("Von Dyck (2,3,7) group - different " + TEMPLATE_TEST_CASE("KnuthBendix: Von Dyck (2,3,7) group - different " "presentation (infinite)", "[081][no-valgrind][quick][knuth-bendix][kbmag]", KNUTH_BENDIX_TYPES) { @@ -468,9 +477,9 @@ namespace libsemigroups { presentation::add_rule(p, "abababa", "BABABAB"); presentation::add_rule(p, "BA", "c"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); - kb.overlap_policy(TestType::options::overlap::MAX_AB_BC); + kb.overlap_policy(KnuthBendix::options::overlap::MAX_AB_BC); kb.max_rules(100); kb.run(); REQUIRE(kb.number_of_active_rules() > 100); @@ -482,7 +491,7 @@ namespace libsemigroups { REQUIRE(kb.number_of_active_rules() > 250); } - TEMPLATE_TEST_CASE("rewriting system from another test", + TEMPLATE_TEST_CASE("KnuthBendix: rewriting system from another test", "[082][quick][knuth-bendix][kbmag]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -497,7 +506,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbcbca", "bbcbc"); presentation::add_rule(p, "bbcbcb", "bbcbc"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(!kb.confluent()); REQUIRE(kb.number_of_active_rules() == 6); @@ -535,7 +544,7 @@ namespace libsemigroups { == std::vector({"a", "b", "c"})); } - TEMPLATE_TEST_CASE("rewriting system from Congruence 20", + TEMPLATE_TEST_CASE("KnuthBendix: rewriting system from Congruence 20", "[083][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -546,7 +555,7 @@ namespace libsemigroups { presentation::add_rule(p, "ab", "ba"); presentation::add_rule(p, "aa", "a"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.run(); REQUIRE(knuth_bendix::contains(kb, "abbbbbbbbbbbbbb", "aabbbbbbbbbbbbbb")); @@ -555,7 +564,7 @@ namespace libsemigroups { // 2-generator free abelian group (with this ordering KB terminates - but // no all) - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/ab2)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/ab2)", "[084][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -565,7 +574,7 @@ namespace libsemigroups { presentation::add_inverse_rules(p, "AaBb"); presentation::add_rule(p, "Bab", "a"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -588,7 +597,7 @@ namespace libsemigroups { // generators are unexpectedly involutory. knuth_bendix does not terminate // with the commented out ordering, terminates almost immediately with the // uncommented order. - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/d22) (1 / 3)" + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/d22) (1 / 3)" "(infinite)", "[085][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { @@ -610,7 +619,7 @@ namespace libsemigroups { presentation::add_rule(p, "ybYA", ""); presentation::add_rule(p, "fCFB", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -663,12 +672,12 @@ namespace libsemigroups { } // No generators - no anything! - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/degen1)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/degen1)", "[086][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); - TestType kb; + KnuthBendix kb; REQUIRE(kb.confluent()); REQUIRE(kb.number_of_active_rules() == 0); @@ -680,7 +689,7 @@ namespace libsemigroups { } // Symmetric group S_4 - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/s4)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/s4)", "[087][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -694,7 +703,7 @@ namespace libsemigroups { presentation::add_rule(p, "bb", "B"); presentation::add_rule(p, "BaBa", "abab"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -714,7 +723,7 @@ namespace libsemigroups { "baBa", "Baba", "abaBa", "aBaba", "baBab", "abaBab"})); } - TEMPLATE_TEST_CASE("fp semigroup (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: fp semigroup (infinite)", "[088][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -732,7 +741,7 @@ namespace libsemigroups { presentation::add_rule(p, {2, 1}, {1}); presentation::add_rule(p, {0}, {1}); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); @@ -745,9 +754,10 @@ namespace libsemigroups { REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); } - TEMPLATE_TEST_CASE("Chapter 11, Section 1 (q = 4, r = 3) in NR(size 86)", - "[089][knuth-bendix][quick]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: Chapter 11, Section 1 (q = 4, r = 3) in NR(size 86)", + "[089][knuth-bendix][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -757,7 +767,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbbbb", "b"); presentation::add_rule(p, "abbbabb", "bba"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); REQUIRE(kb.number_of_active_rules() == 20); @@ -800,9 +810,10 @@ namespace libsemigroups { == 86); } - TEMPLATE_TEST_CASE("Chapter 11, Section 1 (q = 8, r = 5) in NR (size 746)", - "[090][no-valgrind][knuth-bendix][quick]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: Chapter 11, Section 1 (q = 8, r = 5) in NR (size 746)", + "[090][no-valgrind][knuth-bendix][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -811,7 +822,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbbbbbbbb", "b"); presentation::add_rule(p, "abbbbbabb", "bba"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.clear_stack_interval(0); REQUIRE(!kb.confluent()); @@ -851,7 +862,7 @@ namespace libsemigroups { } // See KBFP 07 also. - TEMPLATE_TEST_CASE("Chapter 7, Theorem 3.9 in NR (size 240)", + TEMPLATE_TEST_CASE("KnuthBendix: Chapter 7, Theorem 3.9 in NR (size 240)", "[091][no-valgrind][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -864,7 +875,7 @@ namespace libsemigroups { presentation::add_rule(p, "baab", "bb"); presentation::add_rule(p, "aabababababa", "aa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 24); @@ -874,9 +885,10 @@ namespace libsemigroups { == 240); } - TEMPLATE_TEST_CASE("F(2, 5) - Chapter 9, Section 1 in NR (size 11) x 2", - "[092][knuth-bendix][quick]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: F(2, 5) - Chapter 9, Section 1 in NR (size 11) x 2", + "[092][knuth-bendix][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcde"); @@ -887,7 +899,7 @@ namespace libsemigroups { presentation::add_rule(p, "de", "a"); presentation::add_rule(p, "ea", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 24); @@ -901,7 +913,7 @@ namespace libsemigroups { {"a", "b", "c", "d", "e", "aa", "ac", "ad", "bb", "be", "aad"})); } - TEMPLATE_TEST_CASE("F(2, 6) - Chapter 9, Section 1 in NR", + TEMPLATE_TEST_CASE("KnuthBendix: F(2, 6) - Chapter 9, Section 1 in NR", "[093][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -916,7 +928,7 @@ namespace libsemigroups { presentation::add_rule(p, "ef", "a"); presentation::add_rule(p, "fa", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 35); @@ -930,7 +942,7 @@ namespace libsemigroups { {"", "a", "b", "c", "d", "e", "f", "aa", "ac", "ae", "bd", "df"})); } - TEMPLATE_TEST_CASE("Chapter 10, Section 4 in NR (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: Chapter 10, Section 4 in NR (infinite)", "[094][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -943,7 +955,7 @@ namespace libsemigroups { presentation::add_rule(p, "abab", "aaa"); presentation::add_rule(p, "bcbc", "bbb"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); REQUIRE(kb.number_of_active_rules() == 31); @@ -957,9 +969,10 @@ namespace libsemigroups { // Note: the fourth relator in NR's thesis incorrectly has exponent 3, it // should be 2. With exponent 3, the presentation defines the trivial group, // with exponent of 2, it defines the symmetric group as desired. - TEMPLATE_TEST_CASE("Sym(5) from Chapter 3, Proposition 1.1 in NR (size 120)", - "[095][no-valgrind][knuth-bendix][quick]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: Sym(5) from Chapter 3, Proposition 1.1 in NR (size 120)", + "[095][no-valgrind][knuth-bendix][quick]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -977,7 +990,7 @@ namespace libsemigroups { presentation::add_rule(p, "aA", ""); presentation::add_rule(p, "Aa", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -994,10 +1007,10 @@ namespace libsemigroups { "BAb", "BBA", "bAB", "bAb", "bbA"})); } - TEMPLATE_TEST_CASE( - "SL(2, 7) from Chapter 3, Proposition 1.5 in NR (size 336) x 2", - "[096][no-valgrind][quick][knuth-bendix]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE("KnuthBendix: SL(2, 7) from Chapter 3, Proposition 1.5 in " + "NR (size 336) x 2", + "[096][no-valgrind][quick][knuth-bendix]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -1012,7 +1025,7 @@ namespace libsemigroups { presentation::add_rule(p, "bB", ""); presentation::add_rule(p, "Bb", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -1031,7 +1044,7 @@ namespace libsemigroups { "bbA", "bAA", "Aba", "AAb", "AAA", "AAB", "ABa", "Baa", "BAA"})); } - TEMPLATE_TEST_CASE("bicyclic monoid (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: bicyclic monoid (infinite)", "[097][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1041,7 +1054,7 @@ namespace libsemigroups { presentation::add_rule(p, "ab", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); kb.run(); @@ -1057,7 +1070,7 @@ namespace libsemigroups { {"", "a", "b", "aa", "ba", "bb", "aaa", "baa", "bba", "bbb"})); } - TEMPLATE_TEST_CASE("plactic monoid of degree 2 (infinite)", + TEMPLATE_TEST_CASE("KnuthBendix: plactic monoid of degree 2 (infinite)", "[098][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1072,7 +1085,7 @@ namespace libsemigroups { presentation::add_rule(p, "bc", ""); presentation::add_rule(p, "cb", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -1087,7 +1100,7 @@ namespace libsemigroups { } TEMPLATE_TEST_CASE( - "example before Chapter 7, Proposition 1.1 in NR (infinite)", + "KnuthBendix: example before Chapter 7, Proposition 1.1 in NR (infinite)", "[099][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1097,7 +1110,7 @@ namespace libsemigroups { presentation::add_rule(p, "aa", "a"); presentation::add_rule(p, "bb", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); kb.run(); @@ -1110,7 +1123,7 @@ namespace libsemigroups { == std::vector({"a", "b", "ab", "ba", "aba", "bab"})); } - TEMPLATE_TEST_CASE("Chapter 7, Theorem 3.6 in NR (size 243)", + TEMPLATE_TEST_CASE("KnuthBendix: Chapter 7, Theorem 3.6 in NR (size 243)", "[100][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1121,7 +1134,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbbb", "b"); presentation::add_rule(p, "ababababab", "aa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -1147,7 +1160,7 @@ namespace libsemigroups { "bbb"})); } - TEMPLATE_TEST_CASE("finite semigroup (size 99)", + TEMPLATE_TEST_CASE("KnuthBendix: finite semigroup (size 99)", "[101][knuth-bendix][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -1158,7 +1171,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbbb", "b"); presentation::add_rule(p, "abababab", "aa"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -1196,7 +1209,7 @@ namespace libsemigroups { presentation::add_rule(p, "Abba", "BB"); presentation::add_rule(p, "Baab", "AA"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // knuth_bendix::by_overlap_length(kb); REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); diff --git a/tests/test-knuth-bendix-4.cpp b/tests/test-knuth-bendix-4.cpp index 18279147e..ca465f2bf 100644 --- a/tests/test-knuth-bendix-4.cpp +++ b/tests/test-knuth-bendix-4.cpp @@ -68,20 +68,22 @@ namespace libsemigroups { using namespace rx; - // TODO remove default? using rule_type = KnuthBendix<>::rule_type; -#define KNUTH_BENDIX_TYPES \ - KnuthBendix, KnuthBendix + using RewriteTrie = detail::RewriteTrie; + using RewriteFromLeft = detail::RewriteFromLeft; + +#define KNUTH_BENDIX_TYPES RewriteTrie, RewriteFromLeft //////////////////////////////////////////////////////////////////////// // Standard tests //////////////////////////////////////////////////////////////////////// // Takes approx. 2s - TEMPLATE_TEST_CASE("Example 6.6 in Sims (with limited overlap lengths)", - "[102][standard][knuth-bendix]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: Example 6.6 in Sims (with limited overlap lengths)", + "[102][standard][knuth-bendix]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p; @@ -94,7 +96,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbb", ""); presentation::add_rule(p, "ababababababab", ""); presentation::add_rule(p, "abacabacabacabacabacabacabacabac", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); @@ -111,7 +113,7 @@ namespace libsemigroups { } // Takes approx. 2s - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/funny3)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/funny3)", "[103][standard][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -131,7 +133,7 @@ namespace libsemigroups { presentation::add_rule(p, "BcabCABcabCABcabCA", ""); presentation::add_rule(p, "cbACBacbACBacbACBa", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -149,9 +151,10 @@ namespace libsemigroups { // Fibonacci group F(2,7) - order 29 - works better with largish tidyint // Takes approx. 10s - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/f27) (finite) (2 / 2)", - "[104][extreme][knuth-bendix][kbmag][shortlex]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: (from kbmag/standalone/kb_data/f27) (finite) (2 / 2)", + "[104][extreme][knuth-bendix][kbmag][shortlex]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); Presentation p; @@ -167,7 +170,7 @@ namespace libsemigroups { presentation::add_rule(p, "fg", "a"); presentation::add_rule(p, "ga", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -179,7 +182,7 @@ namespace libsemigroups { // Mathieu group M_11 // Takes approx. 58s (majority in checking confluence) - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/m11)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/m11)", "[105][extreme][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -194,7 +197,7 @@ namespace libsemigroups { presentation::add_rule(p, "bbabbabba", "abbabbabb"); presentation::add_rule(p, "aBaBababaBabaBBaBab", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -207,10 +210,10 @@ namespace libsemigroups { presentation::add_rule(p, "a", "b"); presentation::add_rule(p, "B", "a"); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); REQUIRE(kb2.number_of_classes() == 1); - auto ntc = knuth_bendix::non_trivial_classes(kb2, kb); + auto ntc = knuth_bendix::non_trivial_classes(kb, kb2); REQUIRE(ntc.size() == 1); REQUIRE(ntc[0].size() == 7'920); REQUIRE(std::find(ntc[0].cbegin(), ntc[0].cend(), "") != ntc[0].cend()); @@ -223,7 +226,7 @@ namespace libsemigroups { // Weyl group E8 (all gens involutory). // Takes approx. 5s for KnuthBendix - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/e8)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/e8)", "[106][extreme][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -262,7 +265,7 @@ namespace libsemigroups { presentation::add_rule(p, "hf", "fh"); presentation::add_rule(p, "hgh", "ghg"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); REQUIRE(kb.confluent()); @@ -276,7 +279,7 @@ namespace libsemigroups { // Works quickest with large value of tidyint // Takes > 1m (knuth_bendix), didn't run to the end // Takes approx. 6s (knuth_bendix_by_overlap_length) - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/degen4b)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/degen4b)", "[107][extreme][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -289,7 +292,7 @@ namespace libsemigroups { presentation::add_rule(p, "ccBCbCacAABcbCCaaCAcaaCAc", ""); presentation::add_rule(p, "aaCAcAbaBBCacAAbbABabbABa", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); // kb.run(); knuth_bendix::by_overlap_length(kb); @@ -302,7 +305,7 @@ namespace libsemigroups { // value of tidyint works better. // Takes approx. 12s (knuth_bendix_by_overlap_length) // Takes > 19s (knuth_bendix), didn't run to the end - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/f27_2gen)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/f27_2gen)", "[108][extreme][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -314,7 +317,7 @@ namespace libsemigroups { presentation::add_rule(p, "bababbababbabbababbab", "a"); presentation::add_rule(p, "abbabbababbaba", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); knuth_bendix::by_overlap_length(kb); @@ -324,7 +327,7 @@ namespace libsemigroups { } // Takes approx. 1m8s - TEMPLATE_TEST_CASE("Example 6.6 in Sims", + TEMPLATE_TEST_CASE("KnuthBendix: Example 6.6 in Sims", "[109][extreme][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -338,7 +341,7 @@ namespace libsemigroups { presentation::add_rule(p, "ababababababab", ""); presentation::add_rule(p, "abacabacabacabacabacabacabacabac", ""); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); // knuth_bendix::by_overlap_length(kb); @@ -349,9 +352,10 @@ namespace libsemigroups { // Fibonacci group F(2,7) - without inverses // Takes approx. 13s - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/f27) (infinite) (1 / 2)", - "[110][extreme][knuth-bendix][kbmag][shortlex]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: (from kbmag/standalone/kb_data/f27) (infinite) (1 / 2)", + "[110][extreme][knuth-bendix][kbmag][shortlex]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); Presentation p; p.alphabet("aAbBcCdDyYfFgG"); @@ -364,7 +368,7 @@ namespace libsemigroups { presentation::add_rule(p, "fg", "a"); presentation::add_rule(p, "ga", "b"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); @@ -377,7 +381,7 @@ namespace libsemigroups { // An extension of 2^6 be L32 // Takes approx. 1m7s - TEMPLATE_TEST_CASE("(from kbmag/standalone/kb_data/l32ext)", + TEMPLATE_TEST_CASE("KnuthBendix: (from kbmag/standalone/kb_data/l32ext)", "[111][extreme][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -392,7 +396,7 @@ namespace libsemigroups { presentation::add_rule(p, "BaBaBaB", "abababa"); presentation::add_rule(p, "aBabaBabaBabaBab", "BabaBabaBabaBaba"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -412,7 +416,7 @@ namespace libsemigroups { // Tests that fail //////////////////////////////////////////////////////////////////////// - TEMPLATE_TEST_CASE("Ceitin's undecidable word problem example", + TEMPLATE_TEST_CASE("KnuthBendix: Ceitin's undecidable word problem example", "[112][fail][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -427,7 +431,7 @@ namespace libsemigroups { presentation::add_rule(p, "edb", "de"); presentation::add_rule(p, "cca", "ccae"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.run(); // I guess this shouldn't work, and indeed it doesn't! } @@ -461,7 +465,7 @@ namespace libsemigroups { presentation::add_rule(p, "cb", "bc"); presentation::add_rule(p, "ya", "ay"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); @@ -474,7 +478,7 @@ namespace libsemigroups { } while (std::next_permutation(perm.begin(), perm.end())); } - TEMPLATE_TEST_CASE("Sorouhesh", + TEMPLATE_TEST_CASE("KnuthBendix: Sorouhesh", "[114][quick][knuth-bendix][kbmag][shortlex]", KNUTH_BENDIX_TYPES) { using words::pow; @@ -488,7 +492,7 @@ namespace libsemigroups { presentation::add_rule(p, "aba", "b"); presentation::add_rule(p, "ab", pow("b", q) + "a"); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.confluent()); kb.run(); @@ -600,9 +604,10 @@ namespace libsemigroups { } } // namespace - TEMPLATE_TEST_CASE("all 2-generated 1-relation semigroups 1 to 10", - "[115][fail][knuth-bendix][xxx]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: all 2-generated 1-relation semigroups 1 to 10", + "[115][fail][knuth-bendix][xxx]", + KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); StringRange lhss; @@ -626,7 +631,7 @@ namespace libsemigroups { p.contains_empty_word(true); p.alphabet("ab"); presentation::add_rule(p, lhs, rhs); - TestType k(twosided, p); + KnuthBendix k(twosided, p); k.run_for(std::chrono::milliseconds(10)); if (k.confluent()) { register_relation(lhs, rhs, total_c4); @@ -639,7 +644,7 @@ namespace libsemigroups { p.contains_empty_word(true); p.alphabet("ba"); presentation::add_rule(p, lhs, rhs); - TestType k(twosided, p); + KnuthBendix k(twosided, p); k.run_for(std::chrono::milliseconds(10)); if (k.confluent()) { register_relation(lhs, rhs, total_c4); @@ -652,7 +657,7 @@ namespace libsemigroups { REQUIRE(total == 2'092'035); } - TEMPLATE_TEST_CASE("hard 2-generated 1-relation monoid", + TEMPLATE_TEST_CASE("KnuthBendix: hard 2-generated 1-relation monoid", "[116][fail][knuth-bendix][xxx2]", KNUTH_BENDIX_TYPES) { Presentation p; @@ -661,13 +666,13 @@ namespace libsemigroups { presentation::add_rule(p, "a", "cc"); presentation::add_rule(p, "c", "bab"); - TestType k(twosided, p); + KnuthBendix k(twosided, p); k.run(); // knuth_bendix::by_overlap_length(k); REQUIRE(k.active_rules().get() == rule_type({"", ""})); } - TEMPLATE_TEST_CASE("Konovalov", + TEMPLATE_TEST_CASE("KnuthBendix: Konovalov", "[117][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -677,14 +682,15 @@ namespace libsemigroups { presentation::add_rule(p, "Abba", "BB"); presentation::add_rule(p, "Baab", "AA"); - TestType k(twosided, p); + KnuthBendix k(twosided, p); k.run(); REQUIRE(k.number_of_classes() == POSITIVE_INFINITY); } - TEMPLATE_TEST_CASE("https://math.stackexchange.com/questions/2649807", - "[118][knuth-bendix][fail]", - KNUTH_BENDIX_TYPES) { + TEMPLATE_TEST_CASE( + "KnuthBendix: https://math.stackexchange.com/questions/2649807", + "[118][knuth-bendix][fail]", + KNUTH_BENDIX_TYPES) { do { std::string lphbt = "abcABC"; std::string invrs = "ABCabc"; @@ -711,7 +717,7 @@ namespace libsemigroups { presentation::add_rule(p, lhs, rhs); std::cout << "trying rule " << lhs << " -> " << rhs << std::endl; } - TestType k(twosided, p); + KnuthBendix k(twosided, p); k.run_for(std::chrono::seconds(1)); if (k.confluent()) { size_t const N = k.number_of_classes(); @@ -723,7 +729,7 @@ namespace libsemigroups { } while (true); } - TEMPLATE_TEST_CASE("example with undecidable word problem", + TEMPLATE_TEST_CASE("KnuthBendix: example with undecidable word problem", "[119][knuth-bendix][extreme]", KNUTH_BENDIX_TYPES) { Presentation p; @@ -734,7 +740,7 @@ namespace libsemigroups { presentation::add_rule(p, "abaaabb", "abbabaa"); presentation::add_rule(p, "bbbaabbaaba", "bbbaabbaaaa"); presentation::add_rule(p, "aaaabbaaba", "bbaaaa"); - TestType k(twosided, p); + KnuthBendix k(twosided, p); k.run_for(std::chrono::seconds(10)); REQUIRE(!k.finished()); } diff --git a/tests/test-knuth-bendix-5.cpp b/tests/test-knuth-bendix-5.cpp index 360c7c64d..372f5cbff 100644 --- a/tests/test-knuth-bendix-5.cpp +++ b/tests/test-knuth-bendix-5.cpp @@ -75,8 +75,10 @@ namespace libsemigroups { using knuth_bendix::reduce_no_run; using knuth_bendix::redundant_rule; -#define KNUTH_BENDIX_TYPES \ - KnuthBendix, KnuthBendix + using RewriteTrie = detail::RewriteTrie; + using RewriteFromLeft = detail::RewriteFromLeft; + +#define KNUTH_BENDIX_TYPES RewriteTrie, RewriteFromLeft namespace { using rule_type = KnuthBendix<>::rule_type; @@ -89,7 +91,7 @@ namespace libsemigroups { }; } // namespace - TEMPLATE_TEST_CASE("transformation semigroup (size 4)", + TEMPLATE_TEST_CASE("KnuthBendix: transformation semigroup (size 4)", "[120][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -99,7 +101,7 @@ namespace libsemigroups { auto p = to_presentation(S); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); REQUIRE(kb.presentation().rules.size() / 2 == 4); @@ -107,7 +109,7 @@ namespace libsemigroups { REQUIRE(kb.number_of_classes() == 4); } - TEMPLATE_TEST_CASE("transformation semigroup (size 9)", + TEMPLATE_TEST_CASE("KnuthBendix: transformation semigroup (size 9)", "[121][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -119,15 +121,15 @@ namespace libsemigroups { REQUIRE(S.degree() == 5); REQUIRE(S.number_of_rules() == 3); - auto p = to_presentation(S); - TestType kb(twosided, p); + auto p = to_presentation(S); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); REQUIRE(kb.number_of_active_rules() == 3); REQUIRE(kb.number_of_classes() == 9); } - TEMPLATE_TEST_CASE("transformation semigroup (size 88)", + TEMPLATE_TEST_CASE("KnuthBendix: transformation semigroup (size 88)", "[122][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -139,15 +141,15 @@ namespace libsemigroups { REQUIRE(S.degree() == 5); REQUIRE(S.number_of_rules() == 18); - auto p = to_presentation(S); - TestType kb(twosided, p); + auto p = to_presentation(S); + KnuthBendix kb(twosided, p); // kb.process_pending_rules(); REQUIRE(kb.confluent()); REQUIRE(kb.number_of_active_rules() == 18); REQUIRE(kb.number_of_classes() == 88); } - TEMPLATE_TEST_CASE("internal_string_to_word", + TEMPLATE_TEST_CASE("KnuthBendix: internal_string_to_word", "[123][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -157,13 +159,13 @@ namespace libsemigroups { auto p = to_presentation(S); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(kb.confluent()); auto t = to_froidure_pin(kb); REQUIRE(t.generator(0).word(kb) == 0_w); } - TEMPLATE_TEST_CASE("internal_string_to_word x 2", + TEMPLATE_TEST_CASE("KnuthBendix: internal_string_to_word x 2", "[124][quick]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -174,13 +176,13 @@ namespace libsemigroups { auto p = to_presentation(S); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); kb.run(); REQUIRE(kb.confluent()); REQUIRE(kb.number_of_classes() == 88); } - TEMPLATE_TEST_CASE("manual onesided congruence", + TEMPLATE_TEST_CASE("KnuthBendix: manual onesided congruence", "[125][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { using words::operator+; @@ -194,7 +196,7 @@ namespace libsemigroups { auto p = to_presentation(S); - TestType kb1(twosided, p); + KnuthBendix kb1(twosided, p); REQUIRE(kb1.number_of_classes() == 88); presentation::add_rule_no_checks( @@ -204,7 +206,7 @@ namespace libsemigroups { p.alphabet(3); - TestType kb2(twosided, p); + KnuthBendix kb2(twosided, p); auto words = (froidure_pin::normal_forms(S) | rx::transform([](word_type const& w) { return 2_w + w; })); @@ -276,7 +278,7 @@ namespace libsemigroups { {1000100_w, 01000110_w, 10001100_w, 001000100_w, 010001000_w}})); } - TEMPLATE_TEST_CASE("onesided congruence!!!", + TEMPLATE_TEST_CASE("KnuthBendix: onesided congruence!!!", "[126][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { using words::operator+; @@ -290,8 +292,8 @@ namespace libsemigroups { auto p = to_presentation(S); - TestType kb(onesided, p); - Presentation q(kb.presentation()); + KnuthBendix kb(onesided, p); + Presentation q(kb.presentation()); presentation::change_alphabet(q, "ab"); REQUIRE(q.rules @@ -382,7 +384,7 @@ namespace libsemigroups { {1000100_w, 01000110_w, 10001100_w, 001000100_w, 010001000_w}})); } - TEMPLATE_TEST_CASE("manual left congruence!!!", + TEMPLATE_TEST_CASE("KnuthBendix: manual left congruence!!!", "[127][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { using words::operator+; @@ -401,9 +403,9 @@ namespace libsemigroups { presentation::reverse(p); REQUIRE(!p.contains_empty_word()); p.alphabet("abc"); - TestType kb(twosided, p); - ToString to_string; - ToWord to_word; + KnuthBendix kb(twosided, p); + ToString to_string; + ToWord to_word; REQUIRE(to_string(froidure_pin::factorisation(S, Transf<>({3, 4, 4, 4, 4}))) == "abaaabbaa"); @@ -445,7 +447,7 @@ namespace libsemigroups { REQUIRE(kb.gilman_graph().number_of_nodes() == 51); } - TEMPLATE_TEST_CASE("automatic left congruence!!!", + TEMPLATE_TEST_CASE("KnuthBendix: automatic left congruence!!!", "[128][quick][knuth-bendix][no-valgrind]", KNUTH_BENDIX_TYPES) { using words::operator+; @@ -461,7 +463,7 @@ namespace libsemigroups { REQUIRE(!p.contains_empty_word()); presentation::reverse(p); - TestType kb(onesided, p); + KnuthBendix kb(onesided, p); add_generating_pair(kb, "aabbaaaba", "baaab"); diff --git a/tests/test-knuth-bendix-6.cpp b/tests/test-knuth-bendix-6.cpp index 353cc5012..5dd26002e 100644 --- a/tests/test-knuth-bendix-6.cpp +++ b/tests/test-knuth-bendix-6.cpp @@ -55,10 +55,12 @@ namespace libsemigroups { using literals::operator""_w; -#define KNUTH_BENDIX_TYPES \ - KnuthBendix, KnuthBendix + using RewriteTrie = detail::RewriteTrie; + using RewriteFromLeft = detail::RewriteFromLeft; - TEMPLATE_TEST_CASE("Presentation", +#define KNUTH_BENDIX_TYPES RewriteTrie, RewriteFromLeft + + TEMPLATE_TEST_CASE("KnuthBendix: Presentation", "[129][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -68,7 +70,7 @@ namespace libsemigroups { presentation::add_rule(p, 000_w, 0_w); presentation::add_rule(p, 0_w, 11_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!kb.finished()); REQUIRE(kb.number_of_classes() == 5); @@ -81,7 +83,7 @@ namespace libsemigroups { REQUIRE(!knuth_bendix::contains(kb, 0000_w, 000_w)); } - TEMPLATE_TEST_CASE("free semigroup congruence (6 classes)", + TEMPLATE_TEST_CASE("KnuthBendix: free semigroup congruence (6 classes)", "[130][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -104,7 +106,7 @@ namespace libsemigroups { presentation::add_rule(p, 14233_w, 0_w); presentation::add_rule(p, 444_w, 0_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(kb.number_of_classes() == 6); REQUIRE(knuth_bendix::contains(kb, 1_w, 2_w)); @@ -112,7 +114,7 @@ namespace libsemigroups { // more than 255 generators } - TEMPLATE_TEST_CASE("free semigroup congruence (16 classes)", + TEMPLATE_TEST_CASE("KnuthBendix: free semigroup congruence (16 classes)", "[131][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -141,14 +143,14 @@ namespace libsemigroups { presentation::add_rule(p, 2010_w, 201_w); presentation::add_rule(p, 2020_w, 202_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(kb.number_of_classes() == 16); REQUIRE(kb.number_of_active_rules() == 18); REQUIRE(knuth_bendix::contains(kb, 2_w, 3_w)); } - TEMPLATE_TEST_CASE("free semigroup congruence (6 classes) x 2", + TEMPLATE_TEST_CASE("KnuthBendix: free semigroup congruence (6 classes) x 2", "[132][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -176,7 +178,7 @@ namespace libsemigroups { {1, 3, 0, 1}, {1, 0, 1}, {1, 3, 0, 3}, {3, 0, 3}, {3, 0, 1, 0}, {3, 0, 1}, {3, 0, 3, 0}, {3, 0, 3}}; - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(kb.number_of_classes() == 16); REQUIRE(knuth_bendix::contains(kb, {0}, {5})); REQUIRE(knuth_bendix::contains(kb, {0}, {5})); @@ -189,7 +191,7 @@ namespace libsemigroups { REQUIRE(knuth_bendix::contains(kb, {3}, {9})); } - TEMPLATE_TEST_CASE("free semigroup congruence (240 classes)", + TEMPLATE_TEST_CASE("KnuthBendix: free semigroup congruence (240 classes)", "[133][no-valgrind][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -201,11 +203,11 @@ namespace libsemigroups { presentation::add_rule(p, 1001_w, 11_w); presentation::add_rule(p, 001010101010_w, 00_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(kb.number_of_classes() == 240); } - TEMPLATE_TEST_CASE("free semigroup congruence (240 classes) x 2", + TEMPLATE_TEST_CASE("KnuthBendix: free semigroup congruence (240 classes) x 2", "[134][no-valgrind][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -217,11 +219,11 @@ namespace libsemigroups { presentation::add_rule(p, 1001_w, 11_w); presentation::add_rule(p, 001010101010_w, 00_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE_NOTHROW(to_froidure_pin(kb)); } - TEMPLATE_TEST_CASE("constructors", + TEMPLATE_TEST_CASE("KnuthBendix: constructors", "[135][quick][knuth-bendix][no-valgrind]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -231,7 +233,7 @@ namespace libsemigroups { presentation::add_rule(p, 111111111_w, 1_w); presentation::add_rule(p, 011111011_w, 110_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(kb.number_of_classes() == 746); auto copy(kb); @@ -242,7 +244,7 @@ namespace libsemigroups { REQUIRE(copy.number_of_active_rules() == 105); } - TEMPLATE_TEST_CASE("to_froidure_pin", + TEMPLATE_TEST_CASE("KnuthBendix: to_froidure_pin", "[136][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -252,11 +254,11 @@ namespace libsemigroups { presentation::add_rule(p, 1111_w, 1_w); presentation::add_rule(p, 011111011_w, 110_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(to_froidure_pin(kb).size() == 12); } - TEMPLATE_TEST_CASE("number of classes when obv-inf", + TEMPLATE_TEST_CASE("KnuthBendix: number of classes when obv-inf", "[137][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -274,18 +276,18 @@ namespace libsemigroups { presentation::add_rule(p, 21_w, 1_w); presentation::add_rule(p, 0_w, 1_w); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(is_obviously_infinite(kb)); REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); } - TEMPLATE_TEST_CASE("Chinese monoid x 2", + TEMPLATE_TEST_CASE("KnuthBendix: Chinese monoid x 2", "[138][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); Presentation p = fpsemigroup::chinese_monoid(3); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(is_obviously_infinite(kb)); REQUIRE(kb.number_of_classes() == POSITIVE_INFINITY); REQUIRE(kb.presentation().rules.size() / 2 == 8); @@ -293,7 +295,7 @@ namespace libsemigroups { REQUIRE(nf.count() == 1'175); } - TEMPLATE_TEST_CASE("partial_transformation_monoid(4)", + TEMPLATE_TEST_CASE("KnuthBendix: partial_transformation_monoid(4)", "[139][standard][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(false); @@ -301,13 +303,17 @@ namespace libsemigroups { size_t n = 4; auto p = partial_transformation_monoid(n, fpsemigroup::author::Sutov); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!is_obviously_infinite(kb)); REQUIRE(kb.number_of_classes() == 625); + REQUIRE(to_human_readable_repr(kb) + == " with 362/204 " + "active/inactive rules>"); } // Takes about 1 minute - TEMPLATE_TEST_CASE("partial_transformation_monoid5", + TEMPLATE_TEST_CASE("KnuthBendix: partial_transformation_monoid5", "[140][extreme][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); @@ -315,27 +321,27 @@ namespace libsemigroups { size_t n = 5; auto p = partial_transformation_monoid(n, fpsemigroup::author::Sutov); - TestType kb(twosided, p); + KnuthBendix kb(twosided, p); REQUIRE(!is_obviously_infinite(kb)); REQUIRE(kb.number_of_classes() == 7'776); } // Takes about 5 seconds - TEMPLATE_TEST_CASE("full_transformation_monoid Iwahori", + TEMPLATE_TEST_CASE("KnuthBendix: full_transformation_monoid Iwahori", "[141][extreme][knuth-bendix]", KNUTH_BENDIX_TYPES) { auto rg = ReportGuard(true); - size_t n = 5; - auto p = full_transformation_monoid(n, fpsemigroup::author::Iwahori); - TestType kb(twosided, p); + size_t n = 5; + auto p = full_transformation_monoid(n, fpsemigroup::author::Iwahori); + KnuthBendix kb(twosided, p); REQUIRE(!is_obviously_infinite(kb)); kb.run(); REQUIRE(kb.number_of_active_rules() == 1'162); REQUIRE(kb.number_of_classes() == 3'125); } - TEMPLATE_TEST_CASE("constructors/init for finished x 2", + TEMPLATE_TEST_CASE("KnuthBendix: constructors/init for finished x 2", "[142][quick][knuth-bendix]", KNUTH_BENDIX_TYPES) { using literals::operator""_w; @@ -357,7 +363,7 @@ namespace libsemigroups { presentation::add_rule(p2, 111_w, {}); presentation::add_rule(p2, 010101_w, {}); - TestType kb1(twosided, p1); + KnuthBendix kb1(twosided, p1); REQUIRE(!kb1.confluent()); REQUIRE(!kb1.finished()); kb1.run(); @@ -382,7 +388,7 @@ namespace libsemigroups { REQUIRE(kb1.confluent_known()); REQUIRE(kb1.number_of_active_rules() == 8); - TestType kb2(std::move(kb1)); + KnuthBendix kb2(std::move(kb1)); REQUIRE(kb2.confluent()); REQUIRE(kb2.confluent_known()); REQUIRE(kb2.finished()); @@ -403,7 +409,7 @@ namespace libsemigroups { REQUIRE(kb1.confluent_known()); REQUIRE(kb1.number_of_active_rules() == 8); - TestType kb3(twosided, std::move(p2)); + KnuthBendix kb3(twosided, std::move(p2)); REQUIRE(!kb3.confluent()); REQUIRE(!kb3.finished()); kb3.run(); diff --git a/tests/test-todd-coxeter.cpp b/tests/test-todd-coxeter.cpp index 78b258f71..ff28985bf 100644 --- a/tests/test-todd-coxeter.cpp +++ b/tests/test-todd-coxeter.cpp @@ -22,7 +22,7 @@ #include "catch_amalgamated.hpp" // for TEST_CASE #include "libsemigroups/constants.hpp" -#include "test-main.hpp" // for LIBSEMIGROUPS_TEST_CASE +#include "test-main.hpp" // for LIBSEMIGROUPS_TEST_CASE_V3 #include "libsemigroups/bmat8.hpp" #include "libsemigroups/fpsemi-examples.hpp" // for dual_symmetric_... @@ -288,10 +288,10 @@ namespace libsemigroups { } } // namespace - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "000", - "small 2-sided congruence", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "000", + "small 2-sided congruence", + "[todd-coxeter][quick]") { using namespace rx; auto rg = ReportGuard(false); @@ -335,10 +335,10 @@ namespace libsemigroups { check_normal_forms(tc, tc.number_of_classes()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "001", - "small 2-sided congruence x 2", - "[no-valgrind][todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "001", + "small 2-sided congruence x 2", + "[no-valgrind][todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; @@ -433,10 +433,10 @@ namespace libsemigroups { } // Felsch is actually faster here! - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "002", - "Example 6.6 in Sims (see also KnuthBendix 013)", - "[todd-coxeter][standard]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "002", + "Example 6.6 in Sims (see also KnuthBendix 013)", + "[todd-coxeter][standard]") { auto rg = ReportGuard(false); Presentation p; @@ -504,10 +504,11 @@ namespace libsemigroups { {0_w, 1_w, 2_w, 3_w, 12_w, 13_w, 21_w, 31_w, 121_w, 131_w})); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "003", - "constructed from FroidurePin", - "[no-valgrind][todd-coxeter][quick][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "003", + "constructed from FroidurePin", + "[no-valgrind][todd-coxeter][quick][no-coverage]") { auto rg = ReportGuard(false); FroidurePin S = to_froidure_pin( @@ -568,10 +569,10 @@ namespace libsemigroups { check_normal_forms(tc, tc.number_of_classes()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "004", - "2-sided congruence from FroidurePin", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "004", + "2-sided congruence from FroidurePin", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); using Transf = LeastTransf<5>; @@ -620,10 +621,10 @@ namespace libsemigroups { check_normal_forms(tc, tc.number_of_classes()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "005", - "non-trivial two-sided from relations", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "005", + "non-trivial two-sided from relations", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; @@ -653,10 +654,10 @@ namespace libsemigroups { check_normal_forms(tc, tc.number_of_classes()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "006", - "small onesided cong. on free semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "006", + "small onesided cong. on free semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(2); @@ -678,10 +679,10 @@ namespace libsemigroups { check_normal_forms(tc, tc.number_of_classes()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "007", - "left cong. on free semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "007", + "left cong. on free semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(2); @@ -715,10 +716,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "008", - "for small fp semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "008", + "for small fp semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(2); @@ -743,10 +744,10 @@ namespace libsemigroups { } // TODO move to test-to-todd-coxeter - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "009", - "2-sided cong. trans. semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "009", + "2-sided cong. trans. semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); auto S = to_froidure_pin( {Transf<>({1, 3, 4, 2, 3}), Transf<>({3, 2, 1, 3, 3})}); @@ -854,10 +855,10 @@ namespace libsemigroups { } } // namespace - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "010", - "left congruence on transformation semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "010", + "left congruence on transformation semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); auto S = to_froidure_pin( {Transf<>({1, 3, 4, 2, 3}), Transf<>({3, 2, 1, 3, 3})}); @@ -903,10 +904,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "011", - "onesided cong. trans. semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "011", + "onesided cong. trans. semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); auto S = to_froidure_pin( {Transf<>({1, 3, 4, 2, 3}), Transf<>({3, 2, 1, 3, 3})}); @@ -969,10 +970,10 @@ namespace libsemigroups { REQUIRE(index_of(tc, w5) == index_of(tc, w6)); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "012", - "trans. semigroup (size 88)", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "012", + "trans. semigroup (size 88)", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); FroidurePin> S; @@ -1007,10 +1008,10 @@ namespace libsemigroups { REQUIRE(index_of(tc, w3) == index_of(tc, w4)); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "015", - "finite fp-semigroup, dihedral group of order 6 ", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "015", + "finite fp-semigroup, dihedral group of order 6 ", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; @@ -1035,10 +1036,10 @@ namespace libsemigroups { REQUIRE(index_of(tc, {1}) == index_of(tc, {2})); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "016", - "finite fp-semigroup, size 16", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "016", + "finite fp-semigroup, size 16", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(4); @@ -1077,10 +1078,10 @@ namespace libsemigroups { REQUIRE(index_of(tc, {2}) == index_of(tc, {3})); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "017", - "finite fp-semigroup, size 16 x 2", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "017", + "finite fp-semigroup, size 16 x 2", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(11); @@ -1154,10 +1155,10 @@ namespace libsemigroups { REQUIRE(index_of(tc, {3}) == index_of(tc, {9})); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "018", - "test lookahead", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "018", + "test lookahead", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(2); @@ -1193,10 +1194,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "020", - "2-sided cong. on free semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "020", + "2-sided cong. on free semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(1); @@ -1213,10 +1214,10 @@ namespace libsemigroups { REQUIRE(!contains(tc, 00_w, 0_w)); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "021", - "calling run when obviously infinite", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "021", + "calling run when obviously infinite", + "[todd-coxeter][quick]") { Presentation p; p.alphabet(5); ToddCoxeter tc(twosided, p); @@ -1231,10 +1232,10 @@ namespace libsemigroups { REQUIRE_THROWS_AS(tc.run(), LibsemigroupsException); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "022", - "stellar_monoid S3", - "[todd-coxeter][quick][hivert]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "022", + "stellar_monoid S3", + "[todd-coxeter][quick][hivert]") { auto rg = ReportGuard(false); Presentation p; @@ -1297,10 +1298,10 @@ namespace libsemigroups { os << TCE(32); // Does not do anything visible } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "023", - "finite semigroup (size 5)", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "023", + "finite semigroup (size 5)", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; presentation::add_rule_no_checks(p, 000_w, 0_w); @@ -1320,10 +1321,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 5); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "024", - "exceptions", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "024", + "exceptions", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(2); @@ -1366,10 +1367,10 @@ namespace libsemigroups { // semigroup with 2 generators } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "025", - "obviously infinite", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "025", + "obviously infinite", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(3); @@ -1389,10 +1390,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "026", - "exceptions x 2", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "026", + "exceptions x 2", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; presentation::add_rule_no_checks(p, 000_w, 0_w); @@ -1433,10 +1434,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "028", - "quotient ToddCoxeter", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "028", + "quotient ToddCoxeter", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -1463,10 +1464,10 @@ namespace libsemigroups { } // TODO move to to-todd-coxeter.hpp - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "029", - "from KnuthBendix", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "029", + "from KnuthBendix", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; @@ -1511,10 +1512,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 1); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "031", - "KnuthBendix.finished()", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "031", + "KnuthBendix.finished()", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; @@ -1546,10 +1547,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "032", - "from WordGraph", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "032", + "from WordGraph", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); WordGraph d(1, 2); @@ -1558,10 +1559,10 @@ namespace libsemigroups { REQUIRE_NOTHROW(ToddCoxeter(twosided, d)); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "033", - "congruence of ToddCoxeter", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "033", + "congruence of ToddCoxeter", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(2); @@ -1582,10 +1583,10 @@ namespace libsemigroups { REQUIRE(tc2.number_of_classes() == 3); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "034", - "congruence of ToddCoxeter x 2", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "034", + "congruence of ToddCoxeter x 2", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); using Transf = LeastTransf<5>; FroidurePin S @@ -1606,10 +1607,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 1); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "035", - "congruence over fp semigroup", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "035", + "congruence over fp semigroup", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abe"); @@ -1671,10 +1672,10 @@ namespace libsemigroups { {"babaaa"}})); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "037", - "copy constructor", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "037", + "copy constructor", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet(2); @@ -1719,7 +1720,7 @@ namespace libsemigroups { REQUIRE(tc.current_word_graph() == copy.current_word_graph()); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "039", "stylic_monoid", @@ -1756,10 +1757,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 115'975); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "040", - "fibonacci_semigroup(4, 6)", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "040", + "fibonacci_semigroup(4, 6)", + "[todd-coxeter][fail]") { using fpsemigroup::fibonacci_semigroup; auto rg = ReportGuard(); @@ -1768,10 +1769,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 0); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "041", - "some finite classes", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "041", + "some finite classes", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; @@ -1851,10 +1852,10 @@ namespace libsemigroups { } // Takes about 1.8s - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "042", - "symmetric_group(9, Moore)", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "042", + "symmetric_group(9, Moore)", + "[todd-coxeter][extreme]") { using fpsemigroup::author; using fpsemigroup::symmetric_group; @@ -1884,10 +1885,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 362'880); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "043", - "symmetric_group(7, Coxeter + Moser)", - "[todd-coxeter][quick][no-valgrind]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "043", + "symmetric_group(7, Coxeter + Moser)", + "[todd-coxeter][quick][no-valgrind]") { using fpsemigroup::author; using fpsemigroup::symmetric_group; @@ -1914,10 +1915,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 5'040); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "116", - "symmetric_group(7, Burnside + Miller)", - "[todd-coxeter][quick][no-valgrind]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "116", + "symmetric_group(7, Burnside + Miller)", + "[todd-coxeter][quick][no-valgrind]") { using fpsemigroup::author; using fpsemigroup::symmetric_group; auto rg = ReportGuard(false); @@ -1936,10 +1937,11 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 5'040); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "046", - "Easdown-East-FitzGerald DualSymInv(5)", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "046", + "Easdown-East-FitzGerald DualSymInv(5)", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { auto rg = ReportGuard(false); auto const n = 5; auto p = fpsemigroup::dual_symmetric_inverse_monoid(n); @@ -1956,10 +1958,10 @@ namespace libsemigroups { check_complete_compatible(tc); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "047", - "uniform_block_bijection_monoid(3) (FitzGerald) ", - "[todd-coxeter][quick][no-valgrind]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "047", + "uniform_block_bijection_monoid(3) (FitzGerald) ", + "[todd-coxeter][quick][no-valgrind]") { using fpsemigroup::author; using fpsemigroup::uniform_block_bijection_monoid; @@ -1980,10 +1982,11 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 1496); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "048", - "stellar_monoid(7) (Gay-Hivert)", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "048", + "stellar_monoid(7) (Gay-Hivert)", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { using fpsemigroup::stellar_monoid; auto rg = ReportGuard(false); @@ -2002,10 +2005,11 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 13'700); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "049", - "partition_monoid(4) (East)", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "049", + "partition_monoid(4) (East)", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { auto rg = ReportGuard(false); using fpsemigroup::author; using fpsemigroup::partition_monoid; @@ -2025,10 +2029,11 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 4'140); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "050", - "singular_brauer_monoid(6) (Maltcev + Mazorchuk)", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "050", + "singular_brauer_monoid(6) (Maltcev + Mazorchuk)", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { using fpsemigroup::singular_brauer_monoid; auto rg = ReportGuard(false); @@ -2048,10 +2053,11 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 9); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "051", - "orientation_preserving_monoid(6) (Ruskuc + Arthur)", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "051", + "orientation_preserving_monoid(6) (Ruskuc + Arthur)", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { using fpsemigroup::orientation_preserving_monoid; auto rg = ReportGuard(false); size_t const n = 4; @@ -2070,7 +2076,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 128); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "052", "orientation_preserving_reversing_monoid(5) (Ruskuc + Arthur)", @@ -2091,10 +2097,11 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 1'015); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "053", - "temperley_lieb_monoid(10) (East)", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "053", + "temperley_lieb_monoid(10) (East)", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { using fpsemigroup::temperley_lieb_monoid; auto rg = ReportGuard(false); size_t const n = 10; @@ -2118,7 +2125,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 16'796); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "054", "Generate GAP benchmarks for stellar_monoid(n) (Gay-Hivert)", @@ -2132,7 +2139,7 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "055", "Generate GAP benchmarks for partition_monoid(n) (East)", @@ -2149,11 +2156,12 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "056", - "Generate GAP benchmarks for dual symmetric inverse " - "monoid (Easdown + East + FitzGerald)", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "056", + "Generate GAP benchmarks for dual symmetric inverse " + "monoid (Easdown + East + FitzGerald)", + "[todd-coxeter][fail]") { using fpsemigroup::author; using fpsemigroup::dual_symmetric_inverse_monoid; auto rg = ReportGuard(true); @@ -2166,11 +2174,11 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "057", - "Generate GAP benchmarks for " - "uniform_block_bijection_monoid (FitzGerald)", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "057", + "Generate GAP benchmarks for " + "uniform_block_bijection_monoid (FitzGerald)", + "[todd-coxeter][fail]") { using fpsemigroup::author; using fpsemigroup::uniform_block_bijection_monoid; @@ -2184,10 +2192,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "058", - "Generate GAP benchmarks for stylic monoids", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "058", + "Generate GAP benchmarks for stylic monoids", + "[todd-coxeter][fail]") { using fpsemigroup::stylic_monoid; auto rg = ReportGuard(true); @@ -2198,10 +2206,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "059", - "Generate GAP benchmarks for OP_n", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "059", + "Generate GAP benchmarks for OP_n", + "[todd-coxeter][fail]") { using fpsemigroup::orientation_preserving_monoid; auto rg = ReportGuard(true); @@ -2212,10 +2220,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "060", - "Generate GAP benchmarks for OR_n", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "060", + "Generate GAP benchmarks for OR_n", + "[todd-coxeter][fail]") { using fpsemigroup::orientation_preserving_reversing_monoid; auto rg = ReportGuard(true); @@ -2227,7 +2235,7 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "061", "Generate GAP benchmarks for temperley_lieb_monoid(n)", @@ -2243,7 +2251,7 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "062", "Generate GAP benchmarks for singular_brauer_monoid(n)", @@ -2259,10 +2267,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "111", - "partition_monoid(2)", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "111", + "partition_monoid(2)", + "[todd-coxeter][quick]") { using fpsemigroup::author; using fpsemigroup::partition_monoid; @@ -2279,10 +2287,11 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 15); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "112", - "brauer_monoid(4) (Kudryavtseva + Mazorchuk)", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "112", + "brauer_monoid(4) (Kudryavtseva + Mazorchuk)", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { using fpsemigroup::brauer_monoid; auto rg = ReportGuard(false); @@ -2300,10 +2309,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 105); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "113", - "symmetric_inverse_monoid(5, Sutov)", - "[todd-coxeter][quick][no-valgrind]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "113", + "symmetric_inverse_monoid(5, Sutov)", + "[todd-coxeter][quick][no-valgrind]") { using fpsemigroup::author; using fpsemigroup::symmetric_inverse_monoid; @@ -2320,10 +2329,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 1'546); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "114", - "partial_transformation_monoid(5, Sutov)", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "114", + "partial_transformation_monoid(5, Sutov)", + "[todd-coxeter][extreme]") { using fpsemigroup::author; using fpsemigroup::partial_transformation_monoid; @@ -2342,10 +2351,10 @@ namespace libsemigroups { } // stop_early in lookahead really helps in this example - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "115", - "full_transformation_monoid(7, Iwahori)", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "115", + "full_transformation_monoid(7, Iwahori)", + "[todd-coxeter][extreme]") { using fpsemigroup::author; using fpsemigroup::full_transformation_monoid; @@ -2373,10 +2382,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 823'543); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "063", - "add_rule", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "063", + "add_rule", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); { Presentation p; @@ -2470,10 +2479,10 @@ namespace libsemigroups { } // KnuthBendix methods fail for this one - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "064", - "from kbmag/standalone/kb_data/s4", - "[todd-coxeter][quick][kbmag]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "064", + "from kbmag/standalone/kb_data/s4", + "[todd-coxeter][quick][kbmag]") { auto rg = ReportGuard(false); Presentation p; @@ -2508,11 +2517,11 @@ namespace libsemigroups { // Second of BHN's series of increasingly complicated presentations // of 1. Doesn't terminate - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "065", - "(from kbmag/standalone/kb_data/degen4b) " - "(KnuthBendix 065)", - "[fail][todd-coxeter][kbmag][shortlex]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "065", + "(from kbmag/standalone/kb_data/degen4b) " + "(KnuthBendix 065)", + "[fail][todd-coxeter][kbmag][shortlex]") { auto rg = ReportGuard(true); Presentation p; @@ -2548,10 +2557,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 1); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "067", - "Repeated construction from same FroidurePin", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "067", + "Repeated construction from same FroidurePin", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); using Transf = LeastTransf<5>; @@ -2601,10 +2610,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "068", - "Sym(5) from Chapter 3, Proposition 1.1 in NR", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "068", + "Sym(5) from Chapter 3, Proposition 1.1 in NR", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; @@ -2650,10 +2659,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 120); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "069", - "Chapter 7, Theorem 3.6 in NR (size 243)", - "[no-valgrind][todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "069", + "Chapter 7, Theorem 3.6 in NR (size 243)", + "[no-valgrind][todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -2673,10 +2682,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 243); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "070", - "finite semigroup (size 99)", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "070", + "finite semigroup (size 99)", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -2702,10 +2711,10 @@ namespace libsemigroups { // The following 8 examples are from Trevor Walker's Thesis: Semigroup // enumeration - computer implementation and applications, p41. - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "071", - "Walker 1", - "[todd-coxeter][standard][no-valgrind]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "071", + "Walker 1", + "[todd-coxeter][standard][no-valgrind]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcABCDEFGHIXYZ"); @@ -2781,10 +2790,11 @@ namespace libsemigroups { // The following example is a good one for using the lookahead. // This is no longer extreme with the preprocessing - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "072", - "Walker 2", - "[todd-coxeter][quick][no-coverage][no-valgrind]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "072", + "Walker 2", + "[todd-coxeter][quick][no-coverage][no-valgrind]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -2843,10 +2853,10 @@ namespace libsemigroups { REQUIRE(contains(tc, "dd", "a")); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "073", - "Walker 3", - "[todd-coxeter][standard]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "073", + "Walker 3", + "[todd-coxeter][standard]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -2872,10 +2882,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 20'490); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "074", - "Walker 4", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "074", + "Walker 4", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(); Presentation p; p.alphabet("ab"); @@ -2923,10 +2933,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 36'412); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "075", - "Walker 5", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "075", + "Walker 5", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(true); Presentation p; p.alphabet("ab"); @@ -2967,10 +2977,10 @@ namespace libsemigroups { check_complete_compatible(tc); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "076", - "not Walker 6", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "076", + "not Walker 6", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(); Presentation p; p.alphabet("ab"); @@ -3013,10 +3023,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 8); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "077", - "Walker 6", - "[todd-coxeter][standard]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "077", + "Walker 6", + "[todd-coxeter][standard]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -3062,10 +3072,10 @@ namespace libsemigroups { } // Felsch is faster here too! - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "078", - "Walker 7", - "[todd-coxeter][standard]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "078", + "Walker 7", + "[todd-coxeter][standard]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcde"); @@ -3105,10 +3115,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 153'500); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "079", - "Walker 8", - "[todd-coxeter][standard]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "079", + "Walker 8", + "[todd-coxeter][standard]") { auto rg = ReportGuard(false); Presentation p; @@ -3147,10 +3157,11 @@ namespace libsemigroups { } // This is a good example of why large collapse is required - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "080", - "KnuthBendix 098", - "[todd-coxeter][quick][no-valgrind][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "080", + "KnuthBendix 098", + "[todd-coxeter][quick][no-valgrind][no-coverage]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("aAbBcCdDyYfFgGe"); @@ -3176,10 +3187,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 29); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "081", - "Holt 2 - SL(2, p)", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "081", + "Holt 2 - SL(2, p)", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(); std::array const sizes = {24, 120, 336, 1'320}; std::array const primes = {3, 5, 7, 11}; @@ -3196,10 +3207,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "082", - "Holt 3", - "[todd-coxeter][standard]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "082", + "Holt 3", + "[todd-coxeter][standard]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("aAbBcC"); @@ -3224,10 +3235,10 @@ namespace libsemigroups { check_normal_forms(tc, 0); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "083", - "Holt 3 x 2", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "083", + "Holt 3 x 2", + "[todd-coxeter][fail]") { auto rg = ReportGuard(); Presentation p; p.alphabet("aAbBcC"); @@ -3252,10 +3263,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 6'561); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "084", - "Campbell-Reza 1", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "084", + "Campbell-Reza 1", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("ab"); @@ -3295,10 +3306,11 @@ namespace libsemigroups { } // The next example demonstrates why we require deferred standardization - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "085", - "Renner monoid type D4 (Gay-Hivert), q = 1", - "[no-valgrind][quick][todd-coxeter][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "085", + "Renner monoid type D4 (Gay-Hivert), q = 1", + "[no-valgrind][quick][todd-coxeter][no-coverage]") { auto rg = ReportGuard(false); ToddCoxeter tc(twosided, fpsemigroup::renner_type_D_monoid(4, 1)); @@ -3327,10 +3339,11 @@ namespace libsemigroups { } // Felsch very slow here - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "086", - "trivial semigroup", - "[no-valgrind][todd-coxeter][quick][no-coverage]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "086", + "trivial semigroup", + "[no-valgrind][todd-coxeter][quick][no-coverage]") { auto rg = ReportGuard(false); for (size_t N = 2; N < 1000; N += 199) { @@ -3354,10 +3367,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "087", - "ACE --- 2p17-2p14 - HLT", - "[todd-coxeter][standard][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "087", + "ACE --- 2p17-2p14 - HLT", + "[todd-coxeter][standard][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcABC"); @@ -3388,10 +3401,10 @@ namespace libsemigroups { "cAaC", "cBbC"})); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "088", - "ACE --- 2p17-2p3 - HLT", - "[todd-coxeter][standard][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "088", + "ACE --- 2p17-2p3 - HLT", + "[todd-coxeter][standard][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcABC"); @@ -3419,10 +3432,10 @@ namespace libsemigroups { // In this example large_collapse makes a huge difference to the run time, // 73ms versus 1173ms for the save case. - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "089", - "ACE --- 2p17-1a - HLT", - "[todd-coxeter][standard][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "089", + "ACE --- 2p17-1a - HLT", + "[todd-coxeter][standard][ace]") { auto rg = ReportGuard(false); Presentation p; @@ -3450,10 +3463,10 @@ namespace libsemigroups { REQUIRE(H.number_of_classes() == 1); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "090", - "ACE --- F27", - "[todd-coxeter][standard][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "090", + "ACE --- F27", + "[todd-coxeter][standard][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcdxyzABCDXYZ"); @@ -3479,10 +3492,10 @@ namespace libsemigroups { REQUIRE(H.number_of_classes() == 29); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "091", - "ACE --- SL219 - HLT", - "[todd-coxeter][standard][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "091", + "ACE --- SL219 - HLT", + "[todd-coxeter][standard][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abAB"); @@ -3528,10 +3541,10 @@ namespace libsemigroups { REQUIRE(H.number_of_classes() == 180); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "092", - "ACE --- perf602p5", - "[no-valgrind][todd-coxeter][quick][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "092", + "ACE --- perf602p5", + "[no-valgrind][todd-coxeter][quick][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abstuvdABSTUVD"); @@ -3579,10 +3592,10 @@ namespace libsemigroups { REQUIRE(H.number_of_classes() == 480); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "093", - "ACE --- M12", - "[todd-coxeter][standard][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "093", + "ACE --- M12", + "[todd-coxeter][standard][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abcABC"); @@ -3613,10 +3626,10 @@ namespace libsemigroups { REQUIRE(H.number_of_classes() == 95'040); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "094", - "ACE --- C5", - "[todd-coxeter][quick][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "094", + "ACE --- C5", + "[todd-coxeter][quick][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abAB"); @@ -3638,10 +3651,10 @@ namespace libsemigroups { REQUIRE(H.number_of_classes() == 5); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "095", - "ACE --- A5-C5", - "[todd-coxeter][quick][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "095", + "ACE --- A5-C5", + "[todd-coxeter][quick][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abAB"); @@ -3666,10 +3679,10 @@ namespace libsemigroups { REQUIRE(H.number_of_classes() == 12); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "096", - "ACE --- A5", - "[todd-coxeter][quick][ace]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "096", + "ACE --- A5", + "[todd-coxeter][quick][ace]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abAB"); @@ -3696,10 +3709,10 @@ namespace libsemigroups { // stands out as being the cause of this, in v2 this takes about 1.4s in v3 // 1.5s or so. // Seems to have gotten worse still since the comment about up to 1.8s - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "097", - "relation ordering", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "097", + "relation ordering", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(true); // Sorting the rules makes this twice as slow... auto p = fpsemigroup::renner_type_D_monoid(5, 1); @@ -3716,10 +3729,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 258'661); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "098", - "relation ordering x 2", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "098", + "relation ordering x 2", + "[todd-coxeter][quick]") { Presentation p; p.alphabet(10); presentation::add_rule(p, 01_w, 0_w); @@ -3825,10 +3838,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 10); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "099", - "short circuit size in obviously infinite", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "099", + "short circuit size in obviously infinite", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abc"); @@ -3837,7 +3850,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == POSITIVE_INFINITY); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "100", "http://brauer.maths.qmul.ac.uk/Atlas/misc/24A8/mag/24A8G1-P1.M", @@ -3870,7 +3883,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 322'560); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "101", "http://brauer.maths.qmul.ac.uk/Atlas/spor/M11/mag/M11G1-P1.M", @@ -3913,7 +3926,7 @@ namespace libsemigroups { REQUIRE(normal_forms(tc).get() == word_type({})); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "102", "http://brauer.maths.qmul.ac.uk/Atlas/spor/M12/mag/M12G1-P1.M", @@ -3941,7 +3954,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 95'040); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "103", "http://brauer.maths.qmul.ac.uk/Atlas/spor/M22/mag/M22G1-P1.M", @@ -3968,7 +3981,7 @@ namespace libsemigroups { // Takes about 4 minutes (2021 - MacBook Air M1 - 8GB RAM) // with Felsch (3.5mins or 2.5mins with lowerbound) or HLT (4.5mins) - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "104", "http://brauer.maths.qmul.ac.uk/Atlas/spor/M23/mag/M23G1-P1.M", @@ -4011,7 +4024,7 @@ namespace libsemigroups { } // Takes about 3 minutes (with HLT) - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "105", "http://brauer.maths.qmul.ac.uk/Atlas/clas/S62/mag/S62G1-P1.M", @@ -4054,7 +4067,7 @@ namespace libsemigroups { } // Approx. 32 minutes (2021 - MacBook Air M1 - 8GB RAM) - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "106", "http://brauer.maths.qmul.ac.uk/Atlas/spor/HS/mag/HSG1-P1.M", @@ -4093,7 +4106,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 4'032'000); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "107", "http://brauer.maths.qmul.ac.uk/Atlas/spor/J1/mag/J1G1-P1.M", @@ -4116,7 +4129,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 175'560); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "108", "http://brauer.maths.qmul.ac.uk/Atlas/lin/L34/mag/L34G1-P1.M", @@ -4147,7 +4160,7 @@ namespace libsemigroups { } // Takes about 10 seconds (2021 - MacBook Air M1 - 8GB RAM) - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "109", "http://brauer.maths.qmul.ac.uk/Atlas/clas/S62/mag/S62G1-P1.M x 2", @@ -4173,10 +4186,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 1'451'520); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "013", - "redundant rule x1", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "013", + "redundant rule x1", + "[todd-coxeter][quick]") { auto rg = ReportGuard(false); Presentation p; p.contains_empty_word(true); @@ -4201,10 +4214,10 @@ namespace libsemigroups { REQUIRE(it == p.rules.end()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "120", - "redundant rule x2", - "[todd-coxeter][standard]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "120", + "redundant rule x2", + "[todd-coxeter][standard]") { auto rg = ReportGuard(false); Presentation p; p.alphabet("abc"); @@ -4222,10 +4235,10 @@ namespace libsemigroups { REQUIRE(*(it + 1) == "baa"); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "014", - "hypo plactic id monoid", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "014", + "hypo plactic id monoid", + "[todd-coxeter][extreme]") { std::array const num = {0, 0, 4, 13, 40, 121, 364, 1'093, 3'280, 9'841, 29'524}; // A003462 @@ -4255,10 +4268,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "019", - "Chinese id monoid", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "019", + "Chinese id monoid", + "[todd-coxeter][extreme]") { std::array const num = { 0, 0, 4, 14, 50, 187, 730, 2'949, 12'234, 51'821, 223'190}; // A007317 std::vector> tri @@ -4297,10 +4310,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "030", - "Chinese id monoid x 2", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "030", + "Chinese id monoid x 2", + "[todd-coxeter][extreme]") { auto n = 5; auto p = fpsemigroup::chinese_monoid(n); p.contains_empty_word(true); @@ -4399,10 +4412,10 @@ namespace libsemigroups { == std::vector()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "027", - "plactic (n, 1)-id monoid", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "027", + "plactic (n, 1)-id monoid", + "[todd-coxeter][extreme]") { // auto r = 3, s = 2; // std::array const size = {1, 3, 14, 95, 885, 10'858, // 170'209}; @@ -4559,10 +4572,10 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "036", - "plactic (n, 1)-id monoid x 2", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "036", + "plactic (n, 1)-id monoid x 2", + "[todd-coxeter][extreme]") { using words::pow; using words::operator+; // #include "Plact4-1_3_last.txt" @@ -4601,10 +4614,10 @@ namespace libsemigroups { // } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "038", - "sigma-stylic monoid", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "038", + "sigma-stylic monoid", + "[todd-coxeter][extreme]") { auto p = fpsemigroup::sigma_stylic_monoid({2, 2, 2}); p.contains_empty_word(true); ToddCoxeter tc(twosided, p); @@ -4631,10 +4644,10 @@ namespace libsemigroups { REQUIRE((normal_forms(tc) | to_vector()) == std::vector()); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "044", - "2-sylvester monoid", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "044", + "2-sylvester monoid", + "[todd-coxeter][extreme]") { using words::pow; size_t n = 4; Presentation p; @@ -4676,10 +4689,11 @@ namespace libsemigroups { } // Takes nearly 13 hours to complete - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "045", - "Whyte's 8-generator 4-relation full transf monoid 8", - "[todd-coxeter][fail]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "045", + "Whyte's 8-generator 4-relation full transf monoid 8", + "[todd-coxeter][fail]") { auto rg = ReportGuard(true); Presentation p; p.rules = { @@ -4707,11 +4721,11 @@ namespace libsemigroups { auto q = to_presentation(p); ToString to_string(q.alphabet()); - REQUIRE(knuth_bendix::try_equal_to(q, - to_string(1217_w), - to_string(7121_w), - std::chrono::milliseconds(10)) - == tril::TRUE); + // REQUIRE(knuth_bendix::try_equal_to(q, + // to_string(1217_w), + // to_string(7121_w), + // std::chrono::milliseconds(10)) + // == tril::TRUE); presentation::balance_no_checks(p, 0123456_w, 0123456_w); REQUIRE(p.rules @@ -4788,10 +4802,11 @@ namespace libsemigroups { } } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "066", - "Whyte's 2-generator 4-relation full transf monoid 8", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3( + "ToddCoxeter", + "066", + "Whyte's 2-generator 4-relation full transf monoid 8", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(true); Presentation p; p.rules = {00_w, @@ -4838,7 +4853,7 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 0); } - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "110", "minimal E-disjunctive idempotent pure onesided congruence", @@ -4871,7 +4886,7 @@ namespace libsemigroups { } // Takes about 2 minutes - LIBSEMIGROUPS_TEST_CASE( + LIBSEMIGROUPS_TEST_CASE_V3( "ToddCoxeter", "10X", "https://brauer.maths.qmul.ac.uk/Atlas/exc/TF42/mag/TF42G1-P1.M", @@ -4898,10 +4913,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 17'971'200); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "10Y", - "cyclic groups", - "[todd-coxeter][quick]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "10Y", + "cyclic groups", + "[todd-coxeter][quick]") { Presentation p; p.contains_empty_word(true).alphabet("xyz"); @@ -4913,10 +4928,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 5); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "117", - "Rudvalis group", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "117", + "Rudvalis group", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(true); Presentation p; p.alphabet("abctABCT").contains_empty_word(true); @@ -4950,10 +4965,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 7'238'400); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "118", - "alternating group 8", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "118", + "alternating group 8", + "[todd-coxeter][extreme]") { auto rg = ReportGuard(true); Presentation p; p.alphabet("abcABC").contains_empty_word(true); @@ -4975,10 +4990,10 @@ namespace libsemigroups { REQUIRE(tc.number_of_classes() == 20'160); } - LIBSEMIGROUPS_TEST_CASE("ToddCoxeter", - "119", - "full transf. monoid 6 (maybe)", - "[todd-coxeter][extreme]") { + LIBSEMIGROUPS_TEST_CASE_V3("ToddCoxeter", + "119", + "full transf. monoid 6 (maybe)", + "[todd-coxeter][extreme]") { ReportGuard rg(true); Presentation p; p.contains_empty_word(true);