Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/semigroups/libsemigroups/tests/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.5.2025 mit Größe 85 kB image not shown  

Quelle  test-sims1.cpp   Sprache: C

 
//
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
//

#include <cstddef>        // for size_t
#include <iostream>       // for cout
#include <stdexcept>      // for number_of_congruencestime_error
#include <unordered_set>  // for unordered_set
#include <vector>         // for vector

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

#include "libsemigroups/bipart.hpp"           // for Bipartition
#include "libsemigroups/config.hpp"           // for LIBSEMIGROUPS_ENABLE_STATS
#include "libsemigroups/digraph-helper.hpp"   // for action_digraph_helper
#include "libsemigroups/fpsemi-examples.hpp"  // for brauer_monoid etc
#include "libsemigroups/froidure-pin.hpp"     // for FroidurePin
#include "libsemigroups/knuth-bendix.hpp"     // for redundant_rule
#include "libsemigroups/make-froidure-pin.hpp"  // for make
#include "libsemigroups/make-present.hpp"       // for make
#include "libsemigroups/sims1.hpp"              // for Sims1
#include "libsemigroups/transf.hpp"             // for Transf
#include "libsemigroups/types.hpp"              // for word_type
                                                //
namespace libsemigroups {

  using Sims1_       = Sims1<uint32_t>;
  using digraph_type = typename Sims1_::digraph_type;
  using node_type    = typename digraph_type::node_type;

  using fpsemigroup::author;
  using fpsemigroup::make;

  using fpsemigroup::brauer_monoid;
  using fpsemigroup::chinese_monoid;
  using fpsemigroup::fibonacci_semigroup;
  using fpsemigroup::full_transformation_monoid;
  using fpsemigroup::monogenic_semigroup;
  using fpsemigroup::partition_monoid;
  using fpsemigroup::plactic_monoid;
  using fpsemigroup::rectangular_band;
  using fpsemigroup::rook_monoid;
  using fpsemigroup::singular_brauer_monoid;
  using fpsemigroup::stellar_monoid;
  using fpsemigroup::stylic_monoid;
  using fpsemigroup::temperley_lieb_monoid;

  namespace {
    template <typename P>
    void check_extra(congruence_kind ck, P const& p, P const& e, size_t n) {
      P f = e;
      if (ck == congruence_kind::left) {
        presentation::reverse(f);
      }
      auto foo = [&f](auto const& ad) {
        using action_digraph_helper::follow_path_nc;
        for (auto it = f.rules.cbegin(); it != f.rules.cend(); it += 2) {
          if (follow_path_nc(ad, 0, *it) != follow_path_nc(ad, 0, *(it + 1))) {
            return false;
          }
        }
        return true;
      };
      Sims1_ S(ck);
      S.short_rules(p);

      Sims1_ T(ck);
      T.short_rules(p).extra(e);

      REQUIRE(static_cast<uint64_t>(std::count_if(S.cbegin(n), S.cend(n), foo))
              == T.number_of_congruences(n));
    }

