Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  test-kambites.cpp   Sprache: C

 
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2021 James D. Mitchell + Maria Tsalakou
//
// 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 <http://www.gnu.org/licenses/>.
//

#include <stddef.h>  // for size_t

#include <algorithm>      // for count_if, all_of
#include <iostream>       // for string, char_traits
#include <iterator>       // for distance
#include <memory>         // for allocator, shared_ptr
#include <string>         // for basic_string, operator==, operator!=, operator+
#include <unordered_set>  // for unordered_set
#include <vector>         // for vector

#include "catch.hpp"      // for REQUIRE, REQUIRE_THROWS_AS
#include "test-main.hpp"  // for LIBSEMIGROUPS_TEST_CASE

#include "libsemigroups/constants.hpp"          // for UNDEFINED
#include "libsemigroups/froidure-pin-base.hpp"  // for FroidurePinBase
#include "libsemigroups/iterator.hpp"           // for ConstIteratorStateful
#include "libsemigroups/kambites.hpp"           // for Kambites
#include "libsemigroups/knuth-bendix.hpp"       // for KnuthBendix
#include "libsemigroups/report.hpp"             // for ReportGuard
#include "libsemigroups/siso.hpp"               // for const_sislo_iterator
#include "libsemigroups/string.hpp"             // for random_string etc
#include "libsemigroups/transf.hpp"             // for LeastTransf
#include "libsemigroups/types.hpp"              // for tril etc
#include "libsemigroups/word.hpp"               // for number_of_words

namespace libsemigroups {
  struct LibsemigroupsException;  // Forward decl

  constexpr bool REPORT = false;
  using detail::MultiStringView;
  using detail::random_string;

  namespace {
    // TODO(later) remove this, or put it in test-suffix-tree.cpp
    template <typename T>
    size_t number_of_subwords(T first, T last) {
      std::unordered_set<std::string> mp;

      for (auto it = first; it < last; ++it) {
        {
          auto& w = it->first;
          for (auto suffix = w.cbegin(); suffix < w.cend(); ++suffix) {
            for (auto prefix = suffix + 1; prefix < w.cend(); ++prefix) {
              mp.emplace(suffix, prefix);
            }
          }
        }
        {
          auto& w = it->second;
          for (auto suffix = w.cbegin(); suffix < w.cend(); ++suffix) {
            for (auto prefix = suffix + 1; prefix < w.cend(); ++prefix) {
              mp.emplace(suffix, prefix);
            }
          }
        }
      }
      return mp.size();
    }

    // TODO(later) remove this
    template <typename T>
    size_t sum_lengths(T first, T last) {
      size_t result = 0;
      for (auto it = first; it < last; ++it) {
        result += it->first.size();
        result += it->second.size();
      }
      return result;
    }

    std::string random_power_string(std::string const& s,
                                    std::string const& t,
                                    std::string const& u,
                                    size_t             exp) {
      static std::random_device              rd;
      static std::mt19937                    generator(rd());
      static std::uniform_int_distribution<> distribution(0, 2);
      std::string                            result = "";
      while (exp > 0) {
        switch (distribution(generator)) {
          case 0: {
            result += s;
            break;
          }
          case 1: {
            result += t;
            break;
          }
          case 2: {
            result += u;
          }
          default:
            break;
        }
        exp--;
      }
      return result;
    }

    // std::string swap_a_and_b(std::string const& w) {
    //   std::string result;
    //   for (auto l : w) {
    //     if (l == 'a') {
    //       result += "b";
    //     } else if (l == '#') {
    //       result += '#';
    //     } else {
    //       result += "a";
    //     }
    //   }
    //   return result;
    // }

    auto sample(std::string A,
                size_t      R,
                size_t      min,
                size_t      max,
                size_t      sample_size) {
      if (min < 7) {
        LIBSEMIGROUPS_EXCEPTION("the minimum value of is at least 7");
        // Otherwise we get lhs = rhs in many of the things below and this
        // skews the results.
      } else if (min < max && max - min <= 1) {
        LIBSEMIGROUPS_EXCEPTION(
            "the minimum and maximum values must be at least 2 apart");
      }
      auto     rg              = ReportGuard(false);
      uint64_t total_c4        = 0;
      uint64_t total_confluent = 0;
      for (size_t j = 0; j < sample_size; ++j) {
        fpsemigroup::Kambites<std::string> k;
        k.set_alphabet(A);
        fpsemigroup::KnuthBendix kb1;
        kb1.set_alphabet(A);
        fpsemigroup::KnuthBendix kb2;
        std::reverse(A.begin(), A.end());
        kb2.set_alphabet(A);
        std::reverse(A.begin(), A.end());
        for (size_t r = 0; r < R; ++r) {
          auto        lhs = random_string(A, min, max);
          std::string rhs;
          if (lhs.size() == min) {
            rhs = random_string(A, min + 1, max);
          } else {
            rhs = random_string(A, min, lhs.size());
          }

          k.add_rule(lhs, rhs);
          kb1.add_rule(lhs, rhs);
          kb2.add_rule(lhs, rhs);
        }
        kb1.run_for(std::chrono::milliseconds(1));
        kb2.run_for(std::chrono::milliseconds(1));
        if (k.small_overlap_class() >= 4) {
          total_c4++;
        }
        if (kb1.confluent() || kb2.confluent()) {
          total_confluent++;
        }
      }
      return std::make_tuple(total_c4, total_confluent);
    }

    std::array<std::string, 5> swap_a_b_c(std::string const& w) {
      static std::array<std::string, 5> perms
          = {"bac""acb""cba""bca""cab"};
      std::array<std::string, 5> result;
      size_t                     count = 0;
      for (auto const& p : perms) {
        std::string ww;
        for (auto l : w) {
          if (l == 'a') {
            ww += p[0];
          } else if (l == 'b') {
            ww += p[1];
          } else {
            ww += p[2];
          }
        }
        result[count] = ww;
        count++;
      }
      return result;
    }

  }  // namespace

#ifdef false
  namespace {

    Kambites<> random_example(std::string const& alphabet) {
      static std::random_device       rd;
      static std::mt19937             generator(rd());
      std::uniform_int_distribution<> distribution(1, 25);

      Kambites<> k;
      k.set_alphabet(alphabet);

      std::vector<std::string> pieces;
      for (size_t i = 0; i < 13; ++i) {
        pieces.push_back(random_string(alphabet, distribution(generator)));
      }

      k.add_rule(pieces[0] + pieces[1] + pieces[2] + pieces[3],
                 pieces[2] + pieces[0] + pieces[7] + pieces[4]);
      k.add_rule(pieces[4] + pieces[0] + pieces[5], pieces[6]);
      k.add_rule(pieces[7] + pieces[1] + pieces[8], pieces[9]);
      k.add_rule(pieces[10] + pieces[3] + pieces[11], pieces[12]);

      std::cout << "k.add_rule(\""
                << pieces[0] + pieces[1] + pieces[2] + pieces[3] << "\", \""
                << pieces[2] + pieces[0] + pieces[7] + pieces[4] << "\");\n";
      std::cout << "k.add_rule(\"" << pieces[4] + pieces[0] + pieces[5]
                << "\", \"" << pieces[6] << "\");\n";
      std::cout << "k.add_rule(\"" << pieces[7] + pieces[1] + pieces[8]
                << "\", \"" << pieces[9] << "\");\n";
      std::cout << "k.add_rule(\"" << pieces[10] + pieces[3] + pieces[11]
                << "\", \"" << pieces[12] << "\");\n";
      return k;
    }
  }  // namespace
#endif

  namespace fpsemigroup {

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_4() {
      auto rg = ReportGuard(REPORT);

      Kambites<T> k;
      k.set_alphabet("abcdefg");
      k.add_rule("abcd""aaaeaa");
      k.add_rule("ef""dg");

      REQUIRE(k.equal_to("abcd""aaaeaa"));
      REQUIRE(k.equal_to("ef""dg"));
      REQUIRE(k.equal_to("aaaaaef""aaaaadg"));
      REQUIRE(k.equal_to("efababa""dgababa"));
      k.froidure_pin()->enumerate(100);
      REQUIRE(k.froidure_pin()->current_size() == 8205);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "000",
                            "(fpsemi) MT test 4 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_4<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "001",
                            "(fpsemi) MT test 4 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_4<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_no_name_1() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("aAbBcCe");

      k.add_rule("aaa""e");
      k.add_rule("bbb""e");
      k.add_rule("ccc""e");
      k.add_rule("ABa""BaB");
      k.add_rule("bcB""cBc");
      k.add_rule("caC""aCa");
      k.add_rule("abcABCabcABCabcABC""e");
      k.add_rule("BcabCABcabCABcabCA""e");
      k.add_rule("cbACBacbACBacbACBa""e");

      REQUIRE(k.number_of_pieces(0) == 2);
      REQUIRE(k.number_of_pieces(1) == POSITIVE_INFINITY);

      REQUIRE(k.number_of_pieces(2) == 2);
      REQUIRE(k.number_of_pieces(3) == POSITIVE_INFINITY);

      REQUIRE(k.number_of_pieces(4) == 2);
      REQUIRE(k.number_of_pieces(5) == POSITIVE_INFINITY);

      REQUIRE(k.number_of_pieces(6) == 2);
      REQUIRE(k.number_of_pieces(7) == 2);

      REQUIRE(k.number_of_pieces(8) == 2);
      REQUIRE(k.number_of_pieces(9) == 2);

      REQUIRE(k.number_of_pieces(10) == 2);
      REQUIRE(k.number_of_pieces(11) == 2);

      REQUIRE(k.number_of_pieces(12) == 2);
      REQUIRE(k.number_of_pieces(13) == POSITIVE_INFINITY);

      REQUIRE(k.number_of_pieces(14) == 2);
      REQUIRE(k.number_of_pieces(15) == POSITIVE_INFINITY);

      REQUIRE(k.number_of_pieces(16) == 2);
      REQUIRE(k.number_of_pieces(17) == POSITIVE_INFINITY);

      REQUIRE(k.small_overlap_class() == 2);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "002",
                            "(fpsemi) number_of_pieces (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_no_name_1<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "003",
                            "(fpsemi) number_of_pieces (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_no_name_1<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_no_name_2() {
      auto rg = ReportGuard(REPORT);
      for (size_t i = 4; i < 20; ++i) {
        std::string lhs;
        for (size_t b = 1; b <= i; ++b) {
          lhs += "a" + std::string(b, 'b');
        }
        std::string rhs;
        for (size_t b = i + 1; b <= 2 * i; ++b) {
          rhs += "a" + std::string(b, 'b');
        }

        Kambites<T> k;

        k.set_alphabet("ab");
        k.add_rule(lhs, rhs);

        REQUIRE(k.number_of_pieces(0) == i);
        REQUIRE(k.number_of_pieces(1) == i + 1);

        REQUIRE(k.small_overlap_class() == i);
      }
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "004",
                            "(fpsemi) small_overlap_class (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_no_name_2<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "005",
                            "(fpsemi) small_overlap_class (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_no_name_2<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_random() {
      auto rg = ReportGuard(REPORT);
      {
        Kambites<T> k;
        k.set_alphabet("abcdefghi");
        k.add_rule("eiehiegiggfaigcdfdfdgiidcebacgfaf",
                   "cgfaeiehiegiggfaigcdfdfdgigcccbddchbbhgaaedfiiahhehihcba");
        k.add_rule("hihcbaeiehiegiggfaigcdfdfdgiefhbidhbdgb""chhfgafiiddg");
        k.add_rule("gcccbddchbbhgaaedfiiahheidcebacbdefegcehgffedacddiaiih",
                   "eddfcfhbedecacheahcdeeeda");
        k.add_rule("dfbiccfeagaiffcfifg""dceibahghaedhefh");

        REQUIRE(k.small_overlap_class() == 4);
        REQUIRE(number_of_subwords(k.cbegin_rules(), k.cend_rules()) == 3762);
        size_t n = sum_lengths(k.cbegin_rules(), k.cend_rules());
        REQUIRE(n == 254);
        REQUIRE(n * n == 64516);
      }
      {
        Kambites<T> k;
        k.set_alphabet("abcdefghi");
        k.add_rule("feffgccdgcfbeagiifheabecdfbgebfcibeifibccahaafabeihfgfieade"
                   "bciheddeigbaf",
                   "ifibccahaafabeihfgfiefeffgccdgcfbeagiifheabecfeibghddfgbaia"
                   "acghhdhggagaide");
        k.add_rule("ghhdhggagaidefeffgccdgcfbeagiifheabeccbeiddgdcbcf",
                   "ahccccffdeb");
        k.add_rule("feibghddfgbaiaacdfbgebfcibeieaacdbdb""gahdfgbghhhbcci");
        k.add_rule("dgibafaahiabfgeiiibadebciheddeigbaficfbfdbfbbiddgdcifbe",
                   "iahcfgdbggaciih");
        REQUIRE(k.small_overlap_class() == 4);
        REQUIRE(number_of_subwords(k.cbegin_rules(), k.cend_rules()) == 7197);
        size_t n = sum_lengths(k.cbegin_rules(), k.cend_rules());
        REQUIRE(n == 327);
        REQUIRE(n * n == 106929);
      }
      {
        Kambites<T> k;
        k.set_alphabet("abcdefghi");
        k.add_rule("adichhbhibfchbfbbibaidfibifgagcgdedfeeibhggdbchfdaefbefcbaa"
                   "hcbhbidgaahbahhahhb",
                   "edfeeibhggdbchfdaefbeadichhbhibfchbfbbibaiihebabeabahcgdbic"
                   "bgiciffhfggbfadf");
        k.add_rule("bgiciffhfggbfadfadichhbhibfchbfbbibaaggfdcfcebehhbdegiaeaf",
                   "hebceeicbhidcgahhcfbb");
        k.add_rule("iihebabeabahcgdbicidfibifgagcgdedehed",
                   "ecbcgaieieicdcdfdbgagdbf");
        k.add_rule("iagaadbfcbaahcbhbidgaahbahhahhbd""ddddh");
        REQUIRE(k.small_overlap_class() == 3);
        REQUIRE(number_of_subwords(k.cbegin_rules(), k.cend_rules()) == 7408);
        size_t n = sum_lengths(k.cbegin_rules(), k.cend_rules());
        REQUIRE(n == 330);
        REQUIRE(n * n == 108900);
      }
      {
        Kambites<T> k;
        k.set_alphabet("abcdefghi");
        k.add_rule("ibddgdgddiabcahbidbedffeddciiabahbbiacbfehdfccacbhgafbgcdg",
                   "iabahibddgdgddbdfacbafhcgfhdheieihd");
        k.add_rule("hdheieihdibddgdgddebhaeaicciidebegg""giaeehdeeec");
        k.add_rule("bdfacbafhcgfiabcahbidbedffeddcifdfcdcdadhhcbcbebhei",
                   "icaebehdff");
        k.add_rule("aggiiacdbbiacbfehdfccacbhgafbgcdghiahfccdchaiagaha",
                   "hhafbagbhghhihg");

        REQUIRE(k.small_overlap_class() == 4);
        REQUIRE(number_of_subwords(k.cbegin_rules(), k.cend_rules()) == 4560);
        size_t n = sum_lengths(k.cbegin_rules(), k.cend_rules());
        REQUIRE(n == 265);
        REQUIRE(n * n == 70225);
      }
      {
        Kambites<T> k;
        k.set_alphabet("abcdefghi");
        k.add_rule(
            "fibehffegdeggaddgfdaeaiacbhbgbbccceaibfcabbiedhecggbbdgihddd",
            "ceafibehffegdeggafidbaefcebegahcbhciheceaehaaehih");
        k.add_rule("haaehihfibehffegdeggaecbedccaeabifeafi",
                   "bfcccibgefiidgaih");
        k.add_rule("fidbaefcebegahcbhciheceaeddgfdaeaiacbhbgbbcccgiahbibehgbgab"
                   "efdieiggc",
                   "abigdadaecdfdeeciggbdfdf");
        k.add_rule("eeaaiicigieiabibfcabbiedhecggbbdgihdddifadgbgidbfeg",
                   "daheebdgdiaeceeiicddg");
        REQUIRE(k.small_overlap_class() == 4);
        REQUIRE(number_of_subwords(k.cbegin_rules(), k.cend_rules()) == 6398);
        size_t n = sum_lengths(k.cbegin_rules(), k.cend_rules());
        REQUIRE(n == 328);
        REQUIRE(n * n == 107584);
      }
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "006",
                            "(fpsemi) random (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_random<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "007",
                            "(fpsemi) random (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_random<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_knuth_bendix_055() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcdefg");