    constexpr unsigned int factorial(unsigned int n) {
      return n > 1 ? n * factorial(n - 1) : 1;
    }
  }  // namespace

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "000",
                          "fp example 1",
                          "[quick][low-index]") {
    auto rg = ReportGuard(false);

    Presentation<word_type> p;
    p.contains_empty_word(true);
    p.alphabet({0, 1});
    presentation::add_rule_and_check(p, {0, 0, 0}, {0});
    presentation::add_rule_and_check(p, {1, 1}, {1});
    presentation::add_rule_and_check(p, {0, 1, 0, 1}, {0});

    {
      Sims1_ S(congruence_kind::right);
      REQUIRE(S.short_rules(p).number_of_threads(2).number_of_congruences(5)
              == 6);
      REQUIRE_THROWS_AS(S.number_of_congruences(0), LibsemigroupsException);
      REQUIRE_THROWS_AS(S.find_if(0, [](auto) { return false; }),
                        LibsemigroupsException);
      REQUIRE_THROWS_AS(S.for_each(0, [](auto) { return false; }),
                        LibsemigroupsException);
      REQUIRE_THROWS_AS(S.cbegin(0), LibsemigroupsException);
      REQUIRE_THROWS_AS(S.cend(0), LibsemigroupsException);
      REQUIRE(S.number_of_congruences(1) == 1);

      auto it = S.cbegin(1);
      REQUIRE(*it == action_digraph_helper::make<node_type>(1, {{0, 0}}));

      it = S.cbegin(5);
      REQUIRE(*(it++) == action_digraph_helper::make<node_type>(5, {{0, 0}}));
      REQUIRE(*(it++)
              == action_digraph_helper::make<node_type>(5, {{1, 0}, {1, 1}}));
      REQUIRE(*(it++)
              == action_digraph_helper::make<node_type>(5, {{1, 1}, {1, 1}}));
      REQUIRE(*(it++)
              == action_digraph_helper::make<node_type>(
                  5, {{1, 2}, {1, 1}, {1, 2}}));
      REQUIRE(*(it++)
              == action_digraph_helper::make<node_type>(
                  5, {{1, 2}, {1, 1}, {2, 2}}));
      REQUIRE(*(it++)
              == action_digraph_helper::make<node_type>(
                  5, {{1, 2}, {1, 1}, {3, 2}, {3, 3}}));
      REQUIRE(*(it++) == ActionDigraph<node_type>(0, 2));
      REQUIRE(*(it++) == ActionDigraph<node_type>(0, 2));
      REQUIRE(*(it++) == ActionDigraph<node_type>(0, 2));

      it = S.cbegin(3);
      REQUIRE(*it == action_digraph_helper::make<node_type>(3, {{0, 0}}));
    }
    // [[[0, 0]],
    // [[1, 2], [1, 1], [3, 2], [3, 3]],
    // [[1, 2], [1, 1], [2, 2]],
    // [[1, 2], [1, 1], [1, 2]],
    // [[1, 1], [1, 1]],
    // [[1, 0], [1, 1]]]
    {
      Sims1_ S(congruence_kind::left);
      REQUIRE(S.short_rules(p).number_of_congruences(5) == 9);
      for (auto it = S.cbegin(5); it != S.cend(5); ++it) {
        REQUIRE(action_digraph_helper::follow_path_nc(*it, 0, {1, 0, 1, 0})
                == action_digraph_helper::follow_path_nc(*it, 0, {0}));
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "001",
                          "fp example 2",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    p.alphabet({0, 1, 2});
    presentation::add_rule_and_check(p, {0, 1, 0}, {0, 0});
    presentation::add_rule_and_check(p, {2, 2}, {0, 0});
    presentation::add_rule_and_check(p, {0, 0, 0}, {0, 0});
    presentation::add_rule_and_check(p, {2, 1}, {1, 2});
    presentation::add_rule_and_check(p, {2, 0}, {0, 0});
    presentation::add_rule_and_check(p, {1, 1}, {1});
    presentation::add_rule_and_check(p, {0, 2}, {0, 0});

    {
      Sims1_ S(congruence_kind::right);
      S.short_rules(p);
      REQUIRE(S.number_of_congruences(1) == 1);
      REQUIRE(S.number_of_congruences(2) == 3);
      REQUIRE(S.number_of_congruences(3) == 13);
      REQUIRE(S.number_of_congruences(4) == 36);
      REQUIRE(S.number_of_congruences(5) == 82);
      REQUIRE(S.number_of_congruences(6) == 135);
      REQUIRE(S.number_of_congruences(7) == 166);
      REQUIRE(S.number_of_congruences(8) == 175);
      REQUIRE(S.number_of_congruences(9) == 176);
      REQUIRE(S.number_of_congruences(10) == 176);

      auto it = S.cbegin(2);
      REQUIRE(*(it++)
              == action_digraph_helper::make<node_type>(2, {{0, 0, 0}}));
      REQUIRE(
          *(it++)
          == action_digraph_helper::make<node_type>(2, {{1, 0, 1}, {1, 1, 1}}));
      REQUIRE(
          *(it++)
          == action_digraph_helper::make<node_type>(2, {{1, 1, 1}, {1, 1, 1}}));
      REQUIRE(*(it++) == ActionDigraph<node_type>(0, 3));
      REQUIRE(*(it++) == ActionDigraph<node_type>(0, 3));
    }
    {
      Sims1_ S(congruence_kind::left);
      S.short_rules(p);
      REQUIRE(S.number_of_congruences(11) == 176);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "002",
                          "ToddCoxeter failing example",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(false);

    //              a  A  b  B  c  C  e
    p.alphabet({0, 1, 2, 3, 4, 5, 6});
    presentation::add_identity_rules(p, 6);
    presentation::add_inverse_rules(p, {1, 0, 3, 2, 5, 4, 6}, 6);
    presentation::add_rule_and_check(p, {0, 0, 5, 0, 4}, {6});
    presentation::add_rule_and_check(p, {0, 4, 2, 2, 1, 5, 2}, {6});
    presentation::add_rule_and_check(p, {1, 3, 0, 2, 4, 4, 4}, {6});
    Sims1_ S(congruence_kind::right);
    S.short_rules(p);
    REQUIRE(S.number_of_congruences(1) == 1);
    REQUIRE(S.number_of_congruences(3) == 14);
    REQUIRE(S.number_of_congruences(4) == 14);
    REQUIRE(S.number_of_congruences(5) == 14);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "003",
                          "ToddCoxeter failing example",
                          "[quick][low-index]") {
    auto                      rg = ReportGuard(false);
    Presentation<std::string> p;
    p.contains_empty_word(false);

    p.alphabet("aAbBcCe");
    presentation::add_identity_rules(p, 'e');

    presentation::add_inverse_rules(p, "AaBbCce"'e');
    presentation::add_rule_and_check(p, "aaCac""e");
    presentation::add_rule_and_check(p, "acbbACb""e");
    presentation::add_rule_and_check(p, "ABabccc""e");
    Sims1_ S(congruence_kind::right);
    S.short_rules(p);
    REQUIRE(S.number_of_congruences(3) == 14);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "004",
                          "partition_monoid(2) right",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(false);

    p.alphabet({0, 1, 2, 3});
    presentation::add_identity_rules(p, 0);
    presentation::add_rule_and_check(p, {1, 1}, {0});
    presentation::add_rule_and_check(p, {1, 3}, {3});
    presentation::add_rule_and_check(p, {2, 2}, {2});
    presentation::add_rule_and_check(p, {3, 1}, {3});
    presentation::add_rule_and_check(p, {3, 3}, {3});
    presentation::add_rule_and_check(p, {2, 3, 2}, {2});
    presentation::add_rule_and_check(p, {3, 2, 3}, {3});
    presentation::add_rule_and_check(p, {1, 2, 1, 2}, {2, 1, 2});
    presentation::add_rule_and_check(p, {2, 1, 2, 1}, {2, 1, 2});

    Sims1_ S(congruence_kind::right);
    S.short_rules(p);
    REQUIRE(S.number_of_congruences(2) == 4);
    REQUIRE(S.number_of_congruences(3) == 7);
    REQUIRE(S.number_of_congruences(4) == 14);
    REQUIRE(S.number_of_congruences(5) == 23);
    REQUIRE(S.number_of_congruences(6) == 36);
    REQUIRE(S.number_of_congruences(7) == 51);
    REQUIRE(S.number_of_congruences(8) == 62);
    REQUIRE(S.number_of_congruences(9) == 74);
    REQUIRE(S.number_of_congruences(10) == 86);
    REQUIRE(S.number_of_congruences(11) == 95);
    REQUIRE(S.number_of_congruences(12) == 100);
    REQUIRE(S.number_of_congruences(13) == 102);
    REQUIRE(S.number_of_congruences(14) == 104);
    REQUIRE(S.number_of_congruences(15) == 105);
    REQUIRE(S.number_of_congruences(16) == 105);
    REQUIRE(S.number_of_congruences(17) == 105);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "005",
                          "partition_monoid(3)",
                          "[standard][low-index][no-coverage]") {
    auto rg = ReportGuard(false);
    auto p
        = make<Presentation<word_type>>(partition_monoid(3, author::Machine));
    REQUIRE(!p.contains_empty_word());
    REQUIRE(p.alphabet() == word_type({0, 1, 2, 3, 4}));

    Sims1_ S(congruence_kind::right);
    S.short_rules(p).long_rule_length(11).number_of_threads(
        4);  // This actually helps here!
    REQUIRE(S.number_of_congruences(17) == 1589);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "006",
                          "full_transformation_monoid(3) right",
                          "[quick][low-index]") {
    auto                   rg = ReportGuard(false);
    FroidurePin<Transf<3>> S({Transf<3>::make({1, 2, 0}),
                              Transf<3>::make({1, 0, 2}),
                              Transf<3>::make({0, 1, 0})});
    REQUIRE(S.size() == 27);
    REQUIRE(S.number_of_generators() == 3);
    REQUIRE(S.number_of_rules() == 16);
    auto p = make<Presentation<word_type>>(S);
    REQUIRE(static_cast<size_t>(std::distance(p.rules.cbegin(), p.rules.cend()))
            == 2 * S.number_of_rules());
    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(27) == 287);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "007",
                          "full_transformation_monoid(3) left",
                          "[quick][low-index]") {
    auto                   rg = ReportGuard(false);
    FroidurePin<Transf<3>> S(
        {Transf<3>({1, 2, 0}), Transf<3>({1, 0, 2}), Transf<3>({0, 1, 0})});
    REQUIRE(S.size() == 27);
    auto   p = make<Presentation<word_type>>(S);
    Sims1_ C(congruence_kind::left);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(27) == 120);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "008",
                          "full_transformation_monoid(4) left",
                          "[fail][low-index][babbage]") {
    auto rg = ReportGuard(true);

    auto p = make<Presentation<word_type>>(
        full_transformation_monoid(4, author::Iwahori));

    REQUIRE(p.alphabet().size() == 4);

    auto w = presentation::longest_common_subword(p);
    while (!w.empty()) {
      presentation::replace_subword(p, w);
      w = presentation::longest_common_subword(p);
    }

    presentation::sort_each_rule(p);
    presentation::sort_rules(p);
    presentation::remove_duplicate_rules(p);
    presentation::reduce_complements(p);
    presentation::remove_trivial_rules(p);

    do {
      auto it = presentation::redundant_rule(p, std::chrono::milliseconds(100));
      p.rules.erase(it, it + 2);
    } while (presentation::length(p) > 700);

    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    // Takes about 1h31m to run!
    REQUIRE(C.number_of_threads(6).number_of_congruences(256) == 22'069'828);
    // Sims1_ C(congruence_kind::left);
    // C.short_rules(p);
    // REQUIRE(C.number_of_threads(6).number_of_congruences(256) == 120'121);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "009",
                          "rook_monoid(2, 1)",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(false);

    p.alphabet(3);
    for (auto const& rel : rook_monoid(2, 1)) {
      p.add_rule_and_check(rel.first.cbegin(),
                           rel.first.cend(),
                           rel.second.cbegin(),
                           rel.second.cend());
    }
    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(7) == 10);  // Should be 10
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "010",
                          "symmetric_inverse_monoid(2) from FroidurePin",
                          "[quick][low-index]") {
    auto                  rg = ReportGuard(false);
    FroidurePin<PPerm<2>> S({PPerm<2>({1, 0}), PPerm<2>({0}, {0}, 2)});
    REQUIRE(S.size() == 7);
    auto   p = make<Presentation<word_type>>(S);
    Sims1_ C(congruence_kind::left);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(7) == 10);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "011",
                          "symmetric_inverse_monoid(3)",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(false);

    p.alphabet(4);
    for (auto const& rel : rook_monoid(3, 1)) {
      p.add_rule_and_check(rel.first.cbegin(),
                           rel.first.cend(),
                           rel.second.cbegin(),
                           rel.second.cend());
    }
    Sims1_ C(congruence_kind::left);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(34) == 274);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "012",
                          "symmetric_inverse_monoid(4)",
                          "[extreme][low-index]") {
    auto                    rg = ReportGuard(true);
    Presentation<word_type> p;
    p.contains_empty_word(false);

    p.alphabet(5);
    for (auto const& rel : rook_monoid(4, 1)) {
      p.add_rule_and_check(rel.first.cbegin(),
                           rel.first.cend(),
                           rel.second.cbegin(),
                           rel.second.cend());
    }
    presentation::remove_duplicate_rules(p);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);

    REQUIRE(presentation::length(p) == 78);
    REQUIRE(p.alphabet().size() == 5);
    REQUIRE(*presentation::shortest_rule(p) == word_type({0, 0}));
    REQUIRE(*(presentation::shortest_rule(p) + 1) == word_type({0}));
    REQUIRE(presentation::longest_rule_length(p) == 8);

    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_threads(std::thread::hardware_concurrency())
                .number_of_congruences(209)
            == 195'709);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "013",
                          "symmetric_inverse_monoid(5)",
                          "[fail][low-index]") {
    // This might take an extremely long time to terminate
    auto                    rg = ReportGuard(true);
    Presentation<word_type> p;
    p.contains_empty_word(false);

    p.alphabet(6);
    for (auto const& rel : rook_monoid(5, 1)) {
      p.add_rule_and_check(rel.first.cbegin(),
                           rel.first.cend(),
                           rel.second.cbegin(),
                           rel.second.cend());
    }
    Sims1_ C(congruence_kind::left);
    C.short_rules(p);
    REQUIRE(C.number_of_threads(6).number_of_congruences(1'546) == 0);
    // On 24/08/2022 JDM ran this for approx. 16 hours overnight on his laptop,
    // the last line of output was:
    // #4: Sims1: found 63'968'999 congruences in 52156s!
    // #21: Sims1: found 759'256'468 congruences in 244617.546875
    // #12: Sims1: found 943'233'501 congruences in 321019.531250!
    // #30: Sims1: found 1'005'857'634 congruences in 350411.000000!
    // #45: Sims1: found 1'314'588'296 congruences in 487405.000000!
    // #20: Sims1: found 4'619'043'843 congruences in 2'334'184.500000!
    // #49: Sims1: found 5'582'499'404 congruences in 2'912'877.000000!
    // #10: Sims1: found 6'825'113'083 congruences in 3705611.250000!
    //
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "014",
                          "temperley_lieb_monoid(3) from presentation",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    p.alphabet(2);
    for (auto const& rel : temperley_lieb_monoid(3)) {
      p.add_rule_and_check(rel.first.cbegin(),
                           rel.first.cend(),
                           rel.second.cbegin(),
                           rel.second.cend());
    }
    {
      Sims1_ S(congruence_kind::right);
      S.short_rules(p);
      REQUIRE(S.number_of_congruences(14) == 9);
    }
    {
      Sims1_ S(congruence_kind::left);
      S.short_rules(p);
      REQUIRE(S.number_of_congruences(14) == 9);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "015",
                          "temperley_lieb_monoid(4) from presentation",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    p.alphabet(3);
    for (auto const& rel : temperley_lieb_monoid(4)) {
      p.add_rule_and_check(rel.first.cbegin(),
                           rel.first.cend(),
                           rel.second.cbegin(),
                           rel.second.cend());
    }
    {
      Sims1_ S(congruence_kind::right);
      S.short_rules(p);
      REQUIRE(S.number_of_congruences(14) == 79);
    }
    {
      Sims1_ S(congruence_kind::left);
      S.short_rules(p);
      REQUIRE(S.number_of_congruences(14) == 79);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "016",
                          "fp semigroup containing given pairs #1",
                          "[quick][low-index]") {
    auto rg = ReportGuard(false);

    Presentation<word_type> p;
    p.contains_empty_word(true);

    p.alphabet({0, 1});
    presentation::add_rule_and_check(p, {0, 0, 0}, {0});
    presentation::add_rule_and_check(p, {1, 1}, {1});
    presentation::add_rule_and_check(p, {0, 1, 0, 1}, {0});
    Presentation<word_type> e;
    e.contains_empty_word(true);

    e.alphabet({0, 1});
    presentation::add_rule_and_check(e, {0}, {1});
    Sims1_ S(congruence_kind::right);
    S.short_rules(p).extra(e);
    REQUIRE(S.number_of_congruences(5) == 2);
    check_extra(congruence_kind::right, p, e, 5);
    check_extra(congruence_kind::left, p, e, 5);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "017",
                          "fp semigroup containing given pairs #2",
                          "[quick][low-index]") {
    auto rg = ReportGuard(false);

    Presentation<word_type> p;
    p.contains_empty_word(true);

    p.alphabet({0, 1});
    presentation::add_rule_and_check(p, {0, 0, 0}, {0});
    presentation::add_rule_and_check(p, {1, 1}, {1});
    presentation::add_rule_and_check(p, {0, 1, 0, 1}, {0});
    Presentation<word_type> e;
    e.contains_empty_word(true);

    e.alphabet({0, 1});
    presentation::add_rule_and_check(e, {0, 1}, {1});
    Sims1_ T(congruence_kind::right);
    T.short_rules(p).extra(e);
    REQUIRE(T.number_of_congruences(5) == 2);
    check_extra(congruence_kind::right, p, e, 5);
    check_extra(congruence_kind::left, p, e, 5);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "018",
                          "fp semigroup containing given pairs #3",
                          "[quick][low-index]") {
    auto rg = ReportGuard(false);

    Presentation<word_type> p;
    p.contains_empty_word(true);

    p.alphabet({0, 1});
    presentation::add_rule_and_check(p, {0, 0, 0}, {0});
    presentation::add_rule_and_check(p, {1, 1}, {1});
    presentation::add_rule_and_check(p, {0, 1, 0, 1}, {0});
    Presentation<word_type> e;
    e.contains_empty_word(true);

    e.alphabet({0, 1});
    presentation::add_rule_and_check(e, {0, 1, 0, 1}, {0});
    {
      Sims1_ T(congruence_kind::right);
      T.short_rules(p).extra(e);
      REQUIRE(T.number_of_congruences(5) == 6);
    }
    {
      Sims1_ T(congruence_kind::left);
      T.short_rules(p).extra(e);
      REQUIRE(T.number_of_congruences(5) == 9);  // Verified with GAP
    }
    check_extra(congruence_kind::right, p, e, 5);
    check_extra(congruence_kind::left, p, e, 5);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "019",
                          "ToddCoxeter failing example",
                          "[quick][low-index]") {
    auto                      rg = ReportGuard(false);
    Presentation<std::string> p;
    p.contains_empty_word(false);

    p.alphabet("aAbBcCe");
    presentation::add_identity_rules(p, 'e');

    presentation::add_inverse_rules(p, "AaBbCce"'e');
    presentation::add_rule_and_check(p, "aaCac""e");
    presentation::add_rule_and_check(p, "acbbACb""e");
    presentation::add_rule_and_check(p, "ABabccc""e");

    Presentation<std::string> e;
    e.alphabet(p.alphabet());
    presentation::add_rule_and_check(p, "a""A");
    presentation::add_rule_and_check(p, "a""b");

    Sims1_ S(congruence_kind::right);
    S.short_rules(p).extra(e);
    REQUIRE(S.number_of_congruences(3) == 2);

    check_extra(congruence_kind::right, S.short_rules(), S.extra(), 3);
    check_extra(congruence_kind::left, S.short_rules(), S.extra(), 3);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "020",
                          "fp example 2",
                          "[quick][low-index]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    p.alphabet({0, 1, 2});
    presentation::add_rule_and_check(p, {0, 1, 0}, {0, 0});
    presentation::add_rule_and_check(p, {2, 2}, {0, 0});
    presentation::add_rule_and_check(p, {0, 0, 0}, {0, 0});
    presentation::add_rule_and_check(p, {2, 1}, {1, 2});
    presentation::add_rule_and_check(p, {2, 0}, {0, 0});
    presentation::add_rule_and_check(p, {1, 1}, {1});
    presentation::add_rule_and_check(p, {0, 2}, {0, 0});

    Presentation<word_type> e;
    e.alphabet(p.alphabet());
    presentation::add_rule_and_check(e, {1}, {0, 0});
    check_extra(congruence_kind::right, p, e, 11);
    check_extra(congruence_kind::left, p, e, 11);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1""021""exceptions""[quick][low-index]") {
    Presentation<word_type> p;
    p.alphabet({0, 1, 2});
    presentation::add_rule_and_check(p, {0, 1, 0}, {0, 0});

    Presentation<word_type> e;
    e.alphabet({0, 1});
    REQUIRE_THROWS_AS(Sims1_(congruence_kind::right).short_rules(p).extra(e),
                      LibsemigroupsException);
    REQUIRE_THROWS_AS(
        Sims1_(congruence_kind::right).short_rules(p).long_rules(e),
        LibsemigroupsException);
    REQUIRE_THROWS_AS(
        Sims1_(congruence_kind::right).long_rules(p).short_rules(e),
        LibsemigroupsException);
    REQUIRE_THROWS_AS(Sims1_(congruence_kind::right).long_rules(p).extra(e),
                      LibsemigroupsException);
    REQUIRE_THROWS_AS(Sims1_(congruence_kind::right).extra(p).short_rules(e),
                      LibsemigroupsException);
    REQUIRE_THROWS_AS(Sims1_(congruence_kind::right).extra(p).long_rules(e),
                      LibsemigroupsException);
    REQUIRE_NOTHROW(Sims1_(congruence_kind::right).extra(p).extra(e));
    REQUIRE_NOTHROW(
        Sims1_(congruence_kind::right).short_rules(p).short_rules(e));
    REQUIRE_NOTHROW(Sims1_(congruence_kind::right).long_rules(p).long_rules(e));
    REQUIRE_THROWS_AS(Sims1_(congruence_kind::twosided),
                      LibsemigroupsException);
    Sims1_ S(congruence_kind::right);
    REQUIRE_THROWS_AS(S.number_of_threads(0), LibsemigroupsException);
    RepOrc ro;
    REQUIRE_THROWS_AS(ro.number_of_threads(0), LibsemigroupsException);
    MinimalRepOrc mro;
    REQUIRE_THROWS_AS(mro.number_of_threads(0), LibsemigroupsException);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "022",
                          "singular_brauer_monoid(4) (Maltcev-Mazorchuk)",
                          "[extreme][sims1]") {
    auto rg = ReportGuard(true);
    auto p  = make<Presentation<word_type>>(singular_brauer_monoid(4));
    REQUIRE(p.alphabet().size() == 12);
    REQUIRE(presentation::length(p) == 660);

    REQUIRE(*presentation::shortest_rule(p) == word_type({0}));
    REQUIRE(*(presentation::shortest_rule(p) + 1) == word_type({3}));

    presentation::remove_redundant_generators(p);

    presentation::remove_duplicate_rules(p);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);

    REQUIRE(presentation::shortest_rule_length(p) == 3);
    REQUIRE(*presentation::shortest_rule(p) == word_type({0, 0}));
    REQUIRE(*(presentation::shortest_rule(p) + 1) == word_type({0}));

    REQUIRE(presentation::longest_rule_length(p) == 6);
    REQUIRE(*presentation::longest_rule(p) == word_type({0, 4, 8}));
    REQUIRE(*(presentation::longest_rule(p) + 1) == word_type({0, 2, 8}));

    REQUIRE(p.alphabet().size() == 6);
    REQUIRE(presentation::length(p) == 462);
    REQUIRE(p.rules.size() == 186);

    p.contains_empty_word(true);
    p.validate();

    MinimalRepOrc orc;
    auto          d = orc.short_rules(p)
                 .target_size(82)
                 .number_of_threads(std::thread::hardware_concurrency())
                 .report_interval(1'999)
                 .digraph();
    REQUIRE(d.number_of_nodes() == 18);
    REQUIRE(orc.target_size() == 82);

    p.contains_empty_word(false);

    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.short_rules().rules.size() == 186);

    REQUIRE(C.number_of_threads(std::thread::hardware_concurrency())
                .number_of_congruences(81)
            == 601'265);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "023",
                          "Brauer(4) from FroidurePin",
                          "[extreme][sims1]") {
    auto                     rg = ReportGuard(true);
    FroidurePin<Bipartition> S;
    S.add_generator(Bipartition({{1, -1}, {2, -2}, {3, -3}, {4, -4}}));
    S.add_generator(Bipartition({{1, -2}, {2, -3}, {3, -4}, {4, -1}}));
    S.add_generator(Bipartition({{1, -2}, {2, -1}, {3, -3}, {4, -4}}));
    S.add_generator(Bipartition({{1, 2}, {3, -3}, {4, -4}, {-1, -2}}));
    REQUIRE(S.size() == 105);

    auto p = make<Presentation<word_type>>(S);
    REQUIRE(presentation::length(p) == 359);
    presentation::remove_duplicate_rules(p);
    REQUIRE(presentation::length(p) == 359);
    presentation::reduce_complements(p);
    REQUIRE(presentation::length(p) == 359);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);
    REQUIRE(p.rules.size() == 86);
    do {
      auto it = presentation::redundant_rule(p, std::chrono::milliseconds(100));
      p.rules.erase(it, it + 2);
    } while (presentation::length(p) > 300);
    presentation::replace_subword(p, presentation::longest_common_subword(p));

    Sims1_ C(congruence_kind::right);
    C.short_rules(p).long_rule_length(8);
    REQUIRE(C.number_of_threads(std::thread::hardware_concurrency())
                .number_of_congruences(105)
            == 103'406);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "024",
                          "brauer_monoid(4) (Kudryavtseva-Mazorchuk)",
                          "[extreme][sims1]") {
    auto rg = ReportGuard(true);
    auto p  = make<Presentation<word_type>>(brauer_monoid(4));
    REQUIRE(p.alphabet().size() == 7);
    REQUIRE(presentation::length(p) == 182);
    presentation::remove_duplicate_rules(p);
    REQUIRE(presentation::length(p) == 162);
    presentation::reduce_complements(p);
    REQUIRE(presentation::length(p) == 159);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);
    REQUIRE(p.rules.size() == 86);

    auto d = MinimalRepOrc().short_rules(p).target_size(105).digraph();
    REQUIRE(d.number_of_nodes() == 22);
    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
    REQUIRE(
        d
        == action_digraph_helper::make<uint32_t>(
            22, {{0, 0, 1, 0, 2, 3, 2},        {1, 4, 0, 5, 6, 3, 7},
                 {2, 2, 2, 2, 2, 2, 2},        {3, 8, 3, 9, 6, 3, 7},
                 {4, 1, 4, 10, 6, 2, 11},      {5, 10, 5, 1, 12, 2, 7},
                 {6, 6, 8, 12, 6, 3, 13},      {7, 11, 9, 7, 13, 3, 7},
                 {8, 3, 6, 14, 6, 3, 11},      {9, 14, 7, 3, 12, 3, 7},
                 {10, 5, 15, 4, 12, 16, 11},   {11, 7, 17, 11, 13, 16, 11},
                 {12, 12, 18, 6, 12, 16, 13},  {13, 13, 19, 13, 13, 20, 13},
                 {14, 9, 21, 8, 12, 20, 11},   {15, 15, 10, 15, 2, 16, 2},
                 {16, 18, 16, 17, 12, 16, 11}, {17, 21, 11, 16, 6, 16, 11},
                 {18, 16, 12, 21, 12, 16, 7},  {19, 20, 13, 20, 13, 20, 13},
                 {20, 19, 20, 19, 13, 20, 13}, {21, 17, 14, 18, 6, 20, 7}}));

    auto S = make<FroidurePin<Transf<0, node_type>>>(d);
    REQUIRE(S.size() == 105);
    REQUIRE(S.generator(0) == Transf<0, node_type>::identity(22));
    REQUIRE(
        S.generator(1)
        == Transf<0, node_type>({0, 4,  2,  8, 1,  10, 6,  11, 3,  14, 5,
                                 7, 12, 13, 9, 15, 18, 21, 16, 20, 19, 17}));
    REQUIRE(
        S.generator(2)
        == Transf<0, node_type>({1,  0,  2,  3,  4,  5,  8,  9,  6,  7,  15,
                                 17, 18, 19, 21, 10, 16, 11, 12, 13, 20, 14}));
    REQUIRE(S.generator(3)
            == Transf<0, node_type>({0, 5,  2, 9,  10, 1,  12, 7,  14, 3, 4, 11,
                                     6, 13, 8, 15, 17, 16, 21, 20, 19, 18}));
    REQUIRE(S.generator(4)
            == Transf<0, node_type>({2,  6,  2,  6,  6, 12, 6, 13, 6,  12, 12,
                                     13, 12, 13, 12, 2, 12, 6, 12, 13, 13, 6}));
    REQUIRE(
        S.generator(5)
        == Transf<0, node_type>({3,  3,  2,  3,  2,  2,  3,  3,  3,  3,  16,
                                 16, 16, 20, 20, 16, 16, 16, 16, 20, 20, 20}));
    REQUIRE(
        S.generator(6)
        == Transf<0, node_type>({2,  7,  2,  7,  11, 7,  13, 7, 11, 7,  11,
                                 11, 13, 13, 11, 2,  11, 11, 7, 13, 13, 7}));

    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_threads(std::thread::hardware_concurrency())
                .number_of_congruences(105)
            == 103'406);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "025",
                          "brauer_monoid(5) (Kudryavtseva-Mazorchuk)",
                          "[extreme][sims1]") {
    auto rg = ReportGuard(true);
    auto p  = make<Presentation<word_type>>(brauer_monoid(5));

    REQUIRE(presentation::length(p) == 295);

    presentation::remove_duplicate_rules(p);
    presentation::reduce_complements(p);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);
    REQUIRE(presentation::length(p) == 249);

    REQUIRE(presentation::shortest_rule_length(p) == 3);
    REQUIRE(*presentation::shortest_rule(p) == word_type({0, 0}));
    REQUIRE(*(presentation::shortest_rule(p) + 1) == word_type({0}));

    REQUIRE(p.alphabet().size() == 9);

    presentation::remove_redundant_generators(p);
    REQUIRE(p.alphabet() == word_type({1, 2, 3, 4, 5, 6, 7, 8}));
    REQUIRE(p.alphabet().size() == 8);
    REQUIRE(presentation::length(p) == 268);

    REQUIRE(*presentation::longest_rule(p) == word_type({1, 1, 1, 1}));
    REQUIRE(*(presentation::longest_rule(p) + 1) == word_type({1, 1}));

    REQUIRE(presentation::longest_common_subword(p) == word_type({1, 1}));
    p.alphabet(9);
    presentation::replace_subword(p, {1, 1}, {0});
    REQUIRE(presentation::length(p) == 246);

    // This is just very long running (without e!) and I haven't managed to run
    // it to completion.
    Presentation<word_type> e;
    e.alphabet(9);
    presentation::add_rule_and_check(e, {0}, {1});

    auto d = MinimalRepOrc()
                 .short_rules(p)
                 .extra(e)
                 .target_size(945)
                 .number_of_threads(8)
                 .report_interval(100)
                 .digraph();
    // WARNING: the number below is not necessarily the minimal degree of an
    // action on right congruences, only the minimal degree of an action on
    // right congruences containing the pair {0}, {1}.
    REQUIRE(d.number_of_nodes() == 46);
    auto S = make<FroidurePin<Transf<0, node_type>>>(d);
    REQUIRE(S.size() == 945);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "026",
                          "uniform_block_bijection_monoid(4) (Fitzgerald)",
                          "[extreme][sims1]") {
    auto rg = ReportGuard(true);
    auto p  = make<Presentation<word_type>>(
        uniform_block_bijection_monoid(4, author::FitzGerald));
    presentation::remove_duplicate_rules(p);
    presentation::reduce_complements(p);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);

    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_threads(std::thread::hardware_concurrency())
                .number_of_congruences(131)
            == 280'455);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "027",
                          "from https://mathoverflow.net/questions/423541/",
                          "[quick][sims1]") {
    auto                      rg = ReportGuard(false);
    Presentation<std::string> p;
    p.contains_empty_word(false);
    p.alphabet("aAbBe");
    presentation::add_identity_rules(p, 'e');
    presentation::add_inverse_rules(p, "AaBbe"'e');
    presentation::add_rule_and_check(p, "aaa""e");
    presentation::add_rule_and_check(p, "baBBBABA""e");
    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(10) == 3);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "028",
                          "from https://mathoverflow.net/questions/423541/",
                          "[quick][sims1]") {
    auto                      rg = ReportGuard(false);
    Presentation<std::string> p;
    p.contains_empty_word(true);
    p.alphabet("aAbB");
    presentation::add_inverse_rules(p, "AaBb");
    presentation::add_rule_and_check(p, "aaa""");
    presentation::add_rule_and_check(p, "baBBBABA""");
    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(10) == 3);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "029",
                          "fibonacci_semigroup(4, 6)",
                          "[standard][sims1][no-valgrind]") {
    auto rg = ReportGuard(true);  // for code coverage
    auto p  = make<Presentation<word_type>>(fibonacci_semigroup(4, 6));
    presentation::remove_duplicate_rules(p);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);
    REQUIRE(presentation::length(p) == 30);
    REQUIRE(p.rules.size() == 12);
    REQUIRE(p.rules[0].size() + p.rules[1].size() == 5);

    Sims1_ C(congruence_kind::right);
    C.short_rules(p).report_interval(1);
    REQUIRE(C.number_of_congruences(3) == 5);

    C.number_of_threads(2);
    REQUIRE(C.number_of_congruences(3) == 5);
    REQUIRE_THROWS_AS(C.find_if(0, [](auto const&) { return true; }),
                      LibsemigroupsException);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "030",
                          "presentation with one free generator",
                          "[quick][sims1]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.alphabet(4);
    presentation::add_rule(p, {1, 2, 1}, {1, 1});
    presentation::add_rule(p, {3, 3}, {1, 1});
    presentation::add_rule(p, {1, 1, 1}, {1, 1});
    presentation::add_rule(p, {3, 2}, {2, 3});
    presentation::add_rule(p, {3, 1}, {1, 1});
    presentation::add_rule(p, {2, 2}, {2});
    presentation::add_rule(p, {1, 3}, {1, 1});
    p.validate();
    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(2) == 67);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "031",
                          "presentation with non-zero index generators",
                          "[quick][sims1]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    presentation::add_rule(p, {1, 2, 1}, {1, 1});
    presentation::add_rule(p, {3, 3}, {1, 1});
    presentation::add_rule(p, {1, 1, 1}, {1, 1});
    presentation::add_rule(p, {3, 2}, {2, 3});
    presentation::add_rule(p, {3, 1}, {1, 1});
    presentation::add_rule(p, {2, 2}, {2});
    presentation::add_rule(p, {1, 3}, {1, 1});
    p.alphabet_from_rules();
    p.validate();

    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(2) == 7);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "032",
                          "presentation with empty word",
                          "[quick][sims1]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    //          a  A  b  B  c  C
    p.alphabet({0, 1, 2, 3, 4, 5});
    presentation::add_inverse_rules(p, {1, 0, 3, 2, 5, 4});
    presentation::add_rule_and_check(p, {0, 0, 5, 0, 4}, {});
    presentation::add_rule_and_check(p, {0, 4, 2, 2, 1, 5, 2}, {});
    presentation::add_rule_and_check(p, {1, 3, 0, 2, 4, 4, 4}, {});
    Sims1_ S(congruence_kind::right);
    S.short_rules(p);
    REQUIRE(S.number_of_congruences(3) == 14);
    REQUIRE(S.number_of_congruences(4) == 14);
    REQUIRE(S.number_of_congruences(5) == 14);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1""033""constructors""[quick][sims1]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    //          a  A  b  B  c  C
    p.alphabet({0, 1, 2, 3, 4, 5});
    presentation::add_inverse_rules(p, {1, 0, 3, 2, 5, 4});
    presentation::add_rule_and_check(p, {0, 0, 5, 0, 4}, {});
    presentation::add_rule_and_check(p, {0, 4, 2, 2, 1, 5, 2}, {});
    presentation::add_rule_and_check(p, {1, 3, 0, 2, 4, 4, 4}, {});
    Sims1_ S(congruence_kind::right);
    S.short_rules(p);

    Sims1_ T(S);
    REQUIRE(S.number_of_congruences(3) == 14);
    REQUIRE(T.number_of_congruences(3) == 14);

    Sims1_ U(std::move(S));
    REQUIRE(U.number_of_congruences(3) == 14);
    REQUIRE(T.number_of_congruences(3) == 14);

    S = U;
    REQUIRE(S.number_of_congruences(3) == 14);

    S = std::move(U);
    REQUIRE(S.number_of_congruences(3) == 14);

    Presentation<word_type> e;
    e.alphabet({0, 1, 2, 5});

    Sims1_ C(congruence_kind::right);
    REQUIRE_THROWS_AS(C.short_rules(p).extra(e), LibsemigroupsException);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1""034""split_at""[quick][sims1]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    //          a  A  b  B  c  C
    p.alphabet({0, 1, 2, 3, 4, 5});
    presentation::add_inverse_rules(p, {1, 0, 3, 2, 5, 4});
    presentation::add_rule_and_check(p, {0, 0, 5, 0, 4}, {});
    presentation::add_rule_and_check(p, {0, 4, 2, 2, 1, 5, 2}, {});
    presentation::add_rule_and_check(p, {1, 3, 0, 2, 4, 4, 4}, {});
    Sims1_ S(congruence_kind::right);
    S.short_rules(p);

    REQUIRE_THROWS_AS(S.split_at(10), LibsemigroupsException);
    S.split_at(0);

    REQUIRE(S.short_rules().rules.empty());

    for (size_t i = 0; i <= p.rules.size() / 2; ++i) {
      S.split_at(i);
      REQUIRE(S.short_rules().rules.size() == 2 * i);
    }
    REQUIRE(S.short_rules().rules.size() == p.rules.size());
    for (size_t i = p.rules.size() / 2; i > 0; --i) {
      S.split_at(i);
      REQUIRE(S.short_rules().rules.size() == 2 * i);
    }
    S.split_at(7);
    REQUIRE(S.number_of_congruences(3) == 14);
  }

#ifdef LIBSEMIGROUPS_ENABLE_STATS
  LIBSEMIGROUPS_TEST_CASE("Sims1""035""stats""[quick][sims1]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);

    //          a  A  b  B  c  C
    p.alphabet({0, 1, 2, 3, 4, 5});
    presentation::add_inverse_rules(p, {1, 0, 3, 2, 5, 4});
    presentation::add_rule_and_check(p, {0, 0, 5, 0, 4}, {});
    presentation::add_rule_and_check(p, {0, 4, 2, 2, 1, 5, 2}, {});
    presentation::add_rule_and_check(p, {1, 3, 0, 2, 4, 4, 4}, {});
    Sims1_ S(congruence_kind::right);
    S.short_rules(p);

    std::stringbuf buff;
    std::ostream   os(&buff);
    S.number_of_congruences(2);
    // REQUIRE(S.stats().max_pending != 0);
    os << S.cbegin(3).stats();  // Also does not do anything visible
  }
#endif

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "036",
                          "check iterator requirements",
                          "[quick][sims1]") {
    Presentation<word_type> p;
    p.contains_empty_word(true);
    p.alphabet({0, 1});
    presentation::add_rule_and_check(p, {0, 0, 0}, {0});
    presentation::add_rule_and_check(p, {1, 1}, {1});
    presentation::add_rule_and_check(p, {0, 1, 0, 1}, {0});

    {
      Sims1_ S(congruence_kind::right);
      S.short_rules(p);
      verify_forward_iterator_requirements(S.cbegin(10));
      auto it = S.cbegin(10);
      REQUIRE(it->number_of_nodes() == 10);
    }
    {
      Sims1_ S(congruence_kind::left);
      S.short_rules(p);
      verify_forward_iterator_requirements(S.cbegin(10));
      auto it = S.cbegin(10);
      REQUIRE(it->number_of_nodes() == 10);
    }
  }

  // Takes about 30s
  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "037",
                          "rectangular_band(9, 2)",
                          "[extreme][sims1]") {
    auto rg = ReportGuard(true);
    auto p  = make<Presentation<word_type>>(rectangular_band(9, 2));
    presentation::remove_duplicate_rules(p);
    presentation::sort_each_rule(p);
    presentation::sort_rules(p);

    REQUIRE(MinimalRepOrc()
                .short_rules(p)
                .target_size(18)
                .number_of_threads(std::thread::hardware_concurrency())
                .digraph()
                .number_of_nodes()
            == 0);
    p.contains_empty_word(true);
    auto mro = MinimalRepOrc().short_rules(p).target_size(19).number_of_threads(
        std::thread::hardware_concurrency());
    auto d = mro.digraph();
    REQUIRE(d.number_of_nodes() == 11);
    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
    auto S = make<FroidurePin<Transf<0, node_type>>>(d);
    S.add_generator(S.generator(0).identity());
    REQUIRE(S.size() == 19);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "038",
                          "partition_monoid(3) - minimal o.r.c. rep",
                          "[extreme][sims1]") {
    auto rg = ReportGuard(true);
    auto p
        = make<Presentation<word_type>>(partition_monoid(3, author::Machine));
    REQUIRE(!p.contains_empty_word());
    REQUIRE(p.alphabet() == word_type({0, 1, 2, 3, 4}));

    auto d = RepOrc()
                 .short_rules(p)
                 .target_size(203)
                 .min_nodes(1)
                 .max_nodes(22)
                 .number_of_threads(2)
                 .digraph();
    REQUIRE(d.number_of_nodes() == 22);

    auto mro
        = MinimalRepOrc().short_rules(p).target_size(203).number_of_threads(4);
    d = mro.digraph();

    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
    auto S = make<FroidurePin<Transf<0, node_type>>>(d);
    REQUIRE(S.size() == 203);
    // The actual digraph obtained is non-deterministic because we just take
    // whichever one is found first.
    // REQUIRE(
    //     d
    //     == action_digraph_helper::make<node_type>(
    //         22,
    //         {{0, 1, 0, 2, 0},      {1, 3, 3, 4, 5},      {2, 6, 6, 2, 0},
    //          {3, 0, 1, 2, 5},      {4, 4, 4, 4, 4},      {5, 5, 5, 7, 5},
    //          {6, 8, 2, 4, 0},      {7, 9, 9, 7, 5},      {8, 2, 8, 4, 10},
    //          {9, 10, 7, 11, 5},    {10, 7, 10, 12, 10},  {11, 13, 11, 11,
    //          14}, {12, 11, 13, 12, 10}, {13, 12, 12, 15, 10}, {14, 16, 14,
    //          11, 14}, {15, 15, 15, 15, 17}, {16, 18, 18, 19, 5},  {17, 19,
    //          17, 15, 17}, {18, 14, 16, 12, 5},  {19, 20, 20, 19, 21}, {20,
    //          17, 19, 15, 21}, {21, 21, 21, 19, 21}}));
    REQUIRE(d.number_of_nodes() == 22);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "039",
                          "temperley_lieb_monoid(n) - n = 3 .. 6, minimal rep",
                          "[standard][sims1]") {
    auto rg = ReportGuard(false);

    std::array<uint64_t, 11> const sizes
        = {0, 1, 2, 5, 14, 42, 132, 429, 1'430, 4'862, 16'796};
    std::array<uint64_t, 11> const min_degrees
        = {0, 0, 2, 4, 7, 10, 20, 29, 63, 91, 0};
    // The values 63 and 91 are not verified

    for (size_t n = 3; n <= 6; ++n) {
      auto p = make<Presentation<word_type>>(temperley_lieb_monoid(n));
      // There are no relations containing the empty word so we just manually
      // add it.
      p.contains_empty_word(true);
      auto orc
          = MinimalRepOrc().short_rules(p).number_of_threads(2).target_size(
              sizes[n]);

      auto d = orc.digraph();
      REQUIRE(orc.target_size() == sizes[n]);
      REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
      auto S = make<FroidurePin<Transf<0, node_type>>>(d);
      S.add_generator(S.generator(0).identity());
      REQUIRE(S.size() == sizes[n]);
      REQUIRE(d.number_of_nodes() == min_degrees[n]);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "040",
                          "TransitiveGroup(10, 32) - minimal rep",
                          "[quick][sims1]") {
    auto                    rg = ReportGuard(false);
    Presentation<word_type> p;
    p.contains_empty_word(true);
    p.alphabet({0, 1, 2, 3, 4});
    presentation::add_rule_and_check(p, {0, 0}, {});
    presentation::add_rule_and_check(p, {1, 1}, {});
    presentation::add_rule_and_check(p, {2, 2}, {});
    presentation::add_rule_and_check(p, {3, 3}, {});
    presentation::add_rule_and_check(p, {4, 4}, {});
    presentation::add_rule_and_check(p, {0, 1, 0, 1, 0, 1}, {});
    presentation::add_rule_and_check(p, {0, 2, 0, 2}, {});
    presentation::add_rule_and_check(p, {0, 3, 0, 3}, {});
    presentation::add_rule_and_check(p, {0, 4, 0, 4}, {});
    presentation::add_rule_and_check(p, {1, 2, 1, 2, 1, 2}, {});
    presentation::add_rule_and_check(p, {1, 3, 1, 3}, {});
    presentation::add_rule_and_check(p, {1, 4, 1, 4}, {});
    presentation::add_rule_and_check(p, {2, 3, 2, 3, 2, 3}, {});
    presentation::add_rule_and_check(p, {2, 4, 2, 4}, {});
    presentation::add_rule_and_check(p, {3, 4, 3, 4, 3, 4}, {});
    REQUIRE(MinimalRepOrc()
                .short_rules(p)
                .target_size(0)
                .digraph()
                .number_of_nodes()
            == 0);

    REQUIRE(RepOrc()
                .short_rules(p)
                .min_nodes(0)
                .max_nodes(0)
                .target_size(0)
                .digraph()
                .number_of_nodes()
            == 0);

    auto d = MinimalRepOrc().short_rules(p).target_size(720).digraph();
    REQUIRE(d.number_of_nodes() == 6);
    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "041",
                          "rectangular_band(4, 4) - minimal o.r.c. rep",
                          "[standard][sims1]") {
    auto rg = ReportGuard(false);
    auto p  = make<Presentation<word_type>>(rectangular_band(4, 4));
    p.contains_empty_word(true);
    auto d = MinimalRepOrc()
                 .short_rules(p)
                 .number_of_threads(2)
                 .target_size(17)
                 .digraph();
    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
    auto S = make<FroidurePin<Transf<0, node_type>>>(d);
    REQUIRE(S.size() == 16);
    REQUIRE(d.number_of_nodes() == 7);

    p.contains_empty_word(false);
    d = MinimalRepOrc()
            .short_rules(p)
            .target_size(16)
            .number_of_threads(2)
            .digraph();
    REQUIRE(d.number_of_nodes() == 0);
  }

  // unbuffer -p ./test_sims1 "[042]" | ag -v FroidurePin
  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "042",
                          "rectangular_band(m, n) - m = 1 .. 5, n = 1 .. 5",
                          "[fail][sims1]") {
    // This doesn't fail it's just very extreme
    std::vector<std::array<size_t, 6>> results = {{0, 0, 0, 0, 0, 0},
                                                  {0, 2, 2, 3, 4, 5},
                                                  {0, 3, 4, 5, 5, 6},
                                                  {0, 4, 5, 6, 6, 7},
                                                  {0, 5, 6, 7, 7, 8},
                                                  {0, 6, 7, 8, 8, 9}};

    auto rg = ReportGuard(true);
    for (size_t m = 1; m <= 5; ++m) {
      for (size_t n = 1; n <= 5; ++n) {
        std::cout << std::string(72, '#') << "\n"
                  << "CASE m, n = " << m << ", " << n << "\n"
                  << std::string(72, '#') << std::endl;

        auto p = make<Presentation<word_type>>(rectangular_band(m, n));
        p.contains_empty_word(true);
        auto d = MinimalRepOrc()
                     .short_rules(p)
                     .target_size(m * n + 1)
                     .number_of_threads(6)
                     .digraph();
        REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
        auto S = make<FroidurePin<Transf<0, node_type>>>(d);
        REQUIRE(S.size() == m * n);
        REQUIRE(d.number_of_nodes() == results[m][n]);
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "043",
                          "rectangular_band(2, 2) - with and without identity",
                          "[quick][sims1]") {
    auto   rg = ReportGuard(false);
    auto   p  = make<Presentation<word_type>>(rectangular_band(2, 2));
    Sims1_ S(congruence_kind::right);
    S.short_rules(p);

    REQUIRE(S.number_of_congruences(4) == 6);

    p.contains_empty_word(true);

    Sims1_ T(congruence_kind::right);
    T.short_rules(p);
    REQUIRE(T.number_of_congruences(5) == 9);

    auto it = S.cbegin(4);

    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 1, 1}, {1, 1, 1, 1}}));  // Good
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 1, 2}, {1, 1, 1, 2}, {1, 1, 1, 2}}));  // Good
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 2, 1}, {1, 1, 1, 1}, {2, 2, 2, 2}}));  // Good
    REQUIRE(
        *it++
        == action_digraph_helper::make<node_type>(
            5,
            {{1, 1, 2, 1}, {1, 1, 1, 1}, {2, 2, 2, 3}, {2, 2, 2, 3}}));  // Good
    REQUIRE(
        *it++
        == action_digraph_helper::make<node_type>(
            5,
            {{1, 1, 2, 3}, {1, 1, 1, 3}, {2, 2, 2, 2}, {1, 1, 1, 3}}));  // Good
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(5,
                                                      {{1, 1, 2, 3},
                                                       {1, 1, 1, 3},
                                                       {2, 2, 2, 4},
                                                       {1, 1, 1, 3},
                                                       {2, 2, 2, 4}}));  // Good
    REQUIRE(it->number_of_nodes() == 0);

    it = T.cbegin(5);

    REQUIRE(*it++ == action_digraph_helper::make<node_type>(5, {{0, 0, 0, 0}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{0, 0, 0, 1}, {0, 0, 0, 1}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 1, 0}, {1, 1, 1, 0}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 1, 1}, {1, 1, 1, 1}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 1, 2}, {1, 1, 1, 2}, {1, 1, 1, 2}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 2, 1}, {1, 1, 1, 1}, {2, 2, 2, 2}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 2, 1}, {1, 1, 1, 1}, {2, 2, 2, 3}, {2, 2, 2, 3}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(
                5, {{1, 1, 2, 3}, {1, 1, 1, 3}, {2, 2, 2, 2}, {1, 1, 1, 3}}));
    REQUIRE(*it++
            == action_digraph_helper::make<node_type>(5,
                                                      {{1, 1, 2, 3},
                                                       {1, 1, 1, 3},
                                                       {2, 2, 2, 4},
                                                       {1, 1, 1, 3},
                                                       {2, 2, 2, 4}}));
    REQUIRE(it->number_of_nodes() == 0);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "044",
                          "trivial group - minimal o.r.c. rep",
                          "[quick][sims1]") {
    auto                      rg = ReportGuard(false);
    Presentation<std::string> p;
    p.alphabet("aAbB");
    p.contains_empty_word(true);
    presentation::add_inverse_rules(p, "AaBb");
    presentation::add_rule_and_check(p, "ab""");
    presentation::add_rule_and_check(p, "abb""");

    Sims1_ S(congruence_kind::right);
    S.short_rules(p);

    REQUIRE(S.number_of_congruences(10) == 1);
    auto d = MinimalRepOrc().short_rules(p).target_size(1).digraph();
    REQUIRE(d.number_of_nodes() == 1);
    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "045",
                          "right zero semigroup - minimal o.r.c. rep",
                          "[quick][sims1]") {
    // This is an example of a semigroup with a strictly cyclic faithful
    // right representation.
    auto         rg = ReportGuard(false);
    size_t const n  = 5;
    auto         p  = make<Presentation<word_type>>(rectangular_band(1, n));
    auto         d  = MinimalRepOrc().short_rules(p).target_size(n).digraph();
    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
    auto S = make<FroidurePin<Transf<0, node_type>>>(d);
    REQUIRE(S.size() == n);
    REQUIRE(d.number_of_nodes() == 5);
  }

  LIBSEMIGROUPS_TEST_CASE(
      "Sims1",
      "046",
      "semigroup with faithful non-strictly cyclic action of right congruence",
      "[quick][sims1]") {
    // Found with Smallsemi, this example is minimal wrt size of the semigroup.

    auto rg = ReportGuard(false);

    FroidurePin<Transf<6>> S({Transf<6>::make({0, 0, 2, 1, 4, 1}),
                              Transf<6>::make({0, 0, 2, 3, 4, 3}),
                              Transf<6>::make({0, 2, 2, 0, 4, 4})});

    REQUIRE(S.size() == 5);
    auto p = make<Presentation<word_type>>(S);
    auto d = MinimalRepOrc().short_rules(p).target_size(5).digraph();
    REQUIRE(action_digraph_helper::is_strictly_cyclic(d));
    REQUIRE(d.number_of_nodes() == 4);
    REQUIRE(d
            == action_digraph_helper::make<uint32_t>(
                4, {{2, 2, 3}, {0, 1, 2}, {2, 2, 2}, {3, 3, 3}}));
    auto T = make<FroidurePin<Transf<4>>>(d);
    REQUIRE(T.generator(0) == Transf<4>({2, 0, 2, 3}));
    REQUIRE(T.generator(1) == Transf<4>({2, 1, 2, 3}));
    REQUIRE(T.generator(2) == Transf<4>({3, 2, 2, 3}));
    REQUIRE(T.size() == 5);

    auto dd = action_digraph_helper::make<uint8_t>(5,
                                                   {{0, 0, 0, 0, 0},
                                                    {0, 0, 0, 0, 2},
                                                    {2, 2, 2, 2, 2},
                                                    {0, 1, 2, 3, 0},
                                                    {4, 4, 4, 4, 4}});

    REQUIRE(!action_digraph_helper::is_strictly_cyclic(dd));
    REQUIRE(dd.number_of_nodes() == 5);
    auto U = make<FroidurePin<Transf<5>>>(dd);
    REQUIRE(U.size() == 5);

    Sims1_ C(congruence_kind::right);
    C.short_rules(p);
    REQUIRE(C.number_of_congruences(5) == 9);
    uint64_t strictly_cyclic_count     = 0;
    uint64_t non_strictly_cyclic_count = 0;

    for (auto it = C.cbegin(5); it != C.cend(5); ++it) {
      auto W = make<FroidurePin<Transf<0, node_type>>>(
          *it, 1, it->number_of_active_nodes());
      if (p.contains_empty_word()) {
        auto one = W.generator(0).identity();
        if (!W.contains(one)) {
          W.add_generator(one);
        }
      }
      if (W.size() == 5) {
        auto result = *it;
        result.induced_subdigraph(1, result.number_of_active_nodes());
        result.number_of_active_nodes(result.number_of_active_nodes() - 1);
        if (action_digraph_helper::is_strictly_cyclic(result)) {
          strictly_cyclic_count++;
        } else {
          REQUIRE(W.generator(0) == Transf<0, node_type>({3, 0, 2, 3, 4}));
          REQUIRE(W.generator(1) == Transf<0, node_type>({3, 1, 2, 3, 4}));
          REQUIRE(W.generator(2) == Transf<0, node_type>({4, 3, 2, 3, 4}));
          REQUIRE(
              result
              == action_digraph_helper::make<uint32_t>(
                  5, {{3, 3, 4}, {0, 1, 3}, {2, 2, 2}, {3, 3, 3}, {4, 4, 4}}));
          non_strictly_cyclic_count++;
        }
      }
    }
    REQUIRE(strictly_cyclic_count == 2);
    REQUIRE(non_strictly_cyclic_count == 1);
  }

  // Takes about 3 to 4 minutes
  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "047",
                          "rectangular_band(m, n) - m = 1 .. 5, n = 1 .. 5",
                          "[fail][sims1]") {
    // This doesn't fail it's just very extreme
    std::vector<std::array<size_t, 7>> left
        = {{0, 0, 0, 0, 0, 0},
           {0, 0, 0, 0, 0, 0},
           {0, 0, 6, 22, 94, 454, 2'430},
           {0, 0, 30, 205, 1'555, 12'880},
           {0, 0, 240, 4'065, 72'465, 1'353'390},
           {0, 0, 2'756, 148'772, 8'174'244, 456'876'004}};

    // Seems like the m,n-th entry of the table above is:
    // {m, n} ->  Sum([0 .. n], k -> Bell(m)^k*Stirling2(n, k));

    auto rg = ReportGuard(true);
    for (size_t m = 2; m <= 5; ++m) {
      for (size_t n = 2; n <= 6; ++n) {
        std::cout << std::string(72, '#') << "\n"
                  << "CASE m, n = " << m << ", " << n << "\n"
                  << std::string(72, '#') << std::endl;

        auto   p = make<Presentation<word_type>>(rectangular_band(m, n));
        Sims1_ S(congruence_kind::left);
        S.short_rules(p);
        REQUIRE(S.number_of_threads(4).number_of_congruences(m * n)
                == left[m][n]);
        Sims1_ T(congruence_kind::right);
        T.short_rules(p);
        REQUIRE(T.number_of_threads(4).number_of_congruences(m * n)
                == left[n][m]);
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "048",
                          "stellar_monoid(n) n = 3 .. 4",
                          "[fail][sims1][babbage]") {
    std::array<uint64_t, 10> const size      = {0, 0, 0, 16, 65};
    std::array<uint64_t, 10> const num_left  = {0, 0, 0, 1'550, 0};
    std::array<uint64_t, 10> const num_right = {0, 0, 0, 1'521, 0};

    for (size_t n = 3; n < 5; ++n) {
      auto p = make<Presentation<word_type>>(rook_monoid(n, 0));
      auto q = make<Presentation<word_type>>(stellar_monoid(n));
      p.rules.insert(p.rules.end(), q.rules.cbegin(), q.rules.cend());
      REQUIRE(p.alphabet().size() == n + 1);
      {
        Sims1_ S(congruence_kind::left);
        S.short_rules(p).number_of_threads(4);
        REQUIRE(S.number_of_congruences(size[n]) == num_left[n]);
      }
      {
        Sims1_ S(congruence_kind::right);
        S.short_rules(p).number_of_threads(4);
        REQUIRE(S.number_of_congruences(size[n]) == num_right[n]);
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "049",
                          "stylic_monoid(n) n = 3, 4",
                          "[fail][sims1]") {
    auto                           rg   = ReportGuard(true);
    std::array<uint64_t, 10> const size = {0, 0, 0, 14, 51};
    //               1505s
    std::array<uint64_t, 10> const num_left  = {0, 0, 0, 1'214, 1'429'447'174};
    std::array<uint64_t, 10> const num_right = {0, 0, 0, 1'214, 1'429'455'689};

    for (size_t n = 3; n < 5; ++n) {
      auto p = make<Presentation<word_type>>(stylic_monoid(n));
      {
        Sims1_ S(congruence_kind::right);
        S.short_rules(p).number_of_threads(4);
        REQUIRE(S.number_of_congruences(size[n]) == num_right[n]);
      }
      {
        Sims1_ S(congruence_kind::left);
        S.short_rules(p).number_of_threads(4);
        REQUIRE(S.number_of_congruences(size[n]) == num_left[n]);
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "050",
                          "(2, 3, 7)-triangle group - index 50",
                          "[extreme][sims1]") {
    auto                      rg = ReportGuard(true);
    Presentation<std::string> p;
    p.contains_empty_word(true);
    p.alphabet("xy");
    presentation::add_rule_and_check(p, "xx""");
    presentation::add_rule_and_check(p, "yyy""");
    presentation::add_rule_and_check(p, "xyxyxyxyxyxyxy""");
    Sims1_ S(congruence_kind::right);
    S.short_rules(p).number_of_threads(4);
    REQUIRE(S.number_of_congruences(50) == 75'971);
  }

  LIBSEMIGROUPS_TEST_CASE("Sims1",
                          "051",
                          "Heineken group - index 10",
                          "[extreme][sims1]") {
    auto                      rg = ReportGuard(true);
    Presentation<std::string> p;
    p.contains_empty_word(true);
    p.alphabet("xXyY");
    presentation::add_inverse_rules(p, "XxYy");
    presentation::add_rule_and_check(p, "yXYYxyYYxyyXYYxyyXyXYYxy""x");

    Presentation<std::string> q;
    q.alphabet("xXyY");
    presentation::add_rule_and_check(
        q, "YxyyXXYYxyxYxyyXYXyXYYxxyyXYXyXYYxyx""y");

    Sims1_ S(congruence_kind::right);
    S.short_rules(p).long_rules(q).number_of_threads(8);
    REQUIRE(S.number_of_congruences(10) == 1);
  }

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

--> maximum size reached

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

90%


¤ Dauer der Verarbeitung: 0.40 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.