      k.add_rule("abcd""ce");
      k.add_rule("df""dg");

      REQUIRE(k.small_overlap_class() == POSITIVE_INFINITY);
      REQUIRE(k.is_obviously_infinite());

      REQUIRE(k.equal_to("dfabcdf""dfabcdg"));
      REQUIRE(k.normal_form("dfabcdg") == "dfabcdf");

      REQUIRE(k.equal_to("abcdf""ceg"));
      REQUIRE(k.equal_to("abcdf""cef"));
      REQUIRE(k.equal_to("dfabcdf""dfabcdg"));
      REQUIRE(k.equal_to("abcdf""ceg"));
      REQUIRE(k.equal_to("abcdf""cef"));
      REQUIRE(k.normal_form("abcdfceg") == "abcdfabcdf");
      REQUIRE(k.equal_to("abcdfceg""abcdfabcdf"));

      REQUIRE(k.size() == POSITIVE_INFINITY);
      REQUIRE(number_of_words(k.alphabet().size(), 0, 6) == 19608);
      REQUIRE(k.number_of_normal_forms(0, 6) == 17921);

      REQUIRE(number_of_subwords(k.cbegin_rules(), k.cend_rules()) == 7);
      // REQUIRE(std::vector<std::string>(k.cbegin_normal_forms(0, 2),
      //                                 k.cend_normal_forms())
      //        == std::vector<std::string>({"a", "b", "c", "d", "e", "f",
      //        "g"}));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "008",
                            "(fpsemi) KnuthBendix 055 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_knuth_bendix_055<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "009",
        "(fpsemi) KnuthBendix 055 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_knuth_bendix_055<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_gap_smalloverlap_85() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("cab");

      k.add_rule("aabc""acba");
      REQUIRE(!k.equal_to("a""b"));
      REQUIRE(k.equal_to("aabcabc""aabccba"));

      REQUIRE(k.size() == POSITIVE_INFINITY);
      REQUIRE(number_of_words(3, 4, 16) == 21523320);
      REQUIRE(std::distance(cbegin_sislo("cab""aabc""aaabc"),
                            cend_sislo("cab""aabc""aaabc"))
              == 162);

      REQUIRE(std::count_if(
                  cbegin_sislo("cab""cccc""ccccc"),
                  cend_sislo("cab""cccc""ccccc"),
                  [&k](std::string const& w) { return k.equal_to(w, "acba"); })
              == 2);
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "010",
        "(fpsemi) smalloverlap/gap/test.gi:85 (std::string)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_gap_smalloverlap_85<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "011",
        "(fpsemi) smalloverlap/gap/test.gi:85 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_gap_smalloverlap_85<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "012",
                            "(fpsemi) free semigroup",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      Kambites<std::string> k;
      k.set_alphabet("cab");
      REQUIRE(k.small_overlap_class() == POSITIVE_INFINITY);

      Kambites<detail::MultiStringView> kk;
      kk.set_alphabet("cab");
      REQUIRE(kk.small_overlap_class() == POSITIVE_INFINITY);
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_gap_smalloverlap_49() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcdefgh");

      k.add_rule("abcd""ce");
      k.add_rule("df""hd");

      REQUIRE(k.is_obviously_infinite());

      REQUIRE(k.equal_to("abchd""abcdf"));
      REQUIRE(!k.equal_to("abchf""abcdf"));
      REQUIRE(k.equal_to("abchd""abchd"));
      REQUIRE(k.equal_to("abchdf""abchhd"));
      // Test cases (4) and (5)
      REQUIRE(k.equal_to("abchd""cef"));
      REQUIRE(k.equal_to("cef""abchd"));

      REQUIRE(k.size() == POSITIVE_INFINITY);
      REQUIRE(k.number_of_normal_forms(0, 6) == 35199);
      REQUIRE(k.normal_form("hdfabce") == "dffababcd");
      REQUIRE(k.equal_to("hdfabce""dffababcd"));
      // TODO(later) include when we have cbegin_normal_forms,
      // cend_normal_forms
      //  REQUIRE(std::vector<std::string>(k.cbegin_normal_forms(0, 2),
      //                                   k.cend_normal_forms())
      //          == std::vector<std::string>(
      //              {"a", "b", "c", "d", "e", "f", "g", "h"}));*/
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "013",
        "(fpsemi) smalloverlap/gap/test.gi:49 (std::string)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_gap_smalloverlap_49<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "014",
        "(fpsemi) smalloverlap/gap/test.gi:49 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_gap_smalloverlap_49<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_gap_smalloverlap_63() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcdefgh");

      k.add_rule("afh""bgh");
      k.add_rule("hc""d");

      REQUIRE(k.is_obviously_infinite());

      // Test case (6)
      REQUIRE(k.equal_to("afd""bgd"));
      REQUIRE(k.equal_to("bghcafhbgd""afdafhafd"));
      REQUIRE(k.normal_form("bghcafhbgd") == "afdafhafd");
      REQUIRE(k.number_of_normal_forms(0, 6) == 34819);

      REQUIRE(k.size() == POSITIVE_INFINITY);
    }
    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "015",
        "(fpsemi) smalloverlap/gap/test.gi:63 (std::string)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_gap_smalloverlap_63<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "016",
        "(fpsemi) smalloverlap/gap/test.gi:63 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_gap_smalloverlap_63<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_gap_smalloverlap_70() {
      auto rg = ReportGuard(REPORT);
      // The following permits a more complex test of case (6), which also
      // involves using the case (2) code to change the prefix being looked
      // for:
      Kambites<T> k;
      k.set_alphabet("abcdefghij");

      k.add_rule("afh""bgh");
      k.add_rule("hc""de");
      k.add_rule("ei""j");

      REQUIRE(k.number_of_normal_forms(0, 6) == 102255);
      REQUIRE(k.is_obviously_infinite());

      REQUIRE(k.equal_to("afdj""bgdj"));
      REQUIRE(!k.equal_to("xxxxxxxxxxxxxxxxxxxxxxx""b"));
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "017",
        "(fpsemi) smalloverlap/gap/test.gi:70 (std::string)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_gap_smalloverlap_70<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "018",
        "(fpsemi) smalloverlap/gap/test.gi:70 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_gap_smalloverlap_70<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_1_million_equals() {
      auto rg = ReportGuard(REPORT);
      // A slightly more complicated presentation for testing case (6), in
      // which the max piece suffixes of the first two relation words no
      // longer agree (since fh and gh are now pieces).
      Kambites<T> k;
      k.set_alphabet("abcdefghijkl");

      k.add_rule("afh""bgh");
      k.add_rule("hc""de");
      k.add_rule("ei""j");
      k.add_rule("fhk""ghl");

      REQUIRE(k.is_obviously_infinite());

      REQUIRE(k.equal_to("afdj""bgdj"));
      REQUIRE(k.equal_to("afdj""afdj"));
      REQUIRE(k.normal_form("bfhk") == "afhl");
      REQUIRE(k.equal_to("bfhk""afhl"));

      REQUIRE(k.size() == POSITIVE_INFINITY);

      size_t N = std::distance(cbegin_sislo("abcdefghijkl""a""bgdk"),
                               cend_sislo("abcdefghijkl""a""bgdk"));
      REQUIRE(N == 4522);
      size_t M = 0;
      for (auto it1 = cbegin_sislo("abcdefghijkl""a""bgdk");
           it1 != cend_sislo("abcdefghijkl""a""bgdk");
           ++it1) {
        for (auto it2 = cbegin_sislo("abcdefghijkl""a""bgdk"); it2 != it1;
             ++it2) {
          M++;
          if (k.equal_to(*it1, *it2)) {
            N--;
            break;
          }
        }
      }
      REQUIRE(M == 10052729);
      REQUIRE(N == 4392);
      REQUIRE(k.number_of_normal_forms(0, 6) == 255932);

      // TODO(later) include when we have cbegin_normal_forms,
      // cend_normal_forms
      // REQUIRE(
      //     std::vector<std::string>(k.cbegin_normal_forms(0, 2),
      //                              k.cend_normal_forms())
      //     == std::vector<std::string>(
      //         {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
      // "l"}));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "019",
                            "(fpsemi) std::string smalloverlap/gap/test.gi:77 "
                            "(infinite) (KnuthBendix 059)",
                            "[standard][kambites][fpsemigroup][fpsemi]") {
      test_case_1_million_equals<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "020",
        "(fpsemi) MultiStringView smalloverlap/gap/test.gi:77 "
        "(infinite) (KnuthBendix 059)",
        "[standard][kambites][fpsemigroup][fpsemi]") {
      test_case_1_million_equals<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_code_cov() {
      auto rg = ReportGuard(REPORT);
      // A slightly more complicated presentation for testing case (6), in
      // which the max piece suffixes of the first two relation words no
      // longer agree (since fh and gh are now pieces).
      Kambites<T> k;
      k.set_alphabet("abcde");
      k.add_rule("cadeca""baedba");
      REQUIRE(!k.equal_to("cadece""baedce"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "021",
                            "(fpsemi) code coverage (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_code_cov<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "022",
                            "(fpsemi) code coverage (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_code_cov<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_ex_3_13_14() {
      auto rg = ReportGuard(REPORT);
      // Example 3.13 + 3.14
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("abbba""cdc");
      std::string p = "c";
      REQUIRE(k.normal_form("cdcdcabbbabbbabbcd") == "abbbadcabbbabbbabbcd");
      REQUIRE(k.equal_to(k.normal_form("cdcdcabbbabbbabbcd"),
                         "cdcdcabbbabbbabbcd"));
      REQUIRE(k.equal_to("abbbadcbbba""cdabbbcdc"));
      REQUIRE(k.equal_to(k.normal_form("cdabbbcdc"), "cdabbbcdc"));
      REQUIRE(k.normal_form("cdabbbcdc") == "abbbadcbbba");
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "023",
                            "(fpsemi) prefix (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_ex_3_13_14<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "024",
                            "(fpsemi) prefix (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_ex_3_13_14<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_ex_3_15() {
      auto rg = ReportGuard(REPORT);
      // Example 3.15
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("aabc""acba");
      std::string original = "cbacbaabcaabcacbacba";
      std::string expected = "cbaabcabcaabcaabcabc";

      REQUIRE(k.equal_to("cbaabcabcaabcaabccba", original));
      REQUIRE(k.equal_to(original, expected));
      REQUIRE(k.equal_to(expected, original));
      REQUIRE(k.equal_to("cbaabcabcaabcaabccba", expected));

      REQUIRE(k.equal_to(original, "cbaabcabcaabcaabccba"));

      REQUIRE(k.equal_to(expected, "cbaabcabcaabcaabccba"));
      REQUIRE(k.equal_to(k.normal_form(original), original));
      REQUIRE(k.normal_form(original) == expected);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "025",
                            "(fpsemi) normal_form (Example 3.15) (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_ex_3_15<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "026",
        "(fpsemi) normal_form (Example 3.15) (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_ex_3_15<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_ex_3_16() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("abcd""acca");
      std::string original = "bbcabcdaccaccabcddd";
      std::string expected = "bbcabcdabcdbcdbcddd";

      REQUIRE(k.equal_to(original, expected));
      REQUIRE(k.equal_to(expected, original));

      REQUIRE(k.normal_form(original) == expected);
      REQUIRE(k.equal_to(k.normal_form(original), original));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "027",
                            "(fpsemi) normal_form (Example 3.16) (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_ex_3_16<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "028",
        "(fpsemi) normal_form (Example 3.16) (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_ex_3_16<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_ex_3_16_again() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("abcd""acca");

      REQUIRE(std::all_of(
          cbegin_sislo("abcd""a""aaaa"),
          cend_sislo("abcd""a""aaaa"),
          [&k](std::string const& w) { return k.normal_form(w) == w; }));
      REQUIRE(std::count_if(
                  cbegin_sislo("abcd""aaaa""aaaaa"),
                  cend_sislo("abcd""aaaa""aaaaa"),
                  [&k](std::string const& w) { return k.normal_form(w) != w; })
              == 1);
      REQUIRE(std::count_if(
                  cbegin_sislo("abcd""aaaaa""aaaaaa"),
                  cend_sislo("abcd""aaaaa""aaaaaa"),
                  [&k](std::string const& w) { return k.normal_form(w) != w; })
              == 8);
      REQUIRE(std::count_if(
                  cbegin_sislo("abcd""aaaaaa""aaaaaaa"),
                  cend_sislo("abcd""aaaaaa""aaaaaaa"),
                  [&k](std::string const& w) { return k.normal_form(w) != w; })
              == 48);
      {
        std::string w = k.normal_form("accaccabd");

        REQUIRE(w == "abcdbcdbd");

        REQUIRE(std::count_if(cbegin_sislo("abcd""aaaaaaaaa", w),
                              cend_sislo("abcd""aaaaaaaaa", w),
                              [&k, &w](std::string const& u) {
                                return !k.equal_to(u, w);
                              })
                == std::distance(cbegin_sislo("abcd""aaaaaaaaa", w),
                                 cend_sislo("abcd""aaaaaaaaa", w)));
      }
      {
        std::string w = k.normal_form("accbaccad");
        REQUIRE(w == "accbabcdd");

        REQUIRE(std::count_if(cbegin_sislo("abcd""aaaaaaaaa", w),
                              cend_sislo("abcd""aaaaaaaaa", w),
                              [&k, &w](std::string const& u) {
                                return !k.equal_to(u, w);
                              })
                == std::distance(cbegin_sislo("abcd""aaaaaaaaa", w),
                                 cend_sislo("abcd""aaaaaaaaa", w)));
      }
      {
        std::string w = k.normal_form("abcdbcacca");
        REQUIRE(w == "abcdbcabcd");
        REQUIRE(k.equal_to(w, "abcdbcacca"));

        REQUIRE(
            std::count_if(
                cbegin_sislo("abcd", std::string(w.size(), 'a'), w),
                cend_sislo("abcd", std::string(w.size(), 'a'), w),
                [&k, &w](std::string const& u) { return !k.equal_to(u, w); })
            == std::distance(
                cbegin_sislo("abcd", std::string(w.size(), 'a'), w),
                cend_sislo("abcd", std::string(w.size(), 'a'), w)));
      }
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "029",
        "(fpsemi) normal_form (Example 3.16) more exhaustive (std::string)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_ex_3_16_again<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "030",
        "(fpsemi) normal_form (Example 3.16) more exhaustive (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_ex_3_16_again<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_small() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("ab");
      REQUIRE(k.is_obviously_infinite());
      REQUIRE(k.size() == POSITIVE_INFINITY);
      k.add_rule("aaa""a");
      k.add_rule("a""bb");
      REQUIRE(k.small_overlap_class() == 1);
      REQUIRE_THROWS_AS(k.size(), LibsemigroupsException);
      REQUIRE_THROWS_AS(k.equal_to("a""aaa"), LibsemigroupsException);
      REQUIRE(!k.finished());
      k.run();
      REQUIRE(!k.finished());
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "031",
                            "(fpsemi) small presentation (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_small<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "032",
                            "(fpsemi) small presentation (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_small<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_non_smalloverlap() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcdefg");
      k.add_rule("abcd""aaaeaa");
      k.add_rule("ef""dg");
      k.add_rule("a""b");
      REQUIRE(k.small_overlap_class() == 1);
      REQUIRE_THROWS_AS(k.size(), LibsemigroupsException);
      REQUIRE_THROWS_AS(k.equal_to("a""aaa"), LibsemigroupsException);
      REQUIRE(!k.finished());
      k.run();
      REQUIRE(!k.finished());
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "033",
                            "(fpsemi) non-smalloverlap (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_non_smalloverlap<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "034",
                            "(fpsemi) non-smalloverlap (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_non_smalloverlap<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_3() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("abcd""accca");
      REQUIRE(k.number_of_pieces(0) == POSITIVE_INFINITY);
      REQUIRE(k.number_of_pieces(1) == 4);

      REQUIRE(k.small_overlap_class() == 4);
      REQUIRE(k.normal_form("bbcabcdaccaccabcddd") == "bbcabcdaccaccabcddd");
      REQUIRE(k.equal_to("bbcabcdaccaccabcddd""bbcabcdaccaccabcddd"));
      k.run();
      REQUIRE(k.started());
      REQUIRE(k.finished());

      Kambites<T> l(k);
      REQUIRE(l.started());
      REQUIRE(l.finished());

      REQUIRE(l.number_of_pieces(0) == POSITIVE_INFINITY);
      REQUIRE(l.number_of_pieces(1) == 4);

      REQUIRE(l.small_overlap_class() == 4);
      REQUIRE(l.normal_form("bbcabcdaccaccabcddd") == "bbcabcdaccaccabcddd");
      REQUIRE(l.equal_to("bbcabcdaccaccabcddd""bbcabcdaccaccabcddd"));
      REQUIRE(l.number_of_normal_forms(0, 0) == 0);
      REQUIRE(l.number_of_normal_forms(6, 6) == 0);
      REQUIRE(l.number_of_normal_forms(10, 1) == 0);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "035",
                            "(fpsemi) MT test 3 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_3<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "036",
                            "(fpsemi) MT test 3 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_3<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_5() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abc");
      k.add_rule("ac""cbbbbc");
      REQUIRE(k.small_overlap_class() == 4);

      REQUIRE(k.normal_form("acbbbbc") == "aac");
      REQUIRE(k.equal_to("acbbbbc""aac"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "037",
                            "(fpsemi) MT test 5 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_5<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "038",
                            "(fpsemi) MT test 5 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_5<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_6() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abc");
      k.add_rule("ccab""cbac");
      REQUIRE(k.small_overlap_class() == 4);

      REQUIRE(k.normal_form("bacbaccabccabcbacbac") == "bacbacbaccbaccbacbac");
      REQUIRE(k.equal_to("bacbaccabccabcbacbac""bacbacbaccbaccbacbac"));
      REQUIRE(k.normal_form("ccabcbaccab") == "cbaccbacbac");
      REQUIRE(k.equal_to("ccabcbaccab""cbaccbacbac"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "039",
                            "(fpsemi) MT test 6 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_6<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "040",
                            "(fpsemi) MT test 6 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_6<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_10() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcdefghij");
      k.add_rule("afh""bgh");
      k.add_rule("hc""de");
      k.add_rule("ei""j");
      REQUIRE(k.small_overlap_class() == POSITIVE_INFINITY);

      REQUIRE(k.normal_form("bgdj") == "afdei");
      REQUIRE(k.equal_to("bgdj""afdei"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "041",
                            "(fpsemi) MT test 10 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_6<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "042",
                            "(fpsemi) MT test 10 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_6<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_13() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("abcd""dcba");
      REQUIRE(k.small_overlap_class() == 4);

      REQUIRE(k.normal_form("dcbdcba") == "abcdbcd");
      REQUIRE(k.equal_to("dcbdcba""abcdbcd"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "043",
                            "(fpsemi) MT test 13 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_13<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "044",
                            "(fpsemi) MT test 13 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_13<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////
    template <typename T>
    void test_case_mt_14() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("abca""dcbd");
      REQUIRE(k.small_overlap_class() == 4);

      REQUIRE(k.normal_form("dcbabca") == "abcacbd");
      REQUIRE(k.equal_to("dcbabca""abcacbd"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "045",
                            "(fpsemi) MT test 14 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_14<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "046",
                            "(fpsemi) MT test 14 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_14<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_15() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("abcd""dcba");
      k.add_rule("adda""dbbd");
      REQUIRE(k.small_overlap_class() == 4);

      REQUIRE(k.normal_form("dbbabcd") == "addacba");
      REQUIRE(k.equal_to("dbbabcd""addacba"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "047",
                            "(fpsemi) MT test 15 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_15<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "048",
                            "(fpsemi) MT test 15 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_15<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_16() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcdefg");
      k.add_rule("abcd""acca");
      k.add_rule("gf""ge");
      REQUIRE(k.small_overlap_class() == 4);

      REQUIRE(k.normal_form("accabcdgf") == "abcdbcdge");
      REQUIRE(k.equal_to("accabcdgf""abcdbcdge"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "049",
                            "(fpsemi) MT test 16 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_16<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "050",
                            "(fpsemi) MT test 16 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_16<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_mt_17() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("ababbabbbabbbb""abbbbbabbbbbbabbbbbbbabbbbbbbb");
      k.add_rule("cdcddcdddcdddd""cdddddcddddddcdddddddcdddddddd");
      REQUIRE(k.small_overlap_class() == 4);

      REQUIRE(k.normal_form("abbbacdddddcddddddcdddddddcdddddddd")
              == "abbbacdcddcdddcdddd");
      REQUIRE(k.equal_to("abbbacdddddcddddddcdddddddcdddddddd",
                         "abbbacdcddcdddcdddd"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "051",
                            "(fpsemi) MT test 17 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_17<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "052",
                            "(fpsemi) MT test 17 (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_mt_17<MultiStringView>();
    }

    ///////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_weak_1() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("acba""aabc");
      k.add_rule("acba""dbbbd");

      REQUIRE(k.small_overlap_class() == 4);
      REQUIRE(k.equal_to("aaabc""adbbbd"));
      REQUIRE(k.equal_to("adbbbd""aaabc"));
      REQUIRE(number_of_words(4, 4, 6) == 1280);

      REQUIRE(std::count_if(
                  cbegin_sislo("abcd""aaaa""aaaaaa"),
                  cend_sislo("abcd""aaaa""aaaaaa"),
                  [&k](std::string const& w) { return k.equal_to("acba", w); })
              == 3);

      REQUIRE(k.equal_to("aaabcadbbbd""adbbbdadbbbd"));
      REQUIRE(k.equal_to("aaabcaaabc""adbbbdadbbbd"));
      REQUIRE(k.equal_to("acba""dbbbd"));
      REQUIRE(k.equal_to("acbabbbd""aabcbbbd"));
      REQUIRE(k.equal_to("aabcbbbd""acbabbbd"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "053",
                            "(fpsemi) weak C(4) not strong x 1 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_1<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "054",
        "(fpsemi) weak C(4) not strong x 1 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_1<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_weak_2() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("acba""aabc");
      k.add_rule("acba""adbd");
      REQUIRE(k.equal_to("acbacba""aabcabc"));
      REQUIRE(k.normal_form("acbacba") == "aabcabc");
      REQUIRE(k.equal_to(k.normal_form("acbacba"), "aabcabc"));
      REQUIRE(k.equal_to("aabcabc", k.normal_form("acbacba")));

      REQUIRE(std::count_if(
                  cbegin_sislo("abcd""aaaa""aaaaaa"),
                  cend_sislo("abcd""aaaa""aaaaaa"),
                  [&k](std::string const& w) { return k.equal_to("acba", w); })
              == 3);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "055",
                            "(fpsemi) weak C(4) not strong x 2 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_2<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "056",
        "(fpsemi) weak C(4) not strong x 2 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_2<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_weak_3() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcde");
      k.add_rule("bceac""aeebbc");
      k.add_rule("aeebbc""dabcd");
      REQUIRE(k.normal_form("bceacdabcd") == "aeebbcaeebbc");
      REQUIRE(k.equal_to(k.normal_form("bceacdabcd"), "aeebbcaeebbc"));
      REQUIRE(k.equal_to("aeebbcaeebbc", k.normal_form("bceacdabcd")));

      REQUIRE(std::count_if(
                  cbegin_sislo("abcd""aaaa""aaaaaa"),
                  cend_sislo("abcd""aaaa""aaaaaa"),
                  [&k](std::string const& w) { return k.equal_to("acba", w); })
              == 1);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "057",
                            "(fpsemi) weak C(4) not strong x 3 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_3<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "058",
        "(fpsemi) weak C(4) not strong x 3 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_3<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_weak_4() {
      auto        rg = ReportGuard(REPORT);
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("acba""aabc");
      k.add_rule("acba""dbbd");
      REQUIRE(k.normal_form("bbacbcaaabcbbd") == "bbacbcaaabcbbd");
      REQUIRE(k.equal_to(k.normal_form("bbacbcaaabcbbd"), "bbacbcaaabcbbd"));
      REQUIRE(k.equal_to("bbacbcaaabcbbd", k.normal_form("bbacbcaaabcbbd")));
      REQUIRE(k.normal_form("acbacba") == "aabcabc");
      REQUIRE(k.equal_to(k.normal_form("acbacba"), "aabcabc"));
      REQUIRE(k.equal_to("aabcabc", k.normal_form("acbacba")));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "059",
                            "(fpsemi) weak C(4) not strong x 4 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_4<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "060",
        "(fpsemi) weak C(4) not strong x 4 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_4<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_weak_5() {
      Kambites<T> k;
      k.set_alphabet("abcde");
      k.add_rule("abcd""aaeaaa");
      REQUIRE(number_of_subwords(k.cbegin_rules(), k.cend_rules()) == 16);
      size_t n = sum_lengths(k.cbegin_rules(), k.cend_rules());
      REQUIRE(n == 10);
      REQUIRE(n * n == 100);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "061",
                            "(fpsemi) weak C(4) not strong x 5 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_5<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "062",
        "(fpsemi) weak C(4) not strong x 5 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_5<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_weak_6() {
      Kambites<T> k;
      k.set_alphabet("abcd");
      k.add_rule("acba""aabc");
      k.add_rule("acba""adbd");
      REQUIRE(k.normal_form("acbacba") == "aabcabc");
      REQUIRE(k.equal_to(k.normal_form("acbacba"), "aabcabc"));
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "063",
                            "(fpsemi) weak C(4) not strong x 6 (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_6<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "064",
        "(fpsemi) weak C(4) not strong x 6 (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_weak_6<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_konovalov() {
      Kambites<T> k;
      k.set_alphabet("abAB");
      k.add_rule("Abba""BB");
      k.add_rule("Baab""AA");
      REQUIRE(k.small_overlap_class() == 2);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "065",
                            "(fpsemi) Konovalov example (std::string)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_konovalov<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "066",
                            "(fpsemi) Konovalov example (MultiStringView)",
                            "[quick][kambites][fpsemigroup][fpsemi]") {
      test_case_konovalov<MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////

    template <typename T>
    void test_case_long_words() {
      Kambites<T> k;
      k.set_alphabet("abcde");
      k.add_rule("bceac""aeebbc");
      k.add_rule("aeebbc""dabcd");
      REQUIRE(k.small_overlap_class() == 4);

      std::string w1  = "bceac";
      std::string w2  = "dabcd";
      std::string w3  = "aeebbc";
      auto        lhs = random_power_string(w1, w2, w3, 4000);
      auto        rhs = random_power_string(w1, w2, w3, 4000);
      for (size_t i = 0; i < 10; ++i) {
        REQUIRE(k.equal_to(lhs, rhs));
      }
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "067",
        "(fpsemi) long words (std::string)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_long_words<std::string>();
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "068",
        "(fpsemi) long words (MultiStringView)",
        "[quick][kambites][fpsemigroup][fpsemi][no-valgrind]") {
      test_case_long_words<detail::MultiStringView>();
    }

    ////////////////////////////////////////////////////////////////////////
    // Some tests for exploration of the space of all 2-generator 1-relation
    // semigroups
    ////////////////////////////////////////////////////////////////////////

    // TODO(v3) reuse the same Kambites in-place rather than this
    template <typename T>
    auto count_2_gen_1_rel(size_t min, size_t max) {
      Sislo x;
      x.alphabet("ab");
      x.first(min);
      x.last(max);

      auto last = x.cbegin();
      std::advance(last, std::distance(x.cbegin(), x.cend()) - 1);

      uint64_t total_c4 = 0;
      uint64_t total    = 0;

      for (auto it1 = x.cbegin(); it1 != last; ++it1) {
        for (auto it2 = it1 + 1; it2 != x.cend(); ++it2) {
          total++;
          Kambites<std::string> k;
          k.set_alphabet("ab");
          k.add_rule(*it1, *it2);
          if (k.small_overlap_class() >= 4) {
            total_c4++;
          }
        }
      }
      return std::make_pair(total_c4, total);
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "069",
        "(fpsemi) almost all 2-generated 1-relation monoids are C(4)",
        "[extreme][kambites][fpsemigroup][fpsemi]") {
      auto x = count_2_gen_1_rel<std::string>(1, 7);
      REQUIRE(x.first == 1);
      REQUIRE(x.second == 7875);
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "070",
        "(fpsemi) almost all 2-generated 1-relation monoids are C(4)",
        "[extreme][kambites][fpsemigroup][fpsemi]") {
      auto x = count_2_gen_1_rel<std::string>(1, 11);
      REQUIRE(x.first == 18171);
      REQUIRE(x.second == 2092035);
    }

    // Takes approx. 31s
    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "071",
        "(fpsemi) almost all 2-generated 1-relation monoids are C(4)",
        "[extreme][kambites][fpsemigroup][fpsemi]") {
      auto x = count_2_gen_1_rel<std::string>(1, 12);
      REQUIRE(x.first == 235'629);
      REQUIRE(x.second == 8'378'371);
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "072",
        "(fpsemi) almost all 2-generated 1-relation monoids are C(4)",
        "[fail][kambites][fpsemigroup][fpsemi]") {
      auto x = count_2_gen_1_rel<std::string>(1, 13);
      REQUIRE(x.first == 0);
      REQUIRE(x.second == 0);
    }

    LIBSEMIGROUPS_TEST_CASE(
        "Kambites",
        "073",
        "(fpsemi) almost all 2-generated 1-relation monoids are C(4)",
        "[extreme][kambites][fpsemigroup][fpsemi]") {
      std::cout.precision(10);
      size_t const sample_size = 1000;
      std::cout << "Sample size = " << sample_size << std::endl;
      for (size_t i = 8; i < 100; ++i) {
        size_t const min = 7;
        size_t const max = i + 1;
        auto         x   = sample("ab", 1, min, max, sample_size);
        std::cout << "Estimate of C(4) / non-C(4) (length " << min << " to "
                  << max << ") = " << std::fixed
                  << double(std::get<0>(x)) / sample_size << std::endl;
        std::cout << "Estimate of confluent / non-confluent (length " << min
                  << " to " << max << ") = " << std::fixed
                  << double(std::get<1>(x)) / sample_size << std::endl
                  << std::endl;
      }
    }

    ////////////////////////////////////////////////////////////////////////
    // Some tests for exploration of the space of all 3-generator 1-relation
    // semigroups
    ////////////////////////////////////////////////////////////////////////

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "074",
                            "(fpsemi) 3-generated 1-relation C(4)-semigroups",
                            "[extreme][kambites][fpsemigroup][fpsemi]") {
      auto   first = cbegin_sislo("abc""a", std::string(8, 'a'));
      auto   last  = cbegin_sislo("abc""a", std::string(8, 'a'));
      size_t N
          = std::distance(first, cend_sislo("abc""a", std::string(8, 'a')));
      REQUIRE(N == 3279);
      std::advance(last, N - 1);

      size_t total_c4 = 0;
      size_t total    = 0;
      auto   llast    = last;
      ++llast;
      std::unordered_set<std::string> set;

      for (auto it1 = first; it1 != last; ++it1) {
        auto it2 = it1;
        ++it2;
        for (; it2 != llast; ++it2) {
          total++;
          Kambites<std::string> k;
          k.set_alphabet("abc");
          k.add_rule(*it1, *it2);
          if (k.small_overlap_class() >= 4) {
            auto tmp = *it1 + "#" + *it2;
            if (set.insert(tmp).second) {
              auto u = swap_a_b_c(*it1);
              auto v = swap_a_b_c(*it2);
              for (size_t i = 0; i < 5; ++i) {
                if (shortlex_compare(u[i], v[i])) {
                  set.insert(u[i] + "#" + v[i]);
                } else {
                  set.insert(v[i] + "#" + u[i]);
                }
              }
              std::cout << *it1 << " = " << *it2 << std::endl;
              total_c4++;
            }
          }
        }
      }
      REQUIRE(total_c4 == 307511);
      REQUIRE(total == 5374281);
    }

    LIBSEMIGROUPS_TEST_CASE("Kambites",
                            "079",
                            "(fpsemi) normal form possible bug",
                            "[standard][kambites][fpsemigroup][fpsemi]") {
      // There was a bug in MultiStringView::append, that caused this test to
      // fail, so we keep this test to check that the bug in
      // MultiStringView::append is resolved.
      Kambites<MultiStringView> k;
      k.set_alphabet("ab");
      k.add_rule("aaabbab""bbbaaba");

      std::vector<std::string> words = {
          "bbbaabaabbbbbaabaabaaabbaabbbbbaaabaaabababbbbaaabbabababbaabbabaabb"
          "aaabbabbaaaabbabbbbbbaabbbbaabbabaaabaaaaabbaabababababaaaabaabbabba"
          "bbaaabbabababbabaabbbbbbabaabbabaaaababbababbabbabbabbbabbbabbbabbbb"
          "aaaaaabbabbaababbbaaababbbbababababbabaabbbbbabaaaababaaabbaaabbaaab"
          "babaabbbaababbbaaabbaabbbbaabbbbaaaaababbabbbaaaaaababbbbaaabbbabbba"
          "babbbbbbaabaabababbabbbbbaaaabbbbabbababbbaaaabbbbaabbbbbabbbbbabaab"
          "bbaaabaaabbababbbabbaaaaaabbbbabababbaabbabbbbabbabbaabbbaaabaaabbab"
          "abbbabbbbaabaaababbabbaababbbabbaababbabbbbabbbbabaabaaaabaaaabababa"
          "abababbaaabbabbbbbbaaaaaabbbbabbabbabaaaaabaabbaababbbbaabaaabbabaaa"
          "abaaabbbaaaabbabbababaaaabbbbaaabbababababaabbaaaabaabbababbabbaaaba"
          "bbaaabbbbbabbbaababaaabbababbbbbaabbbabaaaaabbbbabbabaaaababbabbabab"
          "aabbaababbaaabbabbbbabbbaaabbabbbaabbababbaabbaaaaaabaaabbbaababbaaa"
          "ababaabbaaabbbaabababbbbbababbbbbbbaabbbbaabababbbaabbbbbbbaabbbbaaa"
          "babaaaabaababbbaabaaabaaabaaaaabaabbbbabbabaaabbabbaabbaabbabaaabbbb"
          "baaabababbaabbbaababababaababbaabbabaaaaabaaabaaababaababaaaaaababaa"
          "aaaaaabaababbbbaabaabbabbabaaaaaabaabbabbbabbaabbbbbbbaaaababababbbb"
          "ababbbabbbaaabbabbabbaabbbbbbbababaabaabababbaaabbaabbbaabbbabbbbbab"
          "aaabbbababbbaabaaaabaabbaaaabbabbbabababbaaabbbbaabaabbababaaaabbbaa"
          "aabbbaabaa",
          "aaabbababbbbbaabaabaaabbaabbbbbaaabaaabababbbbaaabbabababbaabbabaabb"
          "bbbaababaaaabbabbbbbbaabbbbaabbabaaabaaaaabbaabababababaaaabaabbabba"
          "bbaaabbabababbabaabbbbbbabaabbabaaaababbababbabbabbabbbabbbabbbabbbb"
          "aaabbbaababaababbbaaababbbbababababbabaabbbbbabaaaababaaabbaaabbaaab"
          "babaabbbaababbbaaabbaabbbbaabbbbaaaaababbabbbaaaaaababbbbaaabbbabbba"
          "babbbbbbaabaabababbabbbbbaaaabbbbabbababbbaaaabbbbaabbbbbabbbbbabaab"
          "bbaaabbbbaabaabbbabbaaaaaabbbbabababbaabbabbbbabbabbaabbbaaabaaabbab"
          "abbbabbbbaabaaababbabbaababbbabbaababbabbbbabbbbabaabaaaabaaaabababa"
          "abababbaaabbabbbbbbaaaaaabbbbabbabbabaaaaabaabbaababbbbaabaaabbabaaa"
          "abaaabbbabbbaababababaaaabbbbaaabbababababaabbaaaabaabbababbabbaaaba"
          "bbaaabbbbbabbbaababaaabbababbbbbaabbbabaaaaabbbbabbabaaaababbabbabab"
          "aabbaababbbbbaababbbabbbaaabbabbbaabbababbaabbaaaaaabaaabbbaababbaaa"
          "ababaabbaaabbbaabababbbbbababbbbbbbaabbbbaabababbbaabbbbbbbaabbbbaaa"
          "babaaaabaabaaaabbabaabaaabaaaaabaabbbbabbabaaabbabbaabbaabbabaaabbbb"
          "baaabababbaaaaabbabbababaababbaabbabaaaaabaaabaaababaababaaaaaababaa"
          "aaaaaabaababbbbaabaabbabbabaaaaaabaabbabbbabbaabbbbbbbaaaababababbbb"
--> --------------------

--> maximum size reached

--> --------------------

91%


¤ Dauer der Verarbeitung: 0.30 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Entwurf

Ziele

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Ergonomie der
Schnittstellen

Diese beiden folgenden Angebotsgruppen bietet das Unternehmen

Angebot

Hier finden Sie eine Liste der Produkte des Unternehmens






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge