//
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2019-2021 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/ >.
// The purpose of this file is to test the ToddCoxeter classes.
#include <algorithm>
// for is_sorted, copy, all_of
#include <array>
// for array
#include <chrono>
// for duration, milliseconds
#include <cstddef>
// for size_t
#include <fstream>
// for ofstream
#include <functional>
// for mem_fn
#include <iostream>
// for string, operator<<, ostream
#include <memory>
// for unique_ptr, shared_ptr
#include <string>
// for basic_string, operator==
#include <unordered_map>
// for operator!=, operator==
#include <unordered_set>
// for unordered_set
#include <utility>
// for pair
#include <vector>
// for vector, operator==, swap
#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
#include "catch.hpp" // for TEST_CASE
#include "test-main.hpp" // for LIBSEMIGROUPS_TEST_CASE
#include "libsemigroups/bmat8.hpp" // for BMat8
#include "libsemigroups/cong-intf.hpp" // for CongruenceInterface::class...
#include "libsemigroups/cong-wrap.hpp" // for CongruenceWrapper...
#include "libsemigroups/constants.hpp" // for operator==, operator!=
#include "libsemigroups/containers.hpp" // for DynamicArray2, DynamicArra...
#include "libsemigroups/fpsemi-examples.hpp" // for setup, RennerTypeDMonoid
#include "libsemigroups/fpsemi-intf.hpp" // for FpSemigroupInterface::rule...
#include "libsemigroups/fpsemi.hpp" // for FpSemigroup
#include "libsemigroups/froidure-pin-base.hpp" // for FroidurePinBase
#include "libsemigroups/froidure-pin.hpp" // for FroidurePin, FroidurePin<>...
#include "libsemigroups/iterator.hpp" // for ConstIteratorStateful, ope...
#include "libsemigroups/knuth-bendix.hpp" // for KnuthBendix
#include "libsemigroups/order.hpp" // for RecursivePathCompare, Lexi...
#include "libsemigroups/report.hpp" // for ReportGuard
#include "libsemigroups/string.hpp" // for operator<<, to_string
#include "libsemigroups/tce.hpp" // for TCE, operator<<, IncreaseD...
#include "libsemigroups/todd-coxeter.hpp" // for ToddCoxeter, operator|
#include "libsemigroups/transf.hpp" // for Transf, LeastTransf
#include "libsemigroups/types.hpp" // for word_type, relation_type
#include "libsemigroups/wislo.hpp" // for const_wislo_iterator, cbeg...
namespace libsemigroups {
struct LibsemigroupsException;
// Forward declaration
constexpr
bool REPORT =
false ;
congruence_kind constexpr twosided = congruence_kind::twosided;
congruence_kind constexpr left = congruence_kind::left;
congruence_kind constexpr right = congruence_kind::right;
using KnuthBendix = fpsemigroup::KnuthBendix;
using tc_order = congruence::ToddCoxeter::order;
using options = congruence::ToddCoxeter::options;
using fpsemigroup::author;
using fpsemigroup::make;
using fpsemigroup::setup;
using fpsemigroup::brauer_monoid;
using fpsemigroup::dual_symmetric_inverse_monoid;
using fpsemigroup::fibonacci_semigroup;
using fpsemigroup::full_transformation_monoid;
using fpsemigroup::orientation_preserving_monoid;
using fpsemigroup::orientation_reversing_monoid;
using fpsemigroup::partial_transformation_monoid;
using fpsemigroup::partition_monoid;
using fpsemigroup::rook_monoid;
using fpsemigroup::singular_brauer_monoid;
using fpsemigroup::stellar_monoid;
using fpsemigroup::stylic_monoid;
using fpsemigroup::symmetric_group;
using fpsemigroup::symmetric_inverse_monoid;
using fpsemigroup::temperley_lieb_monoid;
using fpsemigroup::uniform_block_bijection_monoid;
namespace {
// Test functions
void check_felsch(congruence::ToddCoxeter& var) {
SECTION(
"Felsch + no standardisation" ) {
var.strategy(options::strategy::felsch).standardize(
false );
}
SECTION(
"Felsch + standardisation" ) {
var.strategy(options::strategy::felsch).standardize(
true );
}
}
void check_felsch(fpsemigroup::ToddCoxeter& var) {
check_felsch(var.congruence());
}
void check_felsch_throws(congruence::ToddCoxeter& var) {
SECTION(
"Felsch (throws)" ) {
REQUIRE_THROWS_AS(var.strategy(options::strategy::felsch),
LibsemigroupsException);
}
}
void check_felsch_throws(fpsemigroup::ToddCoxeter& var) {
check_felsch_throws(var.congruence());
}
void check_hlt_no_save(congruence::ToddCoxeter& var) {
SECTION(
"HLT + no standardise + full lookahead + no save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
false ).lookahead(options::lookahead::full).save(
false );
}
SECTION(
"HLT + standardise + full lookahead + no save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
true ).lookahead(options::lookahead::full).save(
false );
}
SECTION(
"HLT + no standardise + partial lookahead + no save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
false )
.lookahead(options::lookahead::partial)
.save(
false );
}
SECTION(
"HLT + standardise + partial lookahead + no save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
true )
.lookahead(options::lookahead::partial)
.save(
false );
}
}
void check_hlt_no_save(fpsemigroup::ToddCoxeter& var) {
check_hlt_no_save(var.congruence());
}
void check_hlt_save(congruence::ToddCoxeter& var) {
SECTION(
"HLT + no standardise + full lookahead + save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
false ).lookahead(options::lookahead::full).save(
true );
}
SECTION(
"HLT + standardise + full lookahead + save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
true ).lookahead(options::lookahead::full).save(
true );
}
SECTION(
"HLT + no standardise + partial lookahead + save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
false )
.lookahead(options::lookahead::partial)
.save(
true );
}
SECTION(
"HLT + standardise + partial lookahead + save" ) {
var.strategy(options::strategy::hlt);
var.standardize(
true ).lookahead(options::lookahead::partial).save(
true );
}
}
void check_hlt_save_throws(congruence::ToddCoxeter& var) {
SECTION(
"HLT + save (throws)" ) {
REQUIRE_THROWS_AS(var.strategy(options::strategy::hlt).save(
true ),
LibsemigroupsException);
}
}
void check_hlt_save_throws(fpsemigroup::ToddCoxeter& var) {
check_hlt_save_throws(var.congruence());
}
void check_hlt(congruence::ToddCoxeter& var) {
check_hlt_no_save(var);
check_hlt_save(var);
}
void check_hlt(fpsemigroup::ToddCoxeter& var) {
check_hlt(var.congruence());
}
void check_random(congruence::ToddCoxeter& var) {
SECTION(
"random strategy" ) {
var.strategy(options::strategy::random);
}
}
void check_random(fpsemigroup::ToddCoxeter& var) {
check_random(var.congruence());
}
void check_Rc_style(congruence::ToddCoxeter& tc) {
SECTION(
"Rc style + full lookahead" ) {
tc.strategy(options::strategy::Rc).lookahead(options::lookahead::full);
tc.run();
}
SECTION(
"Rc style + partial lookahead" ) {
tc.strategy(options::strategy::Rc)
.lookahead(options::lookahead::partial);
tc.run();
}
}
void check_Rc_style(fpsemigroup::ToddCoxeter& tc) {
check_Rc_style(tc.congruence());
}
void check_Cr_style(congruence::ToddCoxeter& tc) {
SECTION(
"Cr style" ) {
tc.strategy(options::strategy::Cr);
tc.run();
}
}
void check_Cr_style(fpsemigroup::ToddCoxeter& tc) {
check_Cr_style(tc.congruence());
}
void check_R_over_C_style(congruence::ToddCoxeter& tc) {
SECTION(
"R/C style" ) {
tc.strategy(options::strategy::R_over_C);
tc.run();
}
}
void check_R_over_C_style(fpsemigroup::ToddCoxeter& tc) {
check_R_over_C_style(tc.congruence());
}
void check_CR_style(congruence::ToddCoxeter& tc) {
SECTION(
"CR style" ) {
tc.strategy(options::strategy::CR);
tc.run();
}
}
void check_CR_style(fpsemigroup::ToddCoxeter& tc) {
check_CR_style(tc.congruence());
}
// This is how the recursive words up to a given length M, and on an
// arbitrary finite alphabet are generated. On a single letter alphabet,
// this order is just increasing powers of the only generator:
//
// a < aa < aaa < aaaa < ... < aa...a (M times)
//
// With an n-letter alphabet A = {a_1, a_2, ..., a_n}, suppose we have
// already obtained all of the words W_{n - 1} containing {a_1, ..., a_{n
// - 1}}. Every word in W_{n - 1} is less than any word containing a_n,
// and the least word greater than every word in W_{n - 1} is a_n. Words
// greater than a_n are obtain in the follow way, where:
//
// x: is the maximum word in W_{n - 1}, this is constant, in the
// description
// that follows.
// u: the first word obtained in point (1), the first time it is applied
// after (2) has been applied, starting with u = a_{n - 1}.
// v: a word with one fewer letters than u, starting with the empty word.
// w: a word such that w < u, also starting with the empty word.
//
// 1. If v < x, then v is replaced by the next word in the order. If |uv|
// <=
// M, then the next word is uv. Otherwise, goto 1.
//
// 2. If v = x, then and there exists a word w' in the set of words
// obtained
// so far such that w' > w and |w'| <= M - 1, then replace w with w',
// replace u by wa_n, replace v by the empty word, and the next word is
// wa_n.
//
// If no such word w' exists, then we have enumerated all the required
// words, and we can stop.
//
// For example, if A = {a, b} and M = 4, then the initial elements in the
// order are:
//
// e < a < aa < aaa < aaaa (e is the empty word)
//
// Set b > aaaa. At this point, x = aaaa, u = b, v = e, w = e, and so
// (1) applies, v <- a, and since |uv| = ba <= 4 = M, the next word is
// ba. Repeatedly applying (1), until it fails to hold, we obtain the
// following:
//
// aaaa < b < ba < baa < baaa
//
// After defining baa < baaa, x = aaaa, u = b, v = aaaa, and w = e. Hence
// v = x, and so (2) applies. The next w' in the set of words so far
// enumerated is a, and |a| = 1 <= 3 = M - 1, and so w <- a, u <- ab, v <-
// e, and the next word is ab. We repeatedly apply (1), until it fails, to
// obtain
//
// baaa < ab < aba < abaa
//
// At which point u = b, v = aaaa = x, and w = a. Hence (2) applies, w <-
// aa, v <- e, u <- aab, and the next word is: aab. And so on ...
//
// The next function implements this order, returning the words on an
// n-letter alphabet of length up to M.
std::vector<word_type> recursive_path_words(size_t n, size_t M) {
std::vector<word_type> out;
size_t a =
0 ;
for (size_t i =
0 ; i < M; ++i) {
out.push_back(word_type(i +
1 , a));
}
a++;
int x = out.size();
int u = out.size();
int v = -
1 ;
// -1 is the empty word
int w = -
1 ;
// -1 is the empty word
out.push_back({a});
while (a < n) {
if (v < x -
1 ) {
do {
v++;
}
while (v < x && out[u].size() + out[v].size() > M);
if (v < x && out[u].size() + out[v].size() <= M) {
word_type nxt = out[u];
nxt.insert(nxt.end(), out[v].begin(), out[v].end());
out.push_back(nxt);
}
}
else {
do {
w++;
}
while (
static_cast <size_t>(w) < out.size()
&& out[w].size() +
1 > M);
if (
static_cast <size_t>(w) < out.size()) {
word_type nxt = out[w];
u = out.size();
v = -
1 ;
nxt.push_back(a);
out.push_back(nxt);
}
else {
a++;
if (a < n) {
x = out.size();
u = out.size();
v = -
1 ;
w = -
1 ;
out.push_back({a});
}
}
}
}
return out;
}
void output_gap_benchmark_file(std::string
const & fname,
congruence::ToddCoxeter& tc) {
std::ofstream file;
file.open(fname);
file <<
"local free, rules, R, S, T;\n" ;
file << tc.to_gap_string();
file <<
"R := RightMagmaCongruenceByGeneratingPairs(S, []);\n" ;
file <<
"T := CosetTableOfFpSemigroup(R);;\n" ;
file <<
"Assert(0, Length(T) = Size(GeneratorsOfSemigroup(S)));\n" ;
file <<
"Assert(0, Length(T[1]) - 1 = "
<< std::to_string(tc.number_of_classes()) <<
");\n" ;
file.close();
}
}
// namespace
namespace congruence {
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"000" ,
"small 2-sided congruence" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
1 ,
1 ,
1 ,
1 }, {
1 });
tc.add_pair({
0 ,
1 ,
0 ,
1 }, {
0 ,
0 });
REQUIRE(!tc.finished());
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
27 );
tc.shrink_to_fit();
auto words
= std::vector<word_type>(tc.cbegin_class(
1 ,
0 ,
10 ), tc.cend_class());
REQUIRE(words
== std::vector<word_type>({word_type({
1 }),
word_type({
1 ,
1 ,
1 ,
1 }),
word_type({
1 ,
1 ,
1 ,
1 ,
1 ,
1 ,
1 })}));
words = std::vector<word_type>(
tc.cbegin_class(word_type({
1 ,
1 ,
1 ,
1 }),
0 ,
10 ), tc.cend_class());
REQUIRE(words
== std::vector<word_type>({word_type({
1 }),
word_type({
1 ,
1 ,
1 ,
1 }),
word_type({
1 ,
1 ,
1 ,
1 ,
1 ,
1 ,
1 })}));
REQUIRE(tc.number_of_words(
1 ) == POSITIVE_INFINITY);
std::vector<size_t> class_sizes;
for (size_t i =
0 ; i < tc.number_of_classes(); ++i) {
class_sizes.push_back(tc.number_of_words(i));
}
REQUIRE(class_sizes
== std::vector<size_t>(tc.number_of_classes(),
size_t(POSITIVE_INFINITY)));
REQUIRE(tc.word_to_class_index(words[
0 ]) ==
1 );
REQUIRE(
std::all_of(words.cbegin(), words.cend(), [&tc](word_type
const & w) {
return tc.word_to_class_index(w) ==
1 ;
}));
// Too small for lookahead to kick in...
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"001" ,
"small 2-sided congruence" ,
"[no-valgrind][todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
// (a^3, a)
tc.add_pair({
0 }, {
1 ,
1 });
// (a, b^2)
REQUIRE(!tc.finished());
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
5 );
REQUIRE(tc.finished());
REQUIRE(!tc.is_standardized());
REQUIRE(tc.word_to_class_index({
0 ,
0 ,
1 })
== tc.word_to_class_index({
0 ,
0 ,
0 ,
0 ,
1 }));
REQUIRE(tc.word_to_class_index({
0 ,
1 ,
1 ,
0 ,
0 ,
1 })
== tc.word_to_class_index({
0 ,
0 ,
0 ,
0 ,
1 }));
REQUIRE(tc.word_to_class_index({
0 ,
0 ,
0 }) != tc.word_to_class_index({
1 }));
tc.standardize(tc_order::lex);
REQUIRE(tc.class_index_to_word(
0 ) == word_type({
0 }));
REQUIRE(tc.class_index_to_word(
1 ) == word_type({
0 ,
0 }));
REQUIRE(tc.class_index_to_word(
2 ) == word_type({
0 ,
0 ,
1 }));
REQUIRE(tc.class_index_to_word(
3 ) == word_type({
0 ,
0 ,
1 ,
0 }));
REQUIRE(tc.word_to_class_index(word_type({
0 ,
0 ,
0 ,
1 })) ==
3 );
REQUIRE(tc.class_index_to_word(
4 ) == word_type({
1 }));
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
0 )) ==
0 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
1 )) ==
1 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
2 )) ==
2 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
3 )) ==
3 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
4 )) ==
4 );
REQUIRE(tc.word_to_class_index({
0 ,
1 }) ==
3 );
REQUIRE(LexicographicalCompare<word_type>{}({
0 ,
0 ,
1 }, {
0 ,
1 }));
REQUIRE(std::is_sorted(tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
LexicographicalCompare<word_type>{}));
tc.standardize(tc_order::shortlex);
REQUIRE(std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cend_normal_forms())
== std::vector<word_type>({{
0 }, {
1 }, {
0 ,
0 }, {
0 ,
1 }, {
0 ,
0 ,
1 }}));
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
0 )) ==
0 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
1 )) ==
1 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
2 )) ==
2 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
3 )) ==
3 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
4 )) ==
4 );
REQUIRE(std::is_sorted(tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
ShortLexCompare<word_type>{}));
auto nf = std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cend_normal_forms());
REQUIRE(nf
== std::vector<word_type>({{
0 }, {
1 }, {
0 ,
0 }, {
0 ,
1 }, {
0 ,
0 ,
1 }}));
REQUIRE(std::all_of(nf.begin(), nf.end(), [&tc](word_type& w) {
return w == *tc.cbegin_class(w,
0 , w.size() +
1 );
}));
for (size_t i =
2 ; i <
6 ; ++i) {
for (size_t j =
2 ; j <
10 - i; ++j) {
auto v = std::vector<word_type>(
cbegin_wislo(i, {
0 }, word_type(j +
1 ,
0 )),
cend_wislo(i, {
0 }, word_type(j +
1 ,
0 )));
std::sort(v.begin(), v.end(), RecursivePathCompare<word_type>{});
REQUIRE(v == recursive_path_words(i, j));
}
}
tc.standardize(tc_order::recursive);
REQUIRE(tc.class_index_to_word(
0 ) == word_type({
0 }));
REQUIRE(tc.class_index_to_word(
1 ) == word_type({
0 ,
0 }));
REQUIRE(tc.class_index_to_word(
2 ) == word_type({
1 }));
REQUIRE(tc.class_index_to_word(
3 ) == word_type({
1 ,
0 }));
REQUIRE(tc.class_index_to_word(
4 ) == word_type({
1 ,
0 ,
0 }));
REQUIRE(std::is_sorted(tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
RecursivePathCompare<word_type>{}));
}
// Felsch is actually faster here!
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"002" ,
"Example 6.6 in Sims (see also KnuthBendix 013)" ,
"[todd-coxeter][standard]" ) {
using TCE = detail::TCE;
using FroidurePinTCE
= FroidurePin<TCE, FroidurePinTraits<TCE, TCE::Table>>;
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
4 );
tc.add_pair({
0 ,
0 }, {
0 });
tc.add_pair({
1 ,
0 }, {
1 });
tc.add_pair({
0 ,
1 }, {
1 });
tc.add_pair({
2 ,
0 }, {
2 });
tc.add_pair({
0 ,
2 }, {
2 });
tc.add_pair({
3 ,
0 }, {
3 });
tc.add_pair({
0 ,
3 }, {
3 });
tc.add_pair({
1 ,
1 }, {
0 });
tc.add_pair({
2 ,
3 }, {
0 });
tc.add_pair({
2 ,
2 ,
2 }, {
0 });
tc.add_pair({
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 }, {
0 });
tc.add_pair({
1 ,
2 ,
1 ,
3 ,
1 ,
2 ,
1 ,
3 ,
1 ,
2 ,
1 ,
3 ,
1 ,
2 ,
1 ,
3 ,
1 ,
2 ,
1 ,
3 ,
1 ,
2 ,
1 ,
3 ,
1 ,
2 ,
1 ,
3 ,
1 ,
2 ,
1 ,
3 },
{
0 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
10 '752);
REQUIRE(tc.complete());
REQUIRE(tc.compatible());
// Take a copy to test copy constructor
auto & S =
static_cast <FroidurePinTCE&>(*tc.quotient_froidure_pin());
auto T = S.copy_closure({S.generator(
0 )});
REQUIRE(T.size() == S.size());
REQUIRE(T.number_of_generators() == S.number_of_generators());
REQUIRE(S.size() ==
10 '752);
REQUIRE(S.number_of_idempotents() ==
1 );
for (size_t c =
0 ; c < tc.number_of_classes(); ++c) {
REQUIRE(tc.class_index_to_word(c) == S.factorisation(c));
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(c)) == c);
}
REQUIRE(tc.finished());
tc.standardize(tc_order::recursive);
REQUIRE(std::is_sorted(tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
RecursivePathCompare<word_type>{}));
REQUIRE(std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cbegin_normal_forms() +
10 )
== std::vector<word_type>({{{
0 },
{
1 },
{
2 },
{
2 ,
1 },
{
1 ,
2 },
{
1 ,
2 ,
1 },
{
2 ,
2 },
{
2 ,
2 ,
1 },
{
2 ,
1 ,
2 },
{
2 ,
1 ,
2 ,
1 }}}));
tc.standardize(tc_order::lex);
for (size_t c =
0 ; c < tc.number_of_classes(); ++c) {
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(c)) == c);
}
REQUIRE(std::is_sorted(tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
LexicographicalCompare<word_type>{}));
REQUIRE(std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cbegin_normal_forms() +
10 )
== std::vector<word_type>({{
0 },
{
0 ,
1 },
{
0 ,
1 ,
2 },
{
0 ,
1 ,
2 ,
1 },
{
0 ,
1 ,
2 ,
1 ,
2 },
{
0 ,
1 ,
2 ,
1 ,
2 ,
1 },
{
0 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 },
{
0 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 },
{
0 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 },
{
0 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 ,
2 ,
1 }}));
tc.standardize(tc_order::shortlex);
for (size_t c =
0 ; c < tc.number_of_classes(); ++c) {
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(c)) == c);
}
REQUIRE(std::is_sorted(tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
ShortLexCompare<word_type>{}));
REQUIRE(std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cbegin_normal_forms() +
10 )
== std::vector<word_type>({{
0 },
{
1 },
{
2 },
{
3 },
{
1 ,
2 },
{
1 ,
3 },
{
2 ,
1 },
{
3 ,
1 },
{
1 ,
2 ,
1 },
{
1 ,
3 ,
1 }}));
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"003" ,
"constructed from FroidurePin" ,
"[no-valgrind][todd-coxeter][quick][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
FroidurePin<BMat8> S(
{BMat8({{
0 ,
1 ,
0 ,
0 }, {
1 ,
0 ,
0 ,
0 }, {
0 ,
0 ,
1 ,
0 }, {
0 ,
0 ,
0 ,
1 }}),
BMat8({{
0 ,
1 ,
0 ,
0 }, {
0 ,
0 ,
1 ,
0 }, {
0 ,
0 ,
0 ,
1 }, {
1 ,
0 ,
0 ,
0 }}),
BMat8({{
1 ,
0 ,
0 ,
0 }, {
0 ,
1 ,
0 ,
0 }, {
0 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
0 ,
1 }}),
BMat8({{
1 ,
0 ,
0 ,
0 }, {
0 ,
1 ,
0 ,
0 }, {
0 ,
0 ,
1 ,
0 }, {
0 ,
0 ,
0 ,
0 }})});
ToddCoxeter tc(twosided, S);
tc.froidure_pin_policy(options::froidure_pin::use_relations);
tc.add_pair({
0 }, {
1 });
check_felsch(tc);
check_hlt(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
tc.random_interval(std::chrono::milliseconds(
100 ));
tc.lower_bound(
3 );
tc.run();
REQUIRE(tc.complete());
REQUIRE(tc.compatible());
REQUIRE(tc.number_of_classes() ==
3 );
// REQUIRE(tc.number_of_generators() == 4);
REQUIRE(tc.contains({
0 }, {
1 }));
tc.standardize(tc_order::shortlex);
REQUIRE(tc.contains({
0 }, {
1 }));
tc.shrink_to_fit();
REQUIRE(tc.contains({
0 }, {
1 }));
auto & T = *tc.quotient_froidure_pin();
REQUIRE(T.size() ==
3 );
REQUIRE(tc.class_index_to_word(
0 ) == T.factorisation(
0 ));
REQUIRE(tc.class_index_to_word(
1 ) == T.factorisation(
1 ));
REQUIRE(tc.class_index_to_word(
2 ) == T.factorisation(
2 ));
REQUIRE(tc.class_index_to_word(
0 ) == word_type({
0 }));
REQUIRE(tc.class_index_to_word(
1 ) == word_type({
2 }));
REQUIRE(tc.class_index_to_word(
2 ) == word_type({
0 ,
0 }));
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
0 )) ==
0 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
1 )) ==
1 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
2 )) ==
2 );
tc.standardize(tc_order::lex);
REQUIRE(tc.class_index_to_word(
0 ) == word_type({
0 }));
REQUIRE(tc.class_index_to_word(
1 ) == word_type({
0 ,
0 }));
REQUIRE(tc.class_index_to_word(
2 ) == word_type({
0 ,
0 ,
2 }));
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
0 )) ==
0 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
1 )) ==
1 );
REQUIRE(tc.word_to_class_index(tc.class_index_to_word(
2 )) ==
2 );
tc.standardize(tc_order::shortlex);
REQUIRE(tc.class_index_to_word(
0 ) == word_type({
0 }));
REQUIRE(tc.class_index_to_word(
1 ) == word_type({
2 }));
REQUIRE(tc.class_index_to_word(
2 ) == word_type({
0 ,
0 }));
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"004" ,
"2-sided congruence from FroidurePin" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
using Transf = LeastTransf<
5 >;
FroidurePin<Transf> S({Transf({
1 ,
3 ,
4 ,
2 ,
3 }), Transf({
3 ,
2 ,
1 ,
3 ,
3 })});
REQUIRE(S.size() ==
88 );
ToddCoxeter tc(twosided, S);
tc.froidure_pin_policy(options::froidure_pin::use_cayley_graph);
tc.add_pair(S.factorisation(Transf({
3 ,
4 ,
4 ,
4 ,
4 })),
S.factorisation(Transf({
3 ,
1 ,
3 ,
3 ,
3 })));
REQUIRE(!tc.finished());
tc.shrink_to_fit();
// does nothing
REQUIRE(!tc.finished());
tc.standardize(tc_order::none);
// does nothing
REQUIRE(!tc.finished());
check_hlt_no_save(tc);
check_hlt_save_throws(tc);
check_felsch_throws(tc);
check_random(tc);
REQUIRE(tc.number_of_classes() ==
21 );
tc.shrink_to_fit();
REQUIRE(tc.number_of_classes() ==
21 );
tc.standardize(tc_order::recursive);
auto w = std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cend_normal_forms());
REQUIRE(w.size() ==
21 );
REQUIRE(w
== std::vector<word_type>({{
0 },
{
0 ,
0 },
{
0 ,
0 ,
0 },
{
0 ,
0 ,
0 ,
0 },
{
1 },
{
1 ,
0 },
{
1 ,
0 ,
0 },
{
1 ,
0 ,
0 ,
0 },
{
0 ,
1 },
{
0 ,
1 ,
0 },
{
0 ,
1 ,
0 ,
0 },
{
0 ,
1 ,
0 ,
0 ,
0 },
{
0 ,
0 ,
1 },
{
1 ,
1 },
{
1 ,
1 ,
0 },
{
1 ,
1 ,
0 ,
0 },
{
1 ,
1 ,
0 ,
0 ,
0 },
{
0 ,
1 ,
1 },
{
0 ,
1 ,
1 ,
0 },
{
0 ,
1 ,
1 ,
0 ,
0 },
{
0 ,
1 ,
1 ,
0 ,
0 ,
0 }}));
REQUIRE(std::unique(w.begin(), w.end()) == w.end());
REQUIRE(std::is_sorted(tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
RecursivePathCompare<word_type>{}));
REQUIRE(std::all_of(
tc.cbegin_normal_forms(),
tc.cend_normal_forms(),
[&tc](word_type
const & ww) ->
bool {
return tc.class_index_to_word(tc.word_to_class_index(ww)) == ww;
}));
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"005" ,
"non-trivial two-sided from relations" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
3 );
tc.add_pair({
0 ,
1 }, {
1 ,
0 });
tc.add_pair({
0 ,
2 }, {
2 ,
2 });
tc.add_pair({
0 ,
2 }, {
0 });
tc.add_pair({
2 ,
2 }, {
0 });
tc.add_pair({
1 ,
2 }, {
1 ,
2 });
tc.add_pair({
1 ,
2 }, {
2 ,
2 });
tc.add_pair({
1 ,
2 ,
2 }, {
1 });
tc.add_pair({
1 ,
2 }, {
1 });
tc.add_pair({
2 ,
2 }, {
1 });
tc.add_pair({
0 }, {
1 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
2 );
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"006" ,
"small right cong. on free semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(right);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
0 }, {
1 ,
1 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
5 );
REQUIRE(tc.finished());
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"007" ,
"left cong. on free semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
ToddCoxeter tc(left);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
0 }, {
1 ,
1 });
tc.growth_factor(
1 .
5 );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(!tc.is_standardized());
REQUIRE(tc.word_to_class_index({
0 ,
0 ,
1 })
== tc.word_to_class_index({
0 ,
0 ,
0 ,
0 ,
1 }));
REQUIRE(tc.word_to_class_index({
0 ,
1 ,
1 ,
0 ,
0 ,
1 })
== tc.word_to_class_index({
0 ,
0 ,
0 ,
0 ,
1 }));
REQUIRE(tc.word_to_class_index({
1 })
!= tc.word_to_class_index({
0 ,
0 ,
0 ,
0 }));
REQUIRE(tc.word_to_class_index({
0 ,
0 ,
0 })
!= tc.word_to_class_index({
0 ,
0 ,
0 ,
0 }));
tc.standardize(tc_order::shortlex);
REQUIRE(tc.is_standardized());
}
{
ToddCoxeter tc(left);
REQUIRE_NOTHROW(ToddCoxeter(left, tc));
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"008" ,
"for small fp semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
// (a^3, a)
tc.add_pair({
0 }, {
1 ,
1 });
// (a, b^2)
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.word_to_class_index({
0 ,
0 ,
1 })
== tc.word_to_class_index({
0 ,
0 ,
0 ,
0 ,
1 }));
REQUIRE(tc.word_to_class_index({
0 ,
1 ,
1 ,
0 ,
0 ,
1 })
== tc.word_to_class_index({
0 ,
0 ,
0 ,
0 ,
1 }));
REQUIRE(tc.word_to_class_index({
0 ,
0 ,
0 }) != tc.word_to_class_index({
1 }));
REQUIRE(tc.word_to_class_index({
0 ,
0 ,
0 ,
0 }) < tc.number_of_classes());
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"009" ,
"2-sided cong. trans. semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
auto S = FroidurePin<Transf<>>(
{Transf<>({
1 ,
3 ,
4 ,
2 ,
3 }), Transf<>({
3 ,
2 ,
1 ,
3 ,
3 })});
REQUIRE(S.size() ==
88 );
REQUIRE(S.number_of_rules() ==
18 );
ToddCoxeter tc(twosided, S);
tc.froidure_pin_policy(options::froidure_pin::use_relations);
tc.add_pair(S.factorisation(Transf<>({
3 ,
4 ,
4 ,
4 ,
4 })),
S.factorisation(Transf<>({
3 ,
1 ,
3 ,
3 ,
3 })));
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
21 );
REQUIRE(tc.number_of_classes() ==
21 );
REQUIRE(tc.word_to_class_index(S.factorisation(Transf<>({
1 ,
3 ,
1 ,
3 ,
3 })))
== tc.word_to_class_index(
S.factorisation(Transf<>({
4 ,
2 ,
4 ,
4 ,
2 }))));
tc.standardize(tc_order::shortlex);
REQUIRE(tc.number_of_non_trivial_classes() ==
1 );
REQUIRE(tc.cbegin_ntc()->size() ==
68 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"010" ,
"left congruence on transformation semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
auto S = FroidurePin<Transf<>>(
{Transf<>({
1 ,
3 ,
4 ,
2 ,
3 }), Transf<>({
3 ,
2 ,
1 ,
3 ,
3 })});
REQUIRE(S.size() ==
88 );
REQUIRE(S.number_of_rules() ==
18 );
ToddCoxeter tc(left, S);
tc.froidure_pin_policy(options::froidure_pin::use_relations);
tc.add_pair(S.factorisation(Transf<>({
3 ,
4 ,
4 ,
4 ,
4 })),
S.factorisation(Transf<>({
3 ,
1 ,
3 ,
3 ,
3 })));
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
69 );
REQUIRE(tc.number_of_classes() ==
69 );
REQUIRE(tc.word_to_class_index(S.factorisation(Transf<>({
1 ,
3 ,
1 ,
3 ,
3 })))
!= tc.word_to_class_index(
S.factorisation(Transf<>({
4 ,
2 ,
4 ,
4 ,
2 }))));
tc.standardize(tc_order::shortlex);
REQUIRE(tc.number_of_non_trivial_classes() ==
1 );
REQUIRE(tc.cbegin_ntc()->size() ==
20 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"011" ,
"right cong. trans. semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
auto S = FroidurePin<Transf<>>(
{Transf<>({
1 ,
3 ,
4 ,
2 ,
3 }), Transf<>({
3 ,
2 ,
1 ,
3 ,
3 })});
REQUIRE(S.size() ==
88 );
REQUIRE(S.number_of_rules() ==
18 );
ToddCoxeter tc(right, S);
tc.froidure_pin_policy(options::froidure_pin::use_relations);
tc.add_pair(S.factorisation(Transf<>({
3 ,
4 ,
4 ,
4 ,
4 })),
S.factorisation(Transf<>({
3 ,
1 ,
3 ,
3 ,
3 })));
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
72 );
REQUIRE(tc.number_of_classes() ==
72 );
REQUIRE(tc.word_to_class_index(S.factorisation(Transf<>({
1 ,
3 ,
1 ,
3 ,
3 })))
!= tc.word_to_class_index(
S.factorisation(Transf<>({
4 ,
2 ,
4 ,
4 ,
2 }))));
REQUIRE(tc.word_to_class_index(S.factorisation(Transf<>({
1 ,
3 ,
3 ,
3 ,
3 })))
!= tc.word_to_class_index(
S.factorisation(Transf<>({
4 ,
2 ,
4 ,
4 ,
2 }))));
REQUIRE(tc.word_to_class_index(S.factorisation(Transf<>({
2 ,
4 ,
2 ,
2 ,
2 })))
== tc.word_to_class_index(
S.factorisation(Transf<>({
2 ,
3 ,
3 ,
3 ,
3 }))));
REQUIRE(tc.word_to_class_index(S.factorisation(Transf<>({
1 ,
3 ,
3 ,
3 ,
3 })))
!= tc.word_to_class_index(
S.factorisation(Transf<>({
2 ,
3 ,
3 ,
3 ,
3 }))));
tc.standardize(tc_order::shortlex);
REQUIRE(tc.number_of_non_trivial_classes() ==
4 );
std::vector<size_t> v(tc.number_of_non_trivial_classes(),
0 );
std::transform(tc.cbegin_ntc(),
tc.cend_ntc(),
v.begin(),
std::mem_fn(&std::vector<word_type>::size));
REQUIRE(std::count(v.cbegin(), v.cend(),
3 ) ==
1 );
REQUIRE(std::count(v.cbegin(), v.cend(),
5 ) ==
2 );
REQUIRE(std::count(v.cbegin(), v.cend(),
7 ) ==
1 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"012" ,
"trans. semigroup (size 88)" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
FroidurePin<Transf<>> S;
S.add_generator(Transf<>({
1 ,
3 ,
4 ,
2 ,
3 }));
S.add_generator(Transf<>({
3 ,
2 ,
1 ,
3 ,
3 }));
REQUIRE(S.size() ==
88 );
REQUIRE(S.number_of_rules() ==
18 );
REQUIRE(S.degree() ==
5 );
ToddCoxeter tc(twosided, S);
tc.froidure_pin_policy(options::froidure_pin::use_cayley_graph);
word_type w1, w2;
S.factorisation(w1, S.position(Transf<>({
3 ,
4 ,
4 ,
4 ,
4 })));
S.factorisation(w2, S.position(Transf<>({
3 ,
1 ,
3 ,
3 ,
3 })));
tc.add_pair(w1, w2);
check_hlt_no_save(tc);
check_hlt_save_throws(tc);
check_felsch_throws(tc);
check_random(tc);
REQUIRE(tc.number_of_classes() ==
21 );
REQUIRE(tc.number_of_classes() ==
21 );
word_type w3, w4;
S.factorisation(w3, S.position(Transf<>({
1 ,
3 ,
1 ,
3 ,
3 })));
S.factorisation(w4, S.position(Transf<>({
4 ,
2 ,
4 ,
4 ,
2 })));
REQUIRE(tc.word_to_class_index(w3) == tc.word_to_class_index(w4));
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"013" ,
"left cong. on trans. semigroup (size 88)" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
FroidurePin<Transf<>> S;
S.add_generator(Transf<>({
1 ,
3 ,
4 ,
2 ,
3 }));
S.add_generator(Transf<>({
3 ,
2 ,
1 ,
3 ,
3 }));
REQUIRE(S.size() ==
88 );
REQUIRE(S.degree() ==
5 );
word_type w1, w2;
S.factorisation(w1, S.position(Transf<>({
3 ,
4 ,
4 ,
4 ,
4 })));
S.factorisation(w2, S.position(Transf<>({
3 ,
1 ,
3 ,
3 ,
3 })));
ToddCoxeter tc(left, S);
tc.froidure_pin_policy(options::froidure_pin::use_relations);
tc.add_pair(w1, w2);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
69 );
REQUIRE(tc.number_of_classes() ==
69 );
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"014" ,
"right cong. on trans. semigroup (size 88)" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
FroidurePin<Transf<>> S;
S.add_generator(Transf<>({
1 ,
3 ,
4 ,
2 ,
3 }));
S.add_generator(Transf<>({
3 ,
2 ,
1 ,
3 ,
3 }));
REQUIRE(S.size() ==
88 );
REQUIRE(S.number_of_rules() ==
18 );
REQUIRE(S.degree() ==
5 );
word_type w1, w2;
S.factorisation(w1, S.position(Transf<>({
3 ,
4 ,
4 ,
4 ,
4 })));
S.factorisation(w2, S.position(Transf<>({
3 ,
1 ,
3 ,
3 ,
3 })));
ToddCoxeter tc(right, S);
tc.froidure_pin_policy(options::froidure_pin::use_relations);
tc.add_pair(w1, w2);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
72 );
REQUIRE(tc.number_of_classes() ==
72 );
word_type w3, w4, w5, w6;
S.factorisation(w3, S.position(Transf<>({
1 ,
3 ,
3 ,
3 ,
3 })));
S.factorisation(w4, S.position(Transf<>({
4 ,
2 ,
4 ,
4 ,
2 })));
S.factorisation(w5, S.position(Transf<>({
2 ,
4 ,
2 ,
2 ,
2 })));
S.factorisation(w6, S.position(Transf<>({
2 ,
3 ,
3 ,
3 ,
3 })));
REQUIRE(tc.word_to_class_index(w3) != tc.word_to_class_index(w4));
REQUIRE(tc.word_to_class_index(w5) == tc.word_to_class_index(w6));
REQUIRE(tc.word_to_class_index(w3) != tc.word_to_class_index(w6));
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"015" ,
"finite fp-semigroup, dihedral group of order 6" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
5 );
tc.add_pair({
0 ,
0 }, {
0 });
tc.add_pair({
0 ,
1 }, {
1 });
tc.add_pair({
1 ,
0 }, {
1 });
tc.add_pair({
0 ,
2 }, {
2 });
tc.add_pair({
2 ,
0 }, {
2 });
tc.add_pair({
0 ,
3 }, {
3 });
tc.add_pair({
3 ,
0 }, {
3 });
tc.add_pair({
0 ,
4 }, {
4 });
tc.add_pair({
4 ,
0 }, {
4 });
tc.add_pair({
1 ,
2 }, {
0 });
tc.add_pair({
2 ,
1 }, {
0 });
tc.add_pair({
3 ,
4 }, {
0 });
tc.add_pair({
4 ,
3 }, {
0 });
tc.add_pair({
2 ,
2 }, {
0 });
tc.add_pair({
1 ,
4 ,
2 ,
3 ,
3 }, {
0 });
tc.add_pair({
4 ,
4 ,
4 }, {
0 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
6 );
REQUIRE(tc.word_to_class_index({
1 }) == tc.word_to_class_index({
2 }));
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"016" ,
"finite fp-semigroup, size 16" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
4 );
tc.add_pair({
3 }, {
2 });
tc.add_pair({
0 ,
3 }, {
0 ,
2 });
tc.add_pair({
1 ,
1 }, {
1 });
tc.add_pair({
1 ,
3 }, {
1 ,
2 });
tc.add_pair({
2 ,
1 }, {
2 });
tc.add_pair({
2 ,
2 }, {
2 });
tc.add_pair({
2 ,
3 }, {
2 });
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
0 ,
0 ,
1 }, {
1 });
tc.add_pair({
0 ,
0 ,
2 }, {
2 });
tc.add_pair({
0 ,
1 ,
2 }, {
1 ,
2 });
tc.add_pair({
1 ,
0 ,
0 }, {
1 });
tc.add_pair({
1 ,
0 ,
2 }, {
0 ,
2 });
tc.add_pair({
2 ,
0 ,
0 }, {
2 });
tc.add_pair({
0 ,
1 ,
0 ,
1 }, {
1 ,
0 ,
1 });
tc.add_pair({
0 ,
2 ,
0 ,
2 }, {
2 ,
0 ,
2 });
tc.add_pair({
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 });
tc.add_pair({
1 ,
2 ,
0 ,
1 }, {
1 ,
0 ,
1 });
tc.add_pair({
1 ,
2 ,
0 ,
2 }, {
2 ,
0 ,
2 });
tc.add_pair({
2 ,
0 ,
1 ,
0 }, {
2 ,
0 ,
1 });
tc.add_pair({
2 ,
0 ,
2 ,
0 }, {
2 ,
0 ,
2 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
16 );
REQUIRE(tc.word_to_class_index({
2 }) == tc.word_to_class_index({
3 }));
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"017" ,
"finite fp-semigroup, size 16" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
11 );
tc.add_pair({
2 }, {
1 });
tc.add_pair({
4 }, {
3 });
tc.add_pair({
5 }, {
0 });
tc.add_pair({
6 }, {
3 });
tc.add_pair({
7 }, {
1 });
tc.add_pair({
8 }, {
3 });
tc.add_pair({
9 }, {
3 });
tc.add_pair({
10 }, {
0 });
tc.add_pair({
0 ,
2 }, {
0 ,
1 });
tc.add_pair({
0 ,
4 }, {
0 ,
3 });
tc.add_pair({
0 ,
5 }, {
0 ,
0 });
tc.add_pair({
0 ,
6 }, {
0 ,
3 });
tc.add_pair({
0 ,
7 }, {
0 ,
1 });
tc.add_pair({
0 ,
8 }, {
0 ,
3 });
tc.add_pair({
0 ,
9 }, {
0 ,
3 });
tc.add_pair({
0 ,
10 }, {
0 ,
0 });
tc.add_pair({
1 ,
1 }, {
1 });
tc.add_pair({
1 ,
2 }, {
1 });
tc.add_pair({
1 ,
4 }, {
1 ,
3 });
tc.add_pair({
1 ,
5 }, {
1 ,
0 });
tc.add_pair({
1 ,
6 }, {
1 ,
3 });
tc.add_pair({
1 ,
7 }, {
1 });
tc.add_pair({
1 ,
8 }, {
1 ,
3 });
tc.add_pair({
1 ,
9 }, {
1 ,
3 });
tc.add_pair({
1 ,
10 }, {
1 ,
0 });
tc.add_pair({
3 ,
1 }, {
3 });
tc.add_pair({
3 ,
2 }, {
3 });
tc.add_pair({
3 ,
3 }, {
3 });
tc.add_pair({
3 ,
4 }, {
3 });
tc.add_pair({
3 ,
5 }, {
3 ,
0 });
tc.add_pair({
3 ,
6 }, {
3 });
tc.add_pair({
3 ,
7 }, {
3 });
tc.add_pair({
3 ,
8 }, {
3 });
tc.add_pair({
3 ,
9 }, {
3 });
tc.add_pair({
3 ,
10 }, {
3 ,
0 });
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
0 ,
0 ,
1 }, {
1 });
tc.add_pair({
0 ,
0 ,
3 }, {
3 });
tc.add_pair({
0 ,
1 ,
3 }, {
1 ,
3 });
tc.add_pair({
1 ,
0 ,
0 }, {
1 });
tc.add_pair({
1 ,
0 ,
3 }, {
0 ,
3 });
tc.add_pair({
3 ,
0 ,
0 }, {
3 });
tc.add_pair({
0 ,
1 ,
0 ,
1 }, {
1 ,
0 ,
1 });
tc.add_pair({
0 ,
3 ,
0 ,
3 }, {
3 ,
0 ,
3 });
tc.add_pair({
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 });
tc.add_pair({
1 ,
3 ,
0 ,
1 }, {
1 ,
0 ,
1 });
tc.add_pair({
1 ,
3 ,
0 ,
3 }, {
3 ,
0 ,
3 });
tc.add_pair({
3 ,
0 ,
1 ,
0 }, {
3 ,
0 ,
1 });
tc.add_pair({
3 ,
0 ,
3 ,
0 }, {
3 ,
0 ,
3 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
16 );
REQUIRE(tc.word_to_class_index({
0 }) == tc.word_to_class_index({
5 }));
REQUIRE(tc.word_to_class_index({
0 }) == tc.word_to_class_index({
10 }));
REQUIRE(tc.word_to_class_index({
1 }) == tc.word_to_class_index({
2 }));
REQUIRE(tc.word_to_class_index({
1 }) == tc.word_to_class_index({
7 }));
REQUIRE(tc.word_to_class_index({
3 }) == tc.word_to_class_index({
4 }));
REQUIRE(tc.word_to_class_index({
3 }) == tc.word_to_class_index({
6 }));
REQUIRE(tc.word_to_class_index({
3 }) == tc.word_to_class_index({
8 }));
REQUIRE(tc.word_to_class_index({
3 }) == tc.word_to_class_index({
9 }));
tc.standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"018" ,
"test lookahead" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.next_lookahead(
10 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
1 ,
0 ,
0 }, {
1 ,
0 });
tc.add_pair({
1 ,
0 ,
1 ,
1 ,
1 }, {
1 ,
0 });
tc.add_pair({
1 ,
1 ,
1 ,
1 ,
1 }, {
1 ,
1 });
tc.add_pair({
1 ,
1 ,
0 ,
1 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
1 });
tc.add_pair({
0 ,
0 ,
1 ,
0 ,
1 ,
1 ,
0 }, {
0 ,
1 ,
0 ,
1 ,
1 ,
0 });
tc.add_pair({
0 ,
0 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
0 ,
1 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
0 ,
1 ,
0 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
1 ,
0 ,
1 ,
0 ,
1 ,
0 ,
1 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
1 ,
0 ,
1 ,
0 ,
1 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
1 });
tc.add_pair({
1 ,
0 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
1 ,
0 ,
1 });
tc.add_pair({
1 ,
1 ,
0 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
1 ,
1 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 });
tc.add_pair({
0 ,
0 ,
1 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
1 ,
1 ,
0 ,
1 ,
0 });
check_hlt(tc);
REQUIRE(tc.number_of_classes() ==
78 );
tc.standardize(tc_order::shortlex);
}
{
ToddCoxeter tc(left);
tc.set_number_of_generators(
2 );
tc.next_lookahead(
10 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
1 ,
0 ,
0 }, {
1 ,
0 });
tc.add_pair({
1 ,
0 ,
1 ,
1 ,
1 }, {
1 ,
0 });
tc.add_pair({
1 ,
1 ,
1 ,
1 ,
1 }, {
1 ,
1 });
tc.add_pair({
1 ,
1 ,
0 ,
1 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
1 });
tc.add_pair({
0 ,
0 ,
1 ,
0 ,
1 ,
1 ,
0 }, {
0 ,
1 ,
0 ,
1 ,
1 ,
0 });
tc.add_pair({
0 ,
0 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
0 ,
1 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
0 ,
1 ,
0 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
1 ,
0 ,
1 ,
0 ,
1 ,
0 ,
1 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
1 ,
0 ,
1 ,
0 ,
1 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
1 });
tc.add_pair({
1 ,
0 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
1 ,
0 ,
1 });
tc.add_pair({
1 ,
1 ,
0 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 ,
1 ,
0 });
tc.add_pair({
1 ,
1 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
0 ,
1 ,
0 });
tc.add_pair({
0 ,
0 ,
1 ,
1 ,
1 ,
0 ,
1 ,
0 }, {
1 ,
1 ,
1 ,
0 ,
1 ,
0 });
check_hlt(tc);
REQUIRE(tc.number_of_classes() ==
78 );
tc.standardize(tc_order::shortlex);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"019" ,
"non-trivial left cong. from semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
FroidurePin<Transf<>> S;
S.add_generator(Transf<>({
1 ,
3 ,
4 ,
2 ,
3 }));
S.add_generator(Transf<>({
3 ,
2 ,
1 ,
3 ,
3 }));
REQUIRE(S.size() ==
88 );
REQUIRE(S.degree() ==
5 );
word_type w1, w2;
S.factorisation(w1, S.position(Transf<>({
3 ,
4 ,
4 ,
4 ,
4 })));
S.factorisation(w2, S.position(Transf<>({
3 ,
1 ,
3 ,
3 ,
3 })));
ToddCoxeter tc(left, S);
tc.froidure_pin_policy(options::froidure_pin::use_cayley_graph);
tc.add_pair(w1, w2);
check_hlt_no_save(tc);
check_hlt_save_throws(tc);
check_felsch_throws(tc);
check_random(tc);
REQUIRE(tc.number_of_classes() ==
69 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"020" ,
"2-sided cong. on free semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
1 );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
REQUIRE(tc.contains({
0 ,
0 }, {
0 ,
0 }));
REQUIRE(!tc.contains({
0 ,
0 }, {
0 }));
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"021" ,
"calling run when obviously infinite" ,
"[todd-coxeter][quick]" ) {
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
5 );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
REQUIRE_THROWS_AS(tc.run(), LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"022" ,
"stellar_monoid S3" ,
"[todd-coxeter][quick][hivert]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
4 );
tc.add_pair({
3 ,
3 }, {
3 });
tc.add_pair({
0 ,
3 }, {
0 });
tc.add_pair({
3 ,
0 }, {
0 });
tc.add_pair({
1 ,
3 }, {
1 });
tc.add_pair({
3 ,
1 }, {
1 });
tc.add_pair({
2 ,
3 }, {
2 });
tc.add_pair({
3 ,
2 }, {
2 });
tc.add_pair({
0 ,
0 }, {
0 });
tc.add_pair({
1 ,
1 }, {
1 });
tc.add_pair({
2 ,
2 }, {
2 });
tc.add_pair({
0 ,
2 }, {
2 ,
0 });
tc.add_pair({
2 ,
0 }, {
0 ,
2 });
tc.add_pair({
1 ,
2 ,
1 }, {
2 ,
1 ,
2 });
tc.add_pair({
1 ,
0 ,
1 ,
0 }, {
0 ,
1 ,
0 ,
1 });
tc.add_pair({
1 ,
0 ,
1 ,
0 }, {
0 ,
1 ,
0 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
34 );
REQUIRE(tc.quotient_froidure_pin()->size() ==
34 );
using froidure_pin_type =
typename ToddCoxeter::froidure_pin_type;
using detail::TCE;
auto & S =
static_cast <froidure_pin_type&>(*tc.quotient_froidure_pin());
S.run();
std::vector<TCE> v(S.cbegin(), S.cend());
std::sort(v.begin(), v.end());
REQUIRE(v
== std::vector<TCE>({TCE(
1 ), TCE(
2 ), TCE(
3 ), TCE(
4 ), TCE(
5 ),
TCE(
6 ), TCE(
7 ), TCE(
8 ), TCE(
9 ), TCE(
10 ),
TCE(
11 ), TCE(
12 ), TCE(
13 ), TCE(
14 ), TCE(
15 ),
TCE(
16 ), TCE(
17 ), TCE(
18 ), TCE(
19 ), TCE(
20 ),
TCE(
21 ), TCE(
22 ), TCE(
23 ), TCE(
24 ), TCE(
25 ),
TCE(
26 ), TCE(
27 ), TCE(
28 ), TCE(
29 ), TCE(
30 ),
TCE(
31 ), TCE(
32 ), TCE(
33 ), TCE(
34 )}));
REQUIRE(std::vector<TCE>(S.cbegin_sorted(), S.cend_sorted())
== std::vector<TCE>({TCE(
1 ), TCE(
2 ), TCE(
3 ), TCE(
4 ), TCE(
5 ),
TCE(
6 ), TCE(
7 ), TCE(
8 ), TCE(
9 ), TCE(
10 ),
TCE(
11 ), TCE(
12 ), TCE(
13 ), TCE(
14 ), TCE(
15 ),
TCE(
16 ), TCE(
17 ), TCE(
18 ), TCE(
19 ), TCE(
20 ),
TCE(
21 ), TCE(
22 ), TCE(
23 ), TCE(
24 ), TCE(
25 ),
TCE(
26 ), TCE(
27 ), TCE(
28 ), TCE(
29 ), TCE(
30 ),
TCE(
31 ), TCE(
32 ), TCE(
33 ), TCE(
34 )}));
REQUIRE(detail::to_string(TCE(
1 )) ==
"1" );
REQUIRE_NOTHROW(IncreaseDegree<TCE>()(TCE(
1 ),
10 ));
std::ostringstream oss;
oss << TCE(
10 );
// Does not do anything visible
std::stringbuf buf;
std::ostream os(&buf);
os << TCE(
32 );
// Does not do anything visible
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"023" ,
"finite semigroup (size 5)" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
congruence::ToddCoxeter tc(left);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
// (a^3, a)
tc.add_pair({
0 }, {
1 ,
1 });
// (a, b^2)
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
5 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"024" ,
"exceptions" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
congruence::ToddCoxeter tc1(left);
tc1.set_number_of_generators(
2 );
tc1.add_pair({
0 ,
0 ,
0 }, {
0 });
tc1.add_pair({
0 }, {
1 ,
1 });
REQUIRE(tc1.number_of_classes() ==
5 );
REQUIRE_THROWS_AS(ToddCoxeter(right, tc1), LibsemigroupsException);
REQUIRE_THROWS_AS(ToddCoxeter(twosided, tc1), LibsemigroupsException);
ToddCoxeter tc2(left, tc1);
REQUIRE(!tc1.contains({
0 }, {
1 }));
tc2.add_pair({
0 }, {
1 });
check_hlt(tc2);
check_felsch(tc2);
check_random(tc2);
check_Rc_style(tc2);
check_R_over_C_style(tc2);
check_CR_style(tc2);
check_Cr_style(tc2);
REQUIRE(tc2.number_of_classes() ==
1 );
ToddCoxeter tc3(left);
tc3.set_number_of_generators(
2 );
tc3.add_pair({
0 ,
0 ,
0 }, {
0 });
tc3.add_pair({
0 }, {
1 ,
1 });
tc3.add_pair({
0 }, {
1 });
REQUIRE(tc3.number_of_classes() ==
1 );
}
{
congruence::ToddCoxeter tc1(right);
tc1.set_number_of_generators(
2 );
tc1.add_pair({
0 ,
0 ,
0 }, {
0 });
tc1.add_pair({
0 }, {
1 ,
1 });
REQUIRE(tc1.number_of_classes() ==
5 );
REQUIRE_THROWS_AS(ToddCoxeter(left, tc1), LibsemigroupsException);
REQUIRE_THROWS_AS(ToddCoxeter(twosided, tc1), LibsemigroupsException);
ToddCoxeter tc2(right, tc1);
REQUIRE(!tc1.contains({
0 }, {
1 }));
tc2.add_pair({
0 }, {
1 });
check_hlt(tc2);
check_felsch(tc2);
check_random(tc2);
check_Rc_style(tc2);
check_R_over_C_style(tc2);
check_CR_style(tc2);
check_Cr_style(tc2);
REQUIRE(tc2.number_of_classes() ==
1 );
ToddCoxeter tc3(right);
tc3.set_number_of_generators(
2 );
tc3.add_pair({
0 ,
0 ,
0 }, {
0 });
tc3.add_pair({
0 }, {
1 ,
1 });
tc3.add_pair({
0 }, {
1 });
REQUIRE(tc3.number_of_classes() ==
1 );
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"025" ,
"obviously infinite" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
congruence::ToddCoxeter tc(left);
tc.set_number_of_generators(
3 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
REQUIRE(tc.number_of_classes() == POSITIVE_INFINITY);
REQUIRE(!tc.is_quotient_obviously_finite());
}
{
congruence::ToddCoxeter tc(right);
tc.set_number_of_generators(
3 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
REQUIRE(tc.number_of_classes() == POSITIVE_INFINITY);
REQUIRE(!tc.is_quotient_obviously_finite());
}
{
congruence::ToddCoxeter tc(twosided);
tc.set_number_of_generators(
3 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
REQUIRE(tc.number_of_classes() == POSITIVE_INFINITY);
REQUIRE(!tc.is_quotient_obviously_finite());
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"026" ,
"exceptions" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
congruence::ToddCoxeter tc(right);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
0 }, {
1 ,
1 });
check_hlt(tc);
check_felsch(tc);
REQUIRE(tc.number_of_classes() ==
5 );
REQUIRE(tc.class_index_to_word(
0 ) == word_type({
0 }));
// This next one should throw
REQUIRE_THROWS_AS(tc.quotient_froidure_pin(), LibsemigroupsException);
}
{
congruence::ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 ,
0 }, {
0 });
tc.add_pair({
0 }, {
1 ,
1 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
5 );
REQUIRE(tc.class_index_to_word(
0 ) == word_type({
0 }));
REQUIRE(tc.class_index_to_word(
1 ) == word_type({
1 }));
REQUIRE(tc.class_index_to_word(
2 ) == word_type({
0 ,
0 }));
REQUIRE(tc.class_index_to_word(
3 ) == word_type({
0 ,
1 }));
REQUIRE(tc.class_index_to_word(
4 ) == word_type({
0 ,
0 ,
1 }));
REQUIRE_THROWS_AS(tc.class_index_to_word(
5 ), LibsemigroupsException);
REQUIRE_THROWS_AS(tc.class_index_to_word(
100 ), LibsemigroupsException);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"027" ,
"empty" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
congruence::ToddCoxeter tc(left);
REQUIRE(tc.empty());
tc.set_number_of_generators(
3 );
REQUIRE(tc.empty());
tc.add_pair({
0 }, {
2 });
REQUIRE(tc.empty());
tc.reserve(
100 );
tc.reserve(
200 );
REQUIRE(tc.empty());
}
{
FroidurePin<BMat8> S(
{BMat8({{
0 ,
1 ,
0 ,
0 }, {
1 ,
0 ,
0 ,
0 }, {
0 ,
0 ,
1 ,
0 }, {
0 ,
0 ,
0 ,
1 }})});
ToddCoxeter tc(twosided, S);
REQUIRE(tc.empty());
tc.add_pair({
0 }, {
0 ,
0 });
REQUIRE(tc.empty());
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"028" ,
"congruence of fpsemigroup::ToddCoxeter" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
fpsemigroup::ToddCoxeter tc1;
tc1.set_alphabet(
"ab" );
tc1.add_rule(
"aaa" ,
"a" );
tc1.add_rule(
"a" ,
"bb" );
REQUIRE(tc1.size() ==
5 );
congruence::ToddCoxeter tc2(left, tc1);
REQUIRE(tc2.empty());
tc2.add_pair({
0 }, {
1 });
REQUIRE_THROWS_AS(tc2.add_pair({
0 }, {
2 }), LibsemigroupsException);
check_hlt_no_save(tc2);
check_hlt_save_throws(tc2);
check_felsch_throws(tc2);
check_random(tc2);
REQUIRE(tc2.number_of_classes() ==
1 );
}
{
fpsemigroup::ToddCoxeter tc1;
tc1.set_alphabet(
"ab" );
tc1.add_rule(
"aaa" ,
"a" );
tc1.add_rule(
"a" ,
"bb" );
congruence::ToddCoxeter tc2(left, tc1);
tc2.add_pair({
0 }, {
1 });
check_hlt(tc2);
check_felsch(tc2);
check_random(tc2);
check_Rc_style(tc2);
check_R_over_C_style(tc2);
check_CR_style(tc2);
check_Cr_style(tc2);
REQUIRE(!tc2.empty());
REQUIRE_THROWS_AS(tc2.add_pair({
0 }, {
2 }), LibsemigroupsException);
REQUIRE(tc2.number_of_classes() ==
1 );
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"029" ,
"!KnuthBendix.started()" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
fpsemigroup::KnuthBendix kb;
kb.set_alphabet(
"abB" );
kb.add_rule(
"bb" ,
"B" );
kb.add_rule(
"BaB" ,
"aba" );
REQUIRE(!kb.confluent());
REQUIRE(!kb.started());
std::unique_ptr<ToddCoxeter> tc = nullptr;
SECTION(
"2-sided" ) {
tc = std::make_unique<ToddCoxeter>(twosided, kb);
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
// Don't use the other check_* functions because they run to avoid an
// issue with fpsemigroup::ToddCoxeter.
}
SECTION(
"left" ) {
tc = std::make_unique<ToddCoxeter>(left, kb);
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
// Don't use the other check_* functions because they run to avoid an
// issue with fpsemigroup::ToddCoxeter.
}
SECTION(
"right" ) {
tc = std::make_unique<ToddCoxeter>(left, kb);
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
// Don't use the other check_* functions because they run to avoid an
// issue with fpsemigroup::ToddCoxeter.
}
REQUIRE(!tc->has_parent_froidure_pin());
tc->add_pair({
1 }, {
2 });
REQUIRE(tc->is_quotient_obviously_infinite());
REQUIRE(tc->number_of_classes() == POSITIVE_INFINITY);
REQUIRE(std::vector<relation_type>(tc->cbegin_generating_pairs(),
tc->cend_generating_pairs())
== std::vector<relation_type>(
{{{
1 ,
1 }, {
2 }}, {{
2 ,
0 ,
2 }, {
0 ,
1 ,
0 }}, {{
1 }, {
2 }}}));
REQUIRE(!tc->finished());
REQUIRE(!tc->started());
tc->add_pair({
1 }, {
0 });
REQUIRE(!tc->is_quotient_obviously_infinite());
REQUIRE(tc->number_of_classes() ==
1 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"030" ,
"KnuthBendix.finished()" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
fpsemigroup::KnuthBendix kb;
kb.set_alphabet(
"abB" );
kb.add_rule(
"bb" ,
"B" );
kb.add_rule(
"BaB" ,
"aba" );
REQUIRE(!kb.confluent());
kb.run();
REQUIRE(kb.confluent());
REQUIRE(kb.number_of_active_rules() ==
6 );
REQUIRE(kb.finished());
std::unique_ptr<ToddCoxeter> tc = nullptr;
SECTION(
"2-sided" ) {
tc = std::make_unique<ToddCoxeter>(twosided, kb);
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
// Don't use the other check_* functions because they run to avoid an
// issue with fpsemigroup::ToddCoxeter.
}
SECTION(
"left" ) {
tc = std::make_unique<ToddCoxeter>(left, kb);
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
// Don't use the other check_* functions because they run to avoid an
// issue with fpsemigroup::ToddCoxeter.
}
SECTION(
"right" ) {
tc = std::make_unique<ToddCoxeter>(right, kb);
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
// Don't use the other check_* functions because they run to avoid an
// issue with fpsemigroup::ToddCoxeter.
}
REQUIRE(tc->has_parent_froidure_pin());
tc->add_pair({
1 }, {
2 });
REQUIRE(tc->is_quotient_obviously_infinite());
REQUIRE(tc->number_of_classes() == POSITIVE_INFINITY);
REQUIRE(std::vector<relation_type>(tc->cbegin_generating_pairs(),
tc->cend_generating_pairs())
== std::vector<relation_type>(
{{{
1 ,
1 }, {
2 }}, {{
2 ,
0 ,
2 }, {
0 ,
1 ,
0 }}, {{
1 }, {
2 }}}));
tc->add_pair({
1 }, {
0 });
REQUIRE(!tc->is_quotient_obviously_infinite());
REQUIRE(tc->number_of_classes() ==
1 );
if (tc->kind() == twosided) {
REQUIRE(tc->quotient_froidure_pin()->size() ==
1 );
}
else {
REQUIRE_THROWS_AS(tc->quotient_froidure_pin(), LibsemigroupsException);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"031" ,
"KnuthBendix.finished()" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
fpsemigroup::KnuthBendix kb;
kb.set_alphabet(
"abB" );
kb.add_rule(
"bb" ,
"B" );
kb.add_rule(
"BaB" ,
"aba" );
kb.add_rule(
"a" ,
"b" );
kb.add_rule(
"b" ,
"B" );
REQUIRE(kb.confluent());
kb.run();
REQUIRE(kb.confluent());
REQUIRE(kb.number_of_active_rules() ==
3 );
REQUIRE(kb.size() ==
1 );
REQUIRE(kb.is_obviously_finite());
REQUIRE(kb.finished());
std::unique_ptr<ToddCoxeter> tc = nullptr;
SECTION(
"2-sided" ) {
tc = std::make_unique<ToddCoxeter>(twosided, kb);
tc->add_pair({
1 }, {
2 });
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
check_Rc_style(*tc);
check_R_over_C_style(*tc);
check_CR_style(*tc);
check_Cr_style(*tc);
}
SECTION(
"left" ) {
tc = std::make_unique<ToddCoxeter>(left, kb);
tc->add_pair({
1 }, {
2 });
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
check_Rc_style(*tc);
check_R_over_C_style(*tc);
check_CR_style(*tc);
check_Cr_style(*tc);
}
SECTION(
"right" ) {
tc = std::make_unique<ToddCoxeter>(left, kb);
tc->add_pair({
1 }, {
2 });
check_hlt(*tc);
check_felsch(*tc);
check_random(*tc);
check_Rc_style(*tc);
check_R_over_C_style(*tc);
check_CR_style(*tc);
check_Cr_style(*tc);
}
REQUIRE(tc->has_parent_froidure_pin());
REQUIRE(tc->number_of_classes() ==
1 );
if (tc->kind() == twosided) {
REQUIRE(tc->quotient_froidure_pin()->size() ==
1 );
}
else {
REQUIRE_THROWS_AS(tc->quotient_froidure_pin(), LibsemigroupsException);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"032" ,
"prefill" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
detail::DynamicArray2<ToddCoxeter::class_index_type> rv(
2 ,
1 );
REQUIRE(rv.number_of_cols() ==
2 );
REQUIRE(rv.number_of_rows() ==
1 );
{
ToddCoxeter tc(twosided);
// prefill before number_of_generators are set
REQUIRE_THROWS_AS(tc.prefill(rv), LibsemigroupsException);
tc.set_number_of_generators(
3 );
// prefill where number_of_generators != number_of_cols of rv
REQUIRE_THROWS_AS(tc.prefill(rv), LibsemigroupsException);
}
{
ToddCoxeter tc(left);
tc.set_number_of_generators(
2 );
rv.set(
0 ,
0 ,
0 );
rv.set(
0 ,
1 ,
1 );
// prefill with too few rows
REQUIRE_THROWS_AS(tc.prefill(rv), LibsemigroupsException);
rv.add_rows(
1 );
REQUIRE(rv.number_of_rows() ==
2 );
rv.set(
1 ,
0 , UNDEFINED);
rv.set(
1 ,
1 , UNDEFINED);
// prefill with bad value (0, 0)
REQUIRE_THROWS_AS(tc.prefill(rv), LibsemigroupsException);
rv.set(
0 ,
0 ,
2 );
// prefill with bad value (0, 0)
REQUIRE_THROWS_AS(tc.prefill(rv), LibsemigroupsException);
rv.set(
0 ,
0 ,
1 );
// UNDEFINED is not allowed
REQUIRE_THROWS_AS(tc.prefill(rv), LibsemigroupsException);
rv.set(
1 ,
0 ,
1 );
rv.set(
1 ,
1 ,
1 );
tc.prefill(rv);
}
{
detail::DynamicArray2<ToddCoxeter::class_index_type> rv2(
2 ,
0 );
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
REQUIRE_THROWS_AS(tc.prefill(rv2), LibsemigroupsException);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"033" ,
"congruence of ToddCoxeter" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc1(twosided);
tc1.set_number_of_generators(
2 );
tc1.add_pair({
0 ,
0 ,
0 }, {
0 });
tc1.add_pair({
0 }, {
1 ,
1 });
REQUIRE(tc1.number_of_classes() ==
5 );
ToddCoxeter tc2(left, tc1);
tc2.next_lookahead(
1 );
tc2.report_every(
1 );
REQUIRE(!tc2.empty());
check_hlt(tc2);
check_random(tc2);
tc2.add_pair({
0 }, {
0 ,
0 });
REQUIRE(tc2.number_of_classes() ==
3 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"034" ,
"congruence of ToddCoxeter" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
using Transf = LeastTransf<
5 >;
FroidurePin<Transf> S({Transf({
1 ,
3 ,
4 ,
2 ,
3 }), Transf({
3 ,
2 ,
1 ,
3 ,
3 })});
REQUIRE(S.size() ==
88 );
REQUIRE(S.number_of_rules() ==
18 );
ToddCoxeter tc(twosided, S);
tc.froidure_pin_policy(options::froidure_pin::none);
tc.set_number_of_generators(
2 );
check_hlt_no_save(tc);
check_hlt_save_throws(tc);
check_felsch_throws(tc);
check_random(tc);
tc.add_pair({
0 }, {
1 ,
1 });
REQUIRE(tc.number_of_classes() ==
1 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"035" ,
"congruence on FpSemigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
FpSemigroup S;
S.set_alphabet(
"abe" );
S.set_identity(
"e" );
S.add_rule(
"abb" ,
"bb" );
S.add_rule(
"bbb" ,
"bb" );
S.add_rule(
"aaaa" ,
"a" );
S.add_rule(
"baab" ,
"bb" );
S.add_rule(
"baaab" ,
"b" );
S.add_rule(
"babab" ,
"b" );
S.add_rule(
"bbaaa" ,
"bb" );
S.add_rule(
"bbaba" ,
"bbaa" );
REQUIRE(S.knuth_bendix()->confluent());
REQUIRE(S.knuth_bendix()->number_of_rules() ==
13 );
ToddCoxeter tc(left, *S.knuth_bendix());
tc.add_pair({
0 }, {
1 ,
1 ,
1 });
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
2 );
REQUIRE(std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cend_normal_forms())
== std::vector<word_type>({{
0 }, {
2 }}));
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"036" ,
"exceptions" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
using Transf = LeastTransf<
5 >;
FroidurePin<Transf> S({Transf({
1 ,
3 ,
4 ,
2 ,
3 }), Transf({
3 ,
2 ,
1 ,
3 ,
3 })});
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 }, {
1 });
tc.add_pair({
0 ,
0 }, {
0 });
REQUIRE(tc.number_of_classes() ==
1 );
REQUIRE_THROWS_AS(tc.prefill(S.right_cayley_graph()),
LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"037" ,
"copy constructor" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 }, {
1 });
tc.add_pair({
0 ,
0 }, {
0 });
tc.strategy(options::strategy::felsch);
REQUIRE(tc.strategy() == options::strategy::felsch);
REQUIRE(!tc.complete());
REQUIRE(tc.compatible());
REQUIRE(tc.number_of_classes() ==
1 );
REQUIRE(std::vector<word_type>(tc.cbegin_normal_forms(),
tc.cend_normal_forms())
== std::vector<word_type>(
1 , {
0 }));
REQUIRE(tc.complete());
REQUIRE(tc.compatible());
ToddCoxeter copy(tc);
REQUIRE(copy.number_of_generators() ==
2 );
REQUIRE(copy.number_of_generating_pairs() ==
2 );
REQUIRE(copy.finished());
REQUIRE(copy.number_of_classes() ==
1 );
REQUIRE(copy.froidure_pin_policy() == options::froidure_pin::none);
REQUIRE(copy.complete());
REQUIRE(copy.compatible());
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"038" ,
"simplify" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
2 );
tc.add_pair({
0 ,
0 }, {
1 });
tc.add_pair({
0 ,
0 }, {
0 });
tc.add_pair({
0 ,
1 ,
0 }, {
0 ,
0 });
tc.add_pair({
0 ,
1 ,
0 ,
1 }, {
0 ,
1 ,
0 });
tc.simplify();
REQUIRE(tc.number_of_generating_pairs() ==
4 );
REQUIRE(tc.number_of_classes() ==
1 );
std::vector<word_type> result(tc.cbegin_relations(), tc.cend_relations());
std::sort(result.begin(), result.end());
REQUIRE(result
== std::vector<word_type>(
{{
0 }, {
0 }, {
0 }, {
0 }, {
0 ,
0 }, {
0 ,
1 ,
0 }, {
0 ,
1 ,
0 ,
1 }, {
1 }}));
ToddCoxeter tc2(right, tc);
tc2.add_pair({
0 ,
0 }, {
1 });
tc2.add_pair({
0 ,
0 }, {
0 });
tc2.add_pair({
0 ,
1 ,
0 }, {
0 ,
0 });
tc2.add_pair({
0 ,
1 ,
0 ,
1 }, {
0 ,
1 ,
0 });
REQUIRE(tc2.felsch_tree_height() ==
4 );
REQUIRE(std::equal(tc.cbegin_relations(),
tc.cend_relations(),
tc2.cbegin_relations(),
tc2.cend_relations()));
REQUIRE(std::vector<word_type>(tc2.cbegin_extra(), tc2.cend_extra())
== std::vector<word_type>({{
0 ,
0 },
{
1 },
{
0 ,
0 },
{
0 },
{
0 ,
1 ,
0 },
{
0 ,
0 },
{
0 ,
1 ,
0 ,
1 },
{
0 ,
1 ,
0 }}));
tc2.simplify();
REQUIRE(
std::vector<word_type>(tc2.cbegin_extra(), tc2.cend_extra()).empty());
REQUIRE(tc2.felsch_tree_height() ==
4 );
REQUIRE(tc2.number_of_classes() ==
1 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"039" ,
"stylic_monoid" ,
"[todd-coxeter][quick][no-coverage][no-valgrind]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
9 );
for (
auto const & w : stylic_monoid(
9 )) {
tc.add_pair(w.first, w.second);
}
tc.strategy(options::strategy::random);
REQUIRE_THROWS_AS(tc.run_for(std::chrono::milliseconds(
100 )),
LibsemigroupsException);
tc.remove_duplicate_generating_pairs()
.sort_generating_pairs()
.strategy(options::strategy::hlt)
.lookahead(options::lookahead::partial | options::lookahead::hlt);
REQUIRE(tc.number_of_classes() ==
115 '974);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"040" ,
"fibonacci_semigroup(4, 6)" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard();
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
6 );
for (
auto const & w : fibonacci_semigroup(
4 ,
6 )) {
tc.add_pair(w.first, w.second);
}
tc.strategy(options::strategy::felsch);
REQUIRE(tc.number_of_classes() ==
0 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"041" ,
"some finite classes" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
1 );
REQUIRE(tc.number_of_classes() == POSITIVE_INFINITY);
tc.add_pair({
0 ,
0 ,
0 ,
0 ,
0 ,
0 }, {
0 ,
0 ,
0 ,
0 });
tc.add_pair({
0 ,
0 ,
0 ,
0 ,
0 ,
0 }, {
0 ,
0 ,
0 ,
0 });
tc.add_pair({
0 ,
0 ,
0 ,
0 ,
0 ,
0 }, {
0 ,
0 ,
0 ,
0 });
tc.strategy(options::strategy::random)
.remove_duplicate_generating_pairs()
.standardize(
true );
REQUIRE(!tc.compatible());
REQUIRE_THROWS_AS(tc.run_for(std::chrono::microseconds(
1 )),
LibsemigroupsException);
tc.strategy(options::strategy::CR);
size_t x =
0 ;
REQUIRE_THROWS_AS(tc.run_until([&x] {
return x >
4 ; }),
LibsemigroupsException);
tc.lower_bound(
100 )
.use_relations_in_extra(
true )
.deduction_policy(options::deductions::v1
| options::deductions::unlimited)
.restandardize(
true )
.max_preferred_defs(
0 );
REQUIRE_THROWS_AS(tc.hlt_defs(
0 ), LibsemigroupsException);
REQUIRE_THROWS_AS(tc.f_defs(
0 ), LibsemigroupsException);
tc.hlt_defs(
10 )
.f_defs(
10 )
.lookahead_growth_factor(
3 .
0 )
.lookahead_growth_threshold(
100 '000)
.large_collapse(
1 );
REQUIRE_THROWS_AS(tc.lookahead_growth_factor(
0 .
1 ),
LibsemigroupsException);
REQUIRE(tc.random_interval() == std::chrono::milliseconds(
200 ));
REQUIRE(tc.felsch_tree_height() ==
6 );
REQUIRE(tc.number_of_classes() ==
5 );
REQUIRE(tc.number_of_words(
0 ) ==
1 );
REQUIRE(tc.number_of_words(
1 ) ==
1 );
REQUIRE(tc.number_of_words(
2 ) ==
1 );
REQUIRE(tc.number_of_words(
3 ) == POSITIVE_INFINITY);
REQUIRE(tc.number_of_words(
4 ) == POSITIVE_INFINITY);
REQUIRE(tc.standardization_order() == ToddCoxeter::order::none);
REQUIRE(tc.felsch_tree_number_of_nodes() ==
7 );
REQUIRE_THROWS_AS(tc.remove_duplicate_generating_pairs(),
LibsemigroupsException);
ToddCoxeter tc2(left, tc);
tc2.add_pair({
0 ,
0 }, {
0 });
tc2.add_pair({
0 ,
0 }, {
0 });
tc2.remove_duplicate_generating_pairs();
// Uses CongruenceInterface's generating pairs
REQUIRE(tc2.number_of_generating_pairs() ==
2 );
ToddCoxeter tc3(twosided);
tc3.set_number_of_generators(
1 );
REQUIRE(tc3.is_non_trivial() == tril::
TRUE );
tc3.add_pair({
0 ,
0 }, {
0 });
REQUIRE(tc3.is_non_trivial() == tril::unknown);
REQUIRE(tc3.number_of_classes() ==
1 );
REQUIRE(tc3.is_non_trivial() == tril::
FALSE );
REQUIRE(!tc.settings_string().empty());
REQUIRE(!tc3.settings_string().empty());
REQUIRE(!tc.stats_string().empty());
}
// Takes about 6m
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"042" ,
"symmetric_group(10, Moore)" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard(
true );
auto s = symmetric_group(
10 , author::Moore);
for (
auto & rel : s) {
if (rel.first.empty()) {
rel.first = {
2 };
}
if (rel.second.empty()) {
rel.second = {
2 };
}
}
auto p = make<Presentation<word_type>>(s);
p.alphabet(
3 );
presentation::add_identity_rules(p,
2 );
p.validate();
ToddCoxeter tc(twosided);
tc.set_number_of_generators(
3 );
for (size_t i =
0 ; i < p.rules.size() -
1 ; i +=
2 ) {
tc.add_pair(p.rules[i], p.rules[i +
1 ]);
}
REQUIRE(tc.number_of_classes() ==
3 '628' 800 );
std::cout << tc.stats_string();
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"043" ,
"symmetric_group(7, Coxeter + Moser)" ,
"[todd-coxeter][quick][no-valgrind]" ) {
auto rg = ReportGuard(REPORT);
size_t n =
7 ;
auto s = symmetric_group(n, author::Coxeter + author::Moser);
for (
auto & rel : s) {
if (rel.first.empty()) {
rel.first = {n -
1 };
}
if (rel.second.empty()) {
rel.second = {n -
1 };
}
}
auto p = make<Presentation<word_type>>(s);
p.alphabet(n);
presentation::add_identity_rules(p, n -
1 );
p.validate();
ToddCoxeter tc(twosided);
tc.set_number_of_generators(n);
for (size_t i =
0 ; i < p.rules.size() -
1 ; i +=
2 ) {
tc.add_pair(p.rules[i], p.rules[i +
1 ]);
}
tc.run_for(std::chrono::microseconds(
1 ));
REQUIRE(tc.is_non_trivial() == tril::
TRUE );
REQUIRE(!tc.finished());
tc.standardize(ToddCoxeter::order::shortlex);
tc.standardize(ToddCoxeter::order::none);
tc.strategy(options::strategy::CR).f_defs(
100 );
REQUIRE(tc.number_of_classes() ==
5 '040);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"116" ,
"symmetric_group(7, Burnside + Miller)" ,
"[todd-coxeter][quick][no-valgrind]" ) {
auto rg = ReportGuard(REPORT);
size_t n =
7 ;
auto s = symmetric_group(n, author::Burnside + author::Miller);
for (
auto & rel : s) {
if (rel.first.empty()) {
rel.first = {n -
1 };
}
if (rel.second.empty()) {
rel.second = {n -
1 };
}
}
auto p = make<Presentation<word_type>>(s);
p.alphabet(n);
presentation::add_identity_rules(p, n -
1 );
p.validate();
ToddCoxeter tc(twosided);
tc.set_number_of_generators(n);
for (size_t i =
0 ; i < p.rules.size() -
1 ; i +=
2 ) {
tc.add_pair(p.rules[i], p.rules[i +
1 ]);
}
REQUIRE(tc.number_of_classes() ==
5 '040);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"044" ,
"Option exceptions" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
REQUIRE_THROWS_AS(options::deductions::unlimited
| options::deductions::unlimited,
LibsemigroupsException);
REQUIRE_THROWS_AS(options::deductions::v1 | options::deductions::v2,
LibsemigroupsException);
REQUIRE_THROWS_AS(options::lookahead::hlt | options::lookahead::hlt,
LibsemigroupsException);
REQUIRE_THROWS_AS(options::lookahead::hlt | options::lookahead::felsch,
LibsemigroupsException);
REQUIRE_THROWS_AS(options::lookahead::full | options::lookahead::partial,
LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"045" ,
"Options operator<<" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
ToddCoxeter tc(twosided);
tc.strategy(options::strategy::hlt);
tc.settings_string();
tc.strategy(options::strategy::felsch);
tc.settings_string();
tc.strategy(options::strategy::random);
tc.settings_string();
tc.strategy(options::strategy::CR);
tc.settings_string();
tc.strategy(options::strategy::R_over_C);
tc.settings_string();
tc.strategy(options::strategy::Cr);
tc.settings_string();
tc.strategy(options::strategy::Rc);
tc.settings_string();
}
{
ToddCoxeter tc(twosided);
tc.lookahead(options::lookahead::full | options::lookahead::felsch);
tc.settings_string();
tc.lookahead(options::lookahead::full | options::lookahead::hlt);
tc.settings_string();
tc.lookahead(options::lookahead::partial | options::lookahead::felsch);
tc.settings_string();
tc.lookahead(options::lookahead::partial | options::lookahead::hlt);
tc.settings_string();
}
{
ToddCoxeter tc(twosided);
tc.deduction_policy(options::deductions::v1
| options::deductions::no_stack_if_no_space);
tc.settings_string();
tc.deduction_policy(options::deductions::v1
| options::deductions::purge_all);
tc.settings_string();
tc.deduction_policy(options::deductions::v1
| options::deductions::purge_from_top);
tc.settings_string();
tc.deduction_policy(options::deductions::v1
| options::deductions::discard_all_if_no_space);
tc.settings_string();
tc.deduction_policy(options::deductions::v1
| options::deductions::unlimited);
tc.settings_string();
tc.deduction_policy(options::deductions::v2
| options::deductions::no_stack_if_no_space);
tc.settings_string();
tc.deduction_policy(options::deductions::v2
| options::deductions::purge_all);
tc.settings_string();
tc.deduction_policy(options::deductions::v2
| options::deductions::purge_from_top);
tc.deduction_policy(options::deductions::v2
| options::deductions::discard_all_if_no_space);
tc.settings_string();
tc.deduction_policy(options::deductions::v2
| options::deductions::unlimited);
tc.settings_string();
}
{
ToddCoxeter tc(twosided);
tc.froidure_pin_policy(options::froidure_pin::none);
tc.settings_string();
tc.froidure_pin_policy(options::froidure_pin::use_cayley_graph);
tc.settings_string();
tc.froidure_pin_policy(options::froidure_pin::use_relations);
tc.settings_string();
}
{
ToddCoxeter tc(twosided);
tc.preferred_defs(options::preferred_defs::none);
tc.settings_string();
tc.preferred_defs(options::preferred_defs::immediate_no_stack);
tc.settings_string();
tc.preferred_defs(options::preferred_defs::immediate_yes_stack);
tc.settings_string();
tc.preferred_defs(options::preferred_defs::deferred);
tc.settings_string();
}
}
// Takes about 9m3s (2021 - MacBook Air M1 - 8GB RAM)
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"046" ,
"Easdown-East-FitzGerald DualSymInv(5)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
auto const n =
5 ;
ToddCoxeter tc(twosided);
setup(tc,
n +
1 ,
dual_symmetric_inverse_monoid,
n,
author::Easdown + author::East + author::FitzGerald);
// tc.strategy(options::strategy::Rc)
// .max_deductions(10'000)
// .max_preferred_defs(512)
// .random_interval(std::chrono::seconds(10));
check_hlt(tc);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_R_over_C_style(tc);
check_Rc_style(tc);
REQUIRE(tc.number_of_classes() ==
6 '721);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"047" ,
"uniform_block_bijection_monoid(3) (FitzGerald)" ,
"[todd-coxeter][quick]" ) {
// 16, 131, 1496, 22482, 426833, 9934563, 9934563
auto rg = ReportGuard(REPORT);
auto const n =
3 ;
ToddCoxeter tc(twosided);
setup(tc, n +
1 , uniform_block_bijection_monoid, n, author::FitzGerald);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_R_over_C_style(tc);
check_Rc_style(tc);
REQUIRE(tc.number_of_classes() ==
16 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"048" ,
"stellar_monoid(7) (Gay-Hivert)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(
false );
size_t
const n =
7 ;
ToddCoxeter tc1(congruence_kind::twosided);
setup(tc1, n +
1 , rook_monoid, n,
0 );
ToddCoxeter tc2(congruence_kind::twosided, tc1);
setup(tc2, n +
1 , stellar_monoid, n);
tc2.strategy(options::strategy::felsch);
REQUIRE(tc2.number_of_classes() ==
13 '700);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"049" ,
"partition_monoid(4) (East)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
size_t
const n =
4 ;
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
5 , partition_monoid, n, author::East);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_R_over_C_style(tc);
check_Rc_style(tc);
REQUIRE(tc.number_of_classes() ==
4 '140);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"050" ,
"singular_brauer_monoid(6) (Maltcev + Mazorchuk)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
size_t
const n =
6 ;
ToddCoxeter tc(congruence_kind::twosided);
setup(tc, n * n - n, singular_brauer_monoid, n);
tc.sort_generating_pairs().remove_duplicate_generating_pairs();
REQUIRE(tc.number_of_classes() ==
9 '675);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"051" ,
"orientation_preserving_monoid(6) (Ruskuc + Arthur)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
size_t
const n =
6 ;
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
3 , orientation_preserving_monoid, n);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_R_over_C_style(tc);
check_Rc_style(tc);
REQUIRE(tc.number_of_classes() ==
2 '742);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"052" ,
"orientation_reversing_monoid(5) (Ruskuc + Arthur)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
size_t
const n =
5 ;
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
4 , orientation_reversing_monoid, n);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.number_of_classes() ==
1 '015);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"053" ,
"temperley_lieb_monoid(10) (East)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
size_t
const n =
10 ;
ToddCoxeter tc(congruence_kind::twosided);
setup(tc, n -
1 , temperley_lieb_monoid, n);
REQUIRE(tc.number_of_classes() ==
16 '795);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"054" ,
"Generate GAP benchmarks for stellar_monoid(n) (Gay-Hivert)" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
9 ; ++n) {
ToddCoxeter tc1(congruence_kind::twosided);
setup(tc1, n +
1 , rook_monoid, n,
0 );
ToddCoxeter tc2(congruence_kind::twosided, tc1);
setup(tc2, n +
1 , stellar_monoid, n);
output_gap_benchmark_file(
"stellar-" + std::to_string(n) +
".g" , tc2);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"055" ,
"Generate GAP benchmarks for partition_monoid(n) (East)" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
4 ; n <=
6 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
5 , partition_monoid, n, author::East);
tc.save(
true );
output_gap_benchmark_file(
"partition-" + std::to_string(n) +
".g" , tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"056" ,
"Generate GAP benchmarks for dual symmetric inverse monoid (East)" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
6 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
n +
1 ,
dual_symmetric_inverse_monoid,
n,
author::Easdown + author::East + author::FitzGerald);
output_gap_benchmark_file(
"dual-sym-inv-" + std::to_string(n) +
".g" ,
tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"057" ,
"Generate GAP benchmarks for "
"uniform_block_bijection_monoid (FitzGerald)" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
7 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc, n +
1 , uniform_block_bijection_monoid, n, author::FitzGerald);
output_gap_benchmark_file(
"uniform-block-bijection-" + std::to_string(n) +
".g" , tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"058" ,
"Generate GAP benchmarks for stylic monoids" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
9 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc, n, stylic_monoid, n);
output_gap_benchmark_file(
"stylic-" + std::to_string(n) +
".g" , tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"059" ,
"Generate GAP benchmarks for OP_n" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
9 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
3 , orientation_preserving_monoid, n);
output_gap_benchmark_file(
"orient-" + std::to_string(n) +
".g" , tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"060" ,
"Generate GAP benchmarks for OR_n" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
8 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
4 , orientation_reversing_monoid, n);
output_gap_benchmark_file(
"orient-reverse-" + std::to_string(n) +
".g" ,
tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"061" ,
"Generate GAP benchmarks for temperley_lieb_monoid(n)" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
13 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc, n -
1 , temperley_lieb_monoid, n);
output_gap_benchmark_file(
"temperley-lieb-" + std::to_string(n) +
".g" ,
tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"062" ,
"Generate GAP benchmarks for singular_brauer_monoid(n)" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard(
false );
for (size_t n =
3 ; n <=
7 ; ++n) {
ToddCoxeter tc(congruence_kind::twosided);
setup(tc, n * n - n, singular_brauer_monoid, n);
output_gap_benchmark_file(
"singular-brauer-" + std::to_string(n) +
".g" ,
tc);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"111" ,
"partition_monoid(2)" ,
"[todd-coxeter][quick]" ) {
ToddCoxeter p(congruence_kind::twosided);
p.set_number_of_generators(
4 );
p.add_pair({
0 ,
1 }, {
1 });
p.add_pair({
1 ,
0 }, {
1 });
p.add_pair({
0 ,
2 }, {
2 });
p.add_pair({
2 ,
0 }, {
2 });
p.add_pair({
0 ,
3 }, {
3 });
p.add_pair({
3 ,
0 }, {
3 });
p.add_pair({
1 ,
1 }, {
0 });
p.add_pair({
1 ,
3 }, {
3 });
p.add_pair({
2 ,
2 }, {
2 });
p.add_pair({
3 ,
1 }, {
3 });
p.add_pair({
3 ,
3 }, {
3 });
p.add_pair({
2 ,
3 ,
2 }, {
2 });
p.add_pair({
3 ,
2 ,
3 }, {
3 });
p.add_pair({
1 ,
2 ,
1 ,
2 }, {
2 ,
1 ,
2 });
p.add_pair({
2 ,
1 ,
2 ,
1 }, {
2 ,
1 ,
2 });
auto rg = ReportGuard(
false );
REQUIRE(p.number_of_classes() ==
15 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"112" ,
"brauer_monoid(4) (Kudryavtseva + Mazorchuk)" ,
"[todd-coxeter][quick][no-valgrind][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
size_t
const n =
4 ;
ToddCoxeter tc(congruence_kind::twosided);
setup(tc,
2 * n -
1 , brauer_monoid, n);
tc.sort_generating_pairs().remove_duplicate_generating_pairs();
REQUIRE(tc.number_of_classes() ==
105 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"113" ,
"symmetric_inverse_monoid" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
size_t n =
5 ;
auto s = symmetric_inverse_monoid(n, author::Sutov);
auto p = make<Presentation<word_type>>(s);
p.alphabet(n +
1 );
presentation::replace_word(p, word_type({}), {n});
presentation::add_identity_rules(p, n);
p.validate();
ToddCoxeter tc(congruence_kind::twosided);
tc.set_number_of_generators(n +
1 );
for (size_t i =
0 ; i < p.rules.size() -
1 ; i +=
2 ) {
tc.add_pair(p.rules[i], p.rules[i +
1 ]);
}
REQUIRE(tc.number_of_classes() ==
1546 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"114" ,
"partial_transformation_monoid(5)" ,
"[todd-coxeter][standard]" ) {
auto rg = ReportGuard(REPORT);
size_t n =
5 ;
auto s = partial_transformation_monoid(n, author::Sutov);
auto p = make<Presentation<word_type>>(s);
p.alphabet(n +
2 );
presentation::replace_word(p, word_type({}), {n +
1 });
presentation::add_identity_rules(p, n +
1 );
p.validate();
ToddCoxeter tc(congruence_kind::twosided);
tc.set_number_of_generators(n +
2 );
for (size_t i =
0 ; i < p.rules.size() -
1 ; i +=
2 ) {
tc.add_pair(p.rules[i], p.rules[i +
1 ]);
}
REQUIRE(tc.number_of_classes() ==
7776 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"115" ,
"full_transformation_monoid(5)" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard(REPORT);
size_t n =
7 ;
auto s = full_transformation_monoid(n, author::Iwahori);
auto p = make<Presentation<word_type>>(s);
p.alphabet(n +
1 );
presentation::replace_word(p, word_type({}), {n});
presentation::add_identity_rules(p, n);
p.validate();
ToddCoxeter tc(congruence_kind::twosided);
tc.set_number_of_generators(n +
1 );
for (size_t i =
0 ; i < p.rules.size() -
1 ; i +=
2 ) {
tc.add_pair(p.rules[i], p.rules[i +
1 ]);
}
REQUIRE(tc.number_of_classes() ==
823543 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"110" ,
"to_gap_string" ,
"[todd-coxeter][quick]" ) {
ToddCoxeter tc1(congruence_kind::right);
tc1.set_number_of_generators(
2 );
tc1.add_pair({
0 ,
1 }, {
1 ,
0 });
REQUIRE_THROWS_AS(tc1.to_gap_string(), LibsemigroupsException);
ToddCoxeter tc2(congruence_kind::left);
tc2.set_number_of_generators(
2 );
tc2.add_pair({
0 ,
1 }, {
1 ,
0 });
REQUIRE_THROWS_AS(tc2.to_gap_string(), LibsemigroupsException);
ToddCoxeter tc3(congruence_kind::twosided);
tc3.set_number_of_generators(
2 );
tc3.add_pair({
0 ,
1 }, {
1 ,
0 });
REQUIRE(tc3.to_gap_string().size() >
0 );
}
}
// namespace congruence
namespace fpsemigroup {
constexpr
bool REPORT =
false ;
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"063" ,
"add_rule" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
{
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"a" ,
"bb" );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
SECTION(
"R/C + Felsch lookahead" ) {
tc.congruence()
.strategy(options::strategy::R_over_C)
.lookahead(options::lookahead::felsch | options::lookahead::full);
tc.congruence().run();
}
SECTION(
"HLT + Felsch lookahead + save" ) {
tc.congruence()
.strategy(options::strategy::hlt)
.save(
true )
.lookahead(options::lookahead::felsch | options::lookahead::full)
.next_lookahead(
2 );
tc.congruence().run();
}
SECTION(
"Cr + small number of f_defs" ) {
tc.congruence().strategy(options::strategy::Cr).f_defs(
3 );
tc.congruence().run();
}
SECTION(
"Rc + small number of deductions" ) {
tc.congruence().strategy(options::strategy::Rc).max_deductions(
0 );
tc.congruence().run();
}
SECTION(
"Felsch + v2 + no preferred defs" ) {
tc.congruence()
.strategy(options::strategy::felsch)
.deduction_policy(options::deductions::v2
| options::deductions::purge_all)
.preferred_defs(options::preferred_defs::none);
}
SECTION(
"Felsch + v2 + immediate no stack" ) {
tc.congruence()
.strategy(options::strategy::felsch)
.deduction_policy(options::deductions::v2
| options::deductions::purge_from_top)
.preferred_defs(options::preferred_defs::immediate_no_stack);
}
SECTION(
"Felsch + v1 + immediate no stack" ) {
tc.congruence()
.strategy(options::strategy::felsch)
.deduction_policy(options::deductions::v1
| options::deductions::discard_all_if_no_space)
.preferred_defs(options::preferred_defs::immediate_no_stack);
}
SECTION(
"Felsch + v1 + immediate yes stack" ) {
tc.congruence()
.strategy(options::strategy::felsch)
.deduction_policy(options::deductions::v1
| options::deductions::no_stack_if_no_space)
.preferred_defs(options::preferred_defs::immediate_yes_stack);
}
SECTION(
"large collapse" ) {
tc.congruence().large_collapse(
0 );
}
REQUIRE(tc.size() ==
5 );
}
{
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"a" ,
"bb" );
tc.congruence().next_lookahead(
1 );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
5 );
}
}
// KnuthBendix methods fail for this one
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"064" ,
"(from kbmag/standalone/kb_data/s4) (KnuthBendix 49)" ,
"[todd-coxeter][quick][kbmag]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"abcd" );
tc.add_rule(
"bb" ,
"c" );
tc.add_rule(
"caca" ,
"abab" );
tc.add_rule(
"bc" ,
"d" );
tc.add_rule(
"cb" ,
"d" );
tc.add_rule(
"aa" ,
"d" );
tc.add_rule(
"ad" ,
"a" );
tc.add_rule(
"da" ,
"a" );
tc.add_rule(
"bd" ,
"b" );
tc.add_rule(
"db" ,
"b" );
tc.add_rule(
"cd" ,
"c" );
tc.add_rule(
"dc" ,
"c" );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
24 );
REQUIRE(tc.froidure_pin()->size() ==
24 );
REQUIRE(tc.normal_form(
"aaaaaaaaaaaaaaaaaaa" ) ==
"a" );
REQUIRE(KnuthBendix(tc.froidure_pin()).confluent());
}
// Second of BHN's series of increasingly complicated presentations
// of 1. Doesn't terminate
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"065" ,
"(from kbmag/standalone/kb_data/degen4b) "
"(KnuthBendix 065)" ,
"[fail][todd-coxeter][kbmag][shortlex]" ) {
auto rg = ReportGuard();
ToddCoxeter tc;
tc.set_alphabet(
"abcdefg" );
tc.set_identity(
"g" );
tc.set_inverses(
"defabcg" );
tc.add_rule(
"bbdeaecbffdbaeeccefbccefb" ,
"g" );
tc.add_rule(
"ccefbfacddecbffaafdcaafdc" ,
"g" );
tc.add_rule(
"aafdcdbaeefacddbbdeabbdea" ,
"g" );
tc.congruence().lookahead(options::lookahead::full
| options::lookahead::felsch);
REQUIRE(!tc.is_obviously_infinite());
REQUIRE(tc.size() ==
1 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"066" ,
"test validate" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"a" ,
"b" );
tc.add_rule(
"bb" ,
"b" );
REQUIRE_THROWS_AS(tc.add_rule(
"b" ,
"c" ), LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"067" ,
"add_rules after construct. from semigroup" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
using Transf = LeastTransf<
5 >;
FroidurePin<Transf> S({Transf({
1 ,
3 ,
4 ,
2 ,
3 }), Transf({
3 ,
2 ,
1 ,
3 ,
3 })});
REQUIRE(S.size() ==
88 );
REQUIRE(S.number_of_rules() ==
18 );
word_type w1, w2, w3, w4;
S.factorisation(w1, S.position(Transf({
3 ,
4 ,
4 ,
4 ,
4 })));
S.factorisation(w2, S.position(Transf({
3 ,
1 ,
3 ,
3 ,
3 })));
S.factorisation(w3, S.position(Transf({
1 ,
3 ,
1 ,
3 ,
3 })));
S.factorisation(w4, S.position(Transf({
4 ,
2 ,
4 ,
4 ,
2 })));
ToddCoxeter tc1(S);
tc1.add_rule(w1, w2);
check_hlt_no_save(tc1);
check_hlt_save_throws(tc1);
check_felsch_throws(tc1);
check_random(tc1);
REQUIRE(tc1.size() ==
21 );
REQUIRE(tc1.size() == tc1.froidure_pin()->size());
REQUIRE(tc1.equal_to(w3, w4));
REQUIRE(tc1.normal_form(w3) == tc1.normal_form(w4));
ToddCoxeter tc2(S);
tc2.add_rule(w1, w2);
check_hlt_no_save(tc2);
check_hlt_save_throws(tc2);
check_felsch_throws(tc2);
REQUIRE(tc2.size() ==
21 );
REQUIRE(tc2.size() == tc2.froidure_pin()->size());
REQUIRE(tc2.equal_to(w3, w4));
REQUIRE(tc2.normal_form(w3) == tc2.normal_form(w4));
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"068" ,
"Sym(5) from Chapter 3, Proposition 1.1 in NR" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ABabe" );
tc.set_identity(
"e" );
tc.add_rule(
"aa" ,
"e" );
tc.add_rule(
"bbbbb" ,
"e" );
tc.add_rule(
"babababa" ,
"e" );
tc.add_rule(
"bB" ,
"e" );
tc.add_rule(
"Bb" ,
"e" );
tc.add_rule(
"BabBab" ,
"e" );
tc.add_rule(
"aBBabbaBBabb" ,
"e" );
tc.add_rule(
"aBBBabbbaBBBabbb" ,
"e" );
tc.add_rule(
"aA" ,
"e" );
tc.add_rule(
"Aa" ,
"e" );
SECTION(
"Deduction policy == purge_from_top" ) {
tc.congruence()
.max_deductions(
2 )
.strategy(options::strategy::felsch)
.max_preferred_defs(
3 );
REQUIRE_THROWS_AS(tc.congruence().deduction_policy(
options::deductions::purge_from_top),
LibsemigroupsException);
tc.congruence().deduction_policy(options::deductions::v1
| options::deductions::purge_from_top);
}
SECTION(
"Deduction policy == purge_all" ) {
tc.congruence().max_deductions(
2 ).strategy(options::strategy::felsch);
tc.congruence().deduction_policy(options::deductions::v1
| options::deductions::purge_all);
}
SECTION(
"Deduction policy == discard_all_if_no_space" ) {
tc.congruence().max_deductions(
2 ).strategy(options::strategy::felsch);
tc.congruence().deduction_policy(
options::deductions::v2
| options::deductions::discard_all_if_no_space);
}
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
120 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"069" ,
"Chapter 7, Theorem 3.6 in NR (size 243)" ,
"[no-valgrind][todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbbb" ,
"b" );
tc.add_rule(
"ababababab" ,
"aa" );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
243 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"070" ,
"finite semigroup (size 99)" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbbb" ,
"b" );
tc.add_rule(
"abababab" ,
"aa" );
REQUIRE(!tc.is_obviously_finite());
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
99 );
REQUIRE(tc.finished());
REQUIRE(tc.is_obviously_finite());
}
// The following 8 examples are from Trevor Walker's Thesis: Semigroup
// enumeration - computer implementation and applications, p41.
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"071" ,
"Walker 1" ,
"[todd-coxeter][standard]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"abcABCDEFGHIXYZ" );
tc.add_rule(
"A" ,
"aaaaaaaaaaaaaa" );
tc.add_rule(
"B" ,
"bbbbbbbbbbbbbb" );
tc.add_rule(
"C" ,
"cccccccccccccc" );
tc.add_rule(
"D" ,
"aaaaba" );
tc.add_rule(
"E" ,
"bbbbab" );
tc.add_rule(
"F" ,
"aaaaca" );
tc.add_rule(
"G" ,
"ccccac" );
tc.add_rule(
"H" ,
"bbbbcb" );
tc.add_rule(
"I" ,
"ccccbc" );
tc.add_rule(
"X" ,
"aaa" );
tc.add_rule(
"Y" ,
"bbb" );
tc.add_rule(
"Z" ,
"ccc" );
tc.add_rule(
"A" ,
"a" );
tc.add_rule(
"B" ,
"b" );
tc.add_rule(
"C" ,
"c" );
tc.add_rule(
"D" ,
"Y" );
tc.add_rule(
"E" ,
"X" );
tc.add_rule(
"F" ,
"Z" );
tc.add_rule(
"G" ,
"X" );
tc.add_rule(
"H" ,
"Z" );
tc.add_rule(
"I" ,
"Y" );
tc.congruence()
.sort_generating_pairs(shortlex_compare)
.next_lookahead(
500 '000)
.run_until([&tc]() ->
bool {
return tc.congruence().coset_capacity() >=
10 '000;
});
REQUIRE(!tc.finished());
REQUIRE(!tc.is_obviously_finite());
tc.congruence().standardize(tc_order::shortlex);
REQUIRE(!tc.finished());
tc.congruence().standardize(tc_order::lex);
REQUIRE(!tc.finished());
tc.congruence().standardize(tc_order::recursive);
REQUIRE(!tc.finished());
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
// This takes approx 1 seconds with Felsch . . .
REQUIRE(tc.size() ==
1 );
tc.congruence().standardize(tc_order::shortlex);
REQUIRE(std::is_sorted(tc.congruence().cbegin_normal_forms(),
tc.congruence().cend_normal_forms(),
ShortLexCompare<word_type>{}));
tc.congruence().standardize(tc_order::lex);
REQUIRE(std::is_sorted(tc.congruence().cbegin_normal_forms(),
tc.congruence().cend_normal_forms(),
LexicographicalCompare<word_type>{}));
tc.congruence().standardize(tc_order::recursive);
REQUIRE(std::is_sorted(tc.congruence().cbegin_normal_forms(),
tc.congruence().cend_normal_forms(),
RecursivePathCompare<word_type>{}));
}
// The following example is a good one for using the lookahead.
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"072" ,
"Walker 2" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ,
"a" );
tc.add_rule(
"bbb" ,
"b" );
tc.add_rule(
"ababa" ,
"b" );
tc.add_rule(
"aaaaaaaaaaaaaaaabaaaabaaaaaaaaaaaaaaaabaaaa" ,
"b" );
REQUIRE(!tc.is_obviously_finite());
SECTION(
"custom HLT" ) {
tc.congruence()
.sort_generating_pairs()
.next_lookahead(
1 '000' 000 )
.max_deductions(
2 '000)
.use_relations_in_extra(
true )
.strategy(options::strategy::hlt)
.lookahead(options::lookahead::partial | options::lookahead::felsch)
.deduction_policy(options::deductions::v2
| options::deductions::no_stack_if_no_space);
}
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
14 '911);
tc.congruence().standardize(tc_order::shortlex);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"073" ,
"Walker 3" ,
"[todd-coxeter][standard]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaaaaaaaaaaaaaaa" ,
"a" );
tc.add_rule(
"bbbbbbbbbbbbbbbb" ,
"b" );
tc.add_rule(
"abb" ,
"baa" );
tc.congruence().next_lookahead(
2 '000' 000 );
tc.congruence().simplify();
REQUIRE(!tc.is_obviously_finite());
check_hlt(tc);
check_felsch(tc);
check_random(tc);
// check_Rc_style(tc); // Rc_style + partial lookahead works very badly
// 2m30s
check_R_over_C_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
20 '490);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"074" ,
"Walker 4" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard();
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbbbbb" ,
"b" );
tc.add_rule(
"ababbbbababbbbababbbbababbbbababbbbababbbbababbbbabba" ,
"bb" );
tc.congruence().next_lookahead(
3 '000' 000 );
REQUIRE(!tc.is_obviously_finite());
check_hlt(tc);
// Felsch very slow
check_random(tc);
SECTION(
"custom R/C" ) {
tc.congruence()
.next_lookahead(
3 '000' 000 )
.strategy(options::strategy::R_over_C)
.max_deductions(
100 '000);
}
tc.congruence().run();
REQUIRE(tc.size() ==
36 '412);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"075" ,
"Walker 5" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbbbbb" ,
"b" );
tc.add_rule(
"ababbbbababbbbababbbbababbbbababbbbababbbbababbbbabbabbbbbaa" ,
"bb" );
tc.congruence().next_lookahead(
5 '000' 000 );
REQUIRE(!tc.is_obviously_finite());
// This example is extremely slow with Felsch
check_hlt(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
tc.congruence().run();
REQUIRE(tc.congruence().complete());
REQUIRE(tc.congruence().compatible());
REQUIRE(tc.size() ==
72 '822);
std::cout << tc.congruence().stats_string();
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"076" ,
"not Walker 6" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard();
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbbbbbbbb" ,
"b" );
tc.add_rule(
"ababbbbababbbbababbbbababbbbababbbbababbbbababbbbabbabbbbbbbb" ,
"bb" );
tc.congruence().next_lookahead(
5 '000' 000 );
REQUIRE(!tc.is_obviously_finite());
// This example is extremely slow with Felsch, the random strategy
// strategy is typically fastest
check_hlt(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
8 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"077" ,
"Walker 6" ,
"[todd-coxeter][standard]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbbbbbbbb" ,
"b" );
std::string lng(
"ababbbbbbb" );
lng += lng;
lng +=
"abbabbbbbbbb" ;
tc.add_rule(lng,
"bb" );
REQUIRE(!tc.is_obviously_finite());
// This example is extremely slow with Felsch
check_hlt(tc);
check_random(tc);
// check_Rc_style(tc); // partial lookahead is too slow
// check_Cr_style(tc); // very slow
check_R_over_C_style(tc);
REQUIRE(tc.size() ==
78 '722);
}
// Felsch is faster here too!
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"078" ,
"Walker 7" ,
"[todd-coxeter][standard]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"abcde" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbb" ,
"b" );
tc.add_rule(
"ccc" ,
"c" );
tc.add_rule(
"ddd" ,
"d" );
tc.add_rule(
"eee" ,
"e" );
tc.add_rule(
"ababab" ,
"aa" );
tc.add_rule(
"bcbcbc" ,
"bb" );
tc.add_rule(
"cdcdcd" ,
"cc" );
tc.add_rule(
"dedede" ,
"dd" );
tc.add_rule(
"ac" ,
"ca" );
tc.add_rule(
"ad" ,
"da" );
tc.add_rule(
"ae" ,
"ea" );
tc.add_rule(
"bd" ,
"db" );
tc.add_rule(
"be" ,
"eb" );
tc.add_rule(
"ce" ,
"ec" );
REQUIRE(!tc.is_obviously_finite());
check_hlt(tc);
check_felsch(tc);
check_random(tc);
// check_Rc_style(tc); // partial lookahead very slow ~8s
check_R_over_C_style(tc);
check_Cr_style(tc);
tc.congruence()
.deduction_policy(options::deductions::v1
| options::deductions::no_stack_if_no_space)
.preferred_defs(options::preferred_defs::none);
REQUIRE(tc.size() ==
153 '500);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"079" ,
"Walker 8" ,
"[todd-coxeter][standard]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aaa" ,
"a" );
tc.add_rule(
"bbbbbbbbbbbbbbbbbbbbbbb" ,
"b" );
tc.add_rule(
"abbbbbbbbbbbabb" ,
"bba" );
REQUIRE(tc.congruence().length_of_generating_pairs() ==
46 );
REQUIRE(!tc.is_obviously_finite());
tc.congruence().next_lookahead(
500 '000);
// This example is extremely slow with Felsch
check_hlt(tc);
check_random(tc);
// check_Rc_style(tc); + partial lookahead too slow
// check_Cr_style(tc); // too slow
check_R_over_C_style(tc);
REQUIRE(tc.congruence().number_of_classes() ==
270 '272);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"080" ,
"KnuthBendix 098" ,
"[todd-coxeter][quick][no-valgrind]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"aAbBcCdDyYfFgGe" );
tc.set_identity(
"e" );
tc.set_inverses(
"AaBbCcDdYyFfGge" );
tc.add_rule(
"ab" ,
"c" );
tc.add_rule(
"bc" ,
"d" );
tc.add_rule(
"cd" ,
"y" );
tc.add_rule(
"dy" ,
"f" );
tc.add_rule(
"yf" ,
"g" );
tc.add_rule(
"fg" ,
"a" );
tc.add_rule(
"ga" ,
"b" );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
29 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"081" ,
"Holt 2 - SL(2, p)" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard();
ToddCoxeter tc;
tc.set_alphabet(
"xXyYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XxYye" );
tc.add_rule(
"xxYXYXYX" ,
"e" );
auto second = [](size_t p) -> std::string {
std::string s =
"xyyyyx" ;
s += std::string((p +
1 ) /
2 ,
'y' );
s += s;
s += std::string(p,
'y' );
s += std::string(
2 * (p /
3 ),
'x' );
return s;
};
REQUIRE(second(
3 ) ==
"xyyyyxyyxyyyyxyyyyyxx" );
SECTION(
"p = 3" ) {
tc.add_rule(second(
3 ),
"e" );
check_hlt(tc);
check_felsch(tc);
REQUIRE(tc.size() ==
24 );
}
SECTION(
"p = 5" ) {
tc.add_rule(second(
5 ),
"e" );
check_hlt(tc);
check_felsch(tc);
REQUIRE(tc.size() ==
120 );
}
SECTION(
"p = 7" ) {
tc.add_rule(second(
7 ),
"e" );
check_hlt(tc);
check_felsch(tc);
REQUIRE(tc.size() ==
336 );
}
SECTION(
"p = 11" ) {
tc.add_rule(second(
11 ),
"e" );
check_hlt(tc);
check_random(tc);
REQUIRE(tc.size() ==
1 '320);
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"082" ,
"Holt 3" ,
"[todd-coxeter][standard]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"aAbBcCe" );
tc.set_identity(
"e" );
tc.set_inverses(
"AaBbCce" );
tc.add_rule(
"bbCbc" ,
"e" );
tc.add_rule(
"aaBab" ,
"e" );
tc.add_rule(
"cABcabc" ,
"e" );
REQUIRE(tc.congruence().is_non_trivial() == tril::
TRUE );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
6 '561);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"083" ,
"Holt 3" ,
"[todd-coxeter][fail]" ) {
auto rg = ReportGuard();
ToddCoxeter tc;
tc.set_alphabet(
"aAbBcCe" );
tc.set_identity(
"e" );
tc.set_inverses(
"AaBbCce" );
tc.add_rule(
"aaCac" ,
"e" );
tc.add_rule(
"acbbACb" ,
"e" );
tc.add_rule(
"ABabccc" ,
"e" );
REQUIRE(!tc.is_obviously_infinite());
REQUIRE(tc.congruence().number_of_generating_pairs() ==
22 );
tc.congruence().strategy(options::strategy::R_over_C);
tc.congruence()
.sort_generating_pairs()
.remove_duplicate_generating_pairs();
REQUIRE(tc.congruence().number_of_generating_pairs() ==
22 );
tc.congruence()
.lookahead(options::lookahead::partial | options::lookahead::hlt)
.lookahead_growth_factor(
1 .
01 )
.lookahead_growth_threshold(
10 )
.f_defs(
250 '000)
.hlt_defs(
20 '000' 000 );
// REQUIRE(tc.congruence().is_non_trivial() == tril::TRUE);
tc.congruence().run();
REQUIRE(tc.size() ==
6 '561);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"084" ,
"Campbell-Reza 1" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"ab" );
tc.add_rule(
"aa" ,
"bb" );
tc.add_rule(
"ba" ,
"aaaaaab" );
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
REQUIRE(tc.size() ==
14 );
tc.congruence().standardize(tc_order::shortlex);
REQUIRE(std::vector<word_type>(tc.congruence().cbegin_normal_forms(),
tc.congruence().cend_normal_forms())
== std::vector<word_type>({{
0 },
{
1 },
{
0 ,
0 },
{
0 ,
1 },
{
1 ,
0 },
{
0 ,
0 ,
0 },
{
0 ,
0 ,
1 },
{
0 ,
0 ,
0 ,
0 },
{
0 ,
0 ,
0 ,
1 },
{
0 ,
0 ,
0 ,
0 ,
0 },
{
0 ,
0 ,
0 ,
0 ,
1 },
{
0 ,
0 ,
0 ,
0 ,
0 ,
0 },
{
0 ,
0 ,
0 ,
0 ,
0 ,
1 },
{
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 }}));
REQUIRE(tc.froidure_pin()->number_of_rules() ==
6 );
REQUIRE(tc.normal_form(
"aaaaaaab" ) ==
"aab" );
REQUIRE(tc.normal_form(
"bab" ) ==
"aaa" );
}
// The next example demonstrates why we require deferred standardization
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"085" ,
"Renner monoid type D4 (Gay-Hivert), q = 1" ,
"[no-valgrind][quick][todd-coxeter][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
11 );
for (relation_type
const & rl : RennerTypeDMonoid(
4 ,
1 )) {
tc.add_rule(rl);
}
REQUIRE(tc.number_of_rules() ==
121 );
REQUIRE(!tc.is_obviously_infinite());
REQUIRE(tc.size() ==
10 '625);
check_hlt(tc);
check_felsch(tc);
check_random(tc);
check_Rc_style(tc);
check_R_over_C_style(tc);
check_CR_style(tc);
check_Cr_style(tc);
tc.congruence().standardize(tc_order::shortlex);
REQUIRE(std::is_sorted(tc.congruence().cbegin_normal_forms(),
tc.congruence().cend_normal_forms(),
ShortLexCompare<word_type>{}));
tc.congruence().standardize(tc_order::lex);
REQUIRE(std::is_sorted(tc.congruence().cbegin_normal_forms(),
tc.congruence().cend_normal_forms(),
LexicographicalCompare<word_type>{}));
// The next section is very slow
// SECTION("standardizing with recursive order") {
// tc.congruence().standardize(tc_order::recursive);
// REQUIRE(std::is_sorted(tc.congruence().cbegin_normal_forms(),
// tc.congruence().cend_normal_forms(),
// RecursivePathCompare<word_type>{}));
// }
}
// Felsch very slow here
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"086" ,
"trivial semigroup" ,
"[no-valgrind][todd-coxeter][quick][no-coverage]" ) {
auto rg = ReportGuard(REPORT);
for (size_t N =
2 ; N <
1000 ; N +=
199 ) {
ToddCoxeter tc;
tc.set_alphabet(
"eab" );
tc.set_identity(
"e" );
std::string lhs =
"a" + std::string(N,
'b' );
std::string rhs =
"e" ;
tc.add_rule(lhs, rhs);
lhs = std::string(N,
'a' );
rhs = std::string(N +
1 ,
'b' );
tc.add_rule(lhs, rhs);
lhs =
"ba" ;
rhs = std::string(N,
'b' ) +
"a" ;
tc.add_rule(lhs, rhs);
tc.run();
if (N %
3 ==
1 ) {
REQUIRE(tc.size() ==
3 );
}
else {
REQUIRE(tc.size() ==
1 );
}
}
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"087" ,
"ACE --- 2p17-2p14 - HLT" ,
"[todd-coxeter][standard][ace]" ) {
auto rg = ReportGuard(
false );
ToddCoxeter G;
G.set_alphabet(
"abcABCe" );
G.set_identity(
"e" );
G.set_inverses(
"ABCabce" );
G.add_rule(
"aBCbac" ,
"e" );
G.add_rule(
"bACbaacA" ,
"e" );
G.add_rule(
"accAABab" ,
"e" );
congruence::ToddCoxeter H(right, G.congruence());
H.add_pair({
1 ,
2 }, {
6 });
H.next_lookahead(
1 '000' 000 );
REQUIRE(H.number_of_classes() ==
16 '384);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"088" ,
"ACE --- 2p17-2p3 - HLT" ,
"[todd-coxeter][standard][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abcABCe" );
G.set_identity(
"e" );
G.set_inverses(
"ABCabce" );
G.add_rule(
"aBCbac" ,
"e" );
G.add_rule(
"bACbaacA" ,
"e" );
G.add_rule(
"accAABab" ,
"e" );
letter_type a =
0 ;
letter_type b =
1 ;
letter_type c =
2 ;
letter_type A =
3 ;
letter_type B =
4 ;
letter_type C =
5 ;
letter_type e =
6 ;
congruence::ToddCoxeter H(right, G.congruence());
H.add_pair({b, c}, {e});
H.add_pair({b, c}, {A, B, A, A, b, c, a, b, C});
H.strategy(options::strategy::hlt)
.save(
true )
.lookahead(options::lookahead::partial);
REQUIRE(H.number_of_classes() ==
8 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"089" ,
"ACE --- 2p17-1a - HLT" ,
"[todd-coxeter][standard][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abcABCe" );
G.set_identity(
"e" );
G.set_inverses(
"ABCabce" );
G.add_rule(
"aBCbac" ,
"e" );
G.add_rule(
"bACbaacA" ,
"e" );
G.add_rule(
"accAABab" ,
"e" );
letter_type a =
0 ;
letter_type b =
1 ;
letter_type c =
2 ;
letter_type A =
3 ;
letter_type B =
4 ;
letter_type C =
5 ;
letter_type e =
6 ;
congruence::ToddCoxeter H(right, G.congruence());
H.add_pair({b, c}, {e});
H.add_pair({A, B, A, A, b, c, a, b, C}, {e});
H.add_pair({A, c, c, c, a, c, B, c, A}, {e});
H.large_collapse(
10 '000);
H.strategy(options::strategy::hlt)
.save(
true )
.lookahead(options::lookahead::partial);
REQUIRE(H.number_of_classes() ==
1 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"090" ,
"ACE --- F27" ,
"[todd-coxeter][standard][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abcdxyzABCDXYZe" );
G.set_identity(
"e" );
G.set_inverses(
"ABCDXYZabcdxyze" );
G.add_rule(
"abC" ,
"e" );
G.add_rule(
"bcD" ,
"e" );
G.add_rule(
"cdX" ,
"e" );
G.add_rule(
"dxY" ,
"e" );
G.add_rule(
"xyZ" ,
"e" );
G.add_rule(
"yzA" ,
"e" );
G.add_rule(
"zaB" ,
"e" );
congruence::ToddCoxeter H(twosided, G);
check_felsch(H);
check_hlt(H);
check_random(H);
REQUIRE(H.number_of_classes() ==
29 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"091" ,
"ACE --- SL219 - HLT" ,
"[todd-coxeter][standard][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abABe" );
G.set_identity(
"e" );
G.set_inverses(
"ABabe" );
G.add_rule(
"aBABAB" ,
"e" );
G.add_rule(
"BAAbaa" ,
"e" );
G.add_rule(
"abbbbabbbbbbbbbbabbbbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaa" ,
"e" );
letter_type b =
1 ;
letter_type e =
4 ;
congruence::ToddCoxeter H(right, G);
H.add_pair({b}, {e});
H.strategy(options::strategy::hlt)
.save(
false )
.lookahead(options::lookahead::partial);
REQUIRE(H.number_of_classes() ==
180 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"092" ,
"ACE --- perf602p5 - HLT" ,
"[no-valgrind][todd-coxeter][quick][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abstuvdABSTUVDe" );
G.set_identity(
"e" );
G.set_inverses(
"ABSTUVDabstuvde" );
G.add_rule(
"aaD" ,
"e" );
G.add_rule(
"bbb" ,
"e" );
G.add_rule(
"ababababab" ,
"e" );
G.add_rule(
"ss" ,
"e" );
G.add_rule(
"tt" ,
"e" );
G.add_rule(
"uu" ,
"e" );
G.add_rule(
"vv" ,
"e" );
G.add_rule(
"dd" ,
"e" );
G.add_rule(
"STst" ,
"e" );
G.add_rule(
"UVuv" ,
"e" );
G.add_rule(
"SUsu" ,
"e" );
G.add_rule(
"SVsv" ,
"e" );
G.add_rule(
"TUtu" ,
"e" );
G.add_rule(
"TVtv" ,
"e" );
G.add_rule(
"AsaU" ,
"e" );
G.add_rule(
"AtaV" ,
"e" );
G.add_rule(
"AuaS" ,
"e" );
G.add_rule(
"AvaT" ,
"e" );
G.add_rule(
"BsbDVT" ,
"e" );
G.add_rule(
"BtbVUTS" ,
"e" );
G.add_rule(
"BubVU" ,
"e" );
G.add_rule(
"BvbU" ,
"e" );
G.add_rule(
"DAda" ,
"e" );
G.add_rule(
"DBdb" ,
"e" );
G.add_rule(
"DSds" ,
"e" );
G.add_rule(
"DTdt" ,
"e" );
G.add_rule(
"DUdu" ,
"e" );
G.add_rule(
"DVdv" ,
"e" );
congruence::ToddCoxeter H(right, G);
letter_type a =
0 ;
letter_type e =
14 ;
H.add_pair({a}, {e});
check_hlt(H);
check_random(H);
check_felsch(H);
REQUIRE(H.number_of_classes() ==
480 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"093" ,
"ACE --- M12" ,
"[todd-coxeter][standard][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abcABCe" );
G.set_identity(
"e" );
G.set_inverses(
"ABCabce" );
G.add_rule(
"aaaaaaaaaaa" ,
"e" );
G.add_rule(
"bb" ,
"e" );
G.add_rule(
"cc" ,
"e" );
G.add_rule(
"ababab" ,
"e" );
G.add_rule(
"acacac" ,
"e" );
G.add_rule(
"bcbcbcbcbcbcbcbcbcbc" ,
"e" );
G.add_rule(
"cbcbabcbcAAAAA" ,
"e" );
congruence::ToddCoxeter H(twosided, G);
SECTION(
"HLT + save + partial lookahead" ) {
H.strategy(options::strategy::hlt)
.save(
true )
.lookahead(options::lookahead::partial);
}
SECTION(
"random" ) {
H.strategy(options::strategy::random)
.random_interval(std::chrono::milliseconds(
100 ));
}
check_felsch(H);
REQUIRE(H.number_of_classes() ==
95 '040);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"094" ,
"ACE --- C5 - HLT" ,
"[todd-coxeter][quick][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abABe" );
G.set_identity(
"e" );
G.set_inverses(
"ABabe" );
G.add_rule(
"aaaaa" ,
"e" );
G.add_rule(
"b" ,
"e" );
congruence::ToddCoxeter H(twosided, G);
check_hlt(H);
check_random(H);
check_felsch(H);
REQUIRE(H.number_of_classes() ==
5 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"095" ,
"ACE --- A5-C5" ,
"[todd-coxeter][quick][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abABe" );
G.set_identity(
"e" );
G.set_inverses(
"ABabe" );
G.add_rule(
"aa" ,
"e" );
G.add_rule(
"bbb" ,
"e" );
G.add_rule(
"ababababab" ,
"e" );
congruence::ToddCoxeter H(right, G);
letter_type
const a =
0 , b =
1 , e =
4 ;
H.add_pair({a, b}, {e});
check_hlt(H);
check_random(H);
check_felsch(H);
REQUIRE(H.number_of_classes() ==
12 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"096" ,
"ACE --- A5" ,
"[todd-coxeter][quick][ace]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter G;
G.set_alphabet(
"abABe" );
G.set_identity(
"e" );
G.set_inverses(
"ABabe" );
G.add_rule(
"aa" ,
"e" );
G.add_rule(
"bbb" ,
"e" );
G.add_rule(
"ababababab" ,
"e" );
congruence::ToddCoxeter H(twosided, G);
check_hlt(H);
check_random(H);
check_felsch(H);
H.random_shuffle_generating_pairs();
REQUIRE(H.number_of_classes() ==
60 );
REQUIRE_THROWS_AS(H.random_shuffle_generating_pairs(),
LibsemigroupsException);
}
// Felsch is much much better here
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"097" ,
"relation ordering" ,
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard();
ToddCoxeter tc;
tc.set_alphabet(
13 );
for (relation_type
const & rl : RennerTypeDMonoid(
5 ,
1 )) {
tc.add_rule(rl);
}
REQUIRE(tc.number_of_rules() ==
173 );
REQUIRE(!tc.is_obviously_infinite());
tc.congruence()
.sort_generating_pairs(&shortlex_compare)
.sort_generating_pairs(recursive_path_compare)
.remove_duplicate_generating_pairs();
REQUIRE(tc.number_of_rules() ==
173 );
tc.congruence().strategy(options::strategy::felsch).f_defs(
100 '000).run();
REQUIRE(tc.size() ==
258 '661);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"098" ,
"relation ordering" ,
"[todd-coxeter][quick]" ) {
ToddCoxeter tc;
tc.set_alphabet(
10 );
tc.add_rule({
0 ,
1 }, {
0 });
tc.add_rule({
0 ,
2 }, {
0 });
tc.add_rule({
0 ,
3 }, {
0 });
tc.add_rule({
0 ,
4 }, {
0 });
tc.add_rule({
0 ,
5 }, {
0 });
tc.add_rule({
0 ,
6 }, {
0 });
tc.add_rule({
0 ,
7 }, {
0 });
tc.add_rule({
0 ,
8 }, {
0 });
tc.add_rule({
0 ,
9 }, {
0 });
tc.add_rule({
1 ,
0 }, {
1 });
tc.add_rule({
1 ,
1 }, {
1 });
tc.add_rule({
1 ,
2 }, {
1 });
tc.add_rule({
1 ,
3 }, {
1 });
tc.add_rule({
1 ,
4 }, {
1 });
tc.add_rule({
1 ,
5 }, {
1 });
tc.add_rule({
1 ,
6 }, {
1 });
tc.add_rule({
1 ,
7 }, {
1 });
tc.add_rule({
1 ,
8 }, {
1 });
tc.add_rule({
1 ,
9 }, {
1 });
tc.add_rule({
2 ,
0 }, {
2 });
tc.add_rule({
2 ,
1 }, {
2 });
tc.add_rule({
2 ,
2 }, {
2 });
tc.add_rule({
2 ,
3 }, {
2 });
tc.add_rule({
2 ,
4 }, {
2 });
tc.add_rule({
2 ,
5 }, {
2 });
tc.add_rule({
2 ,
6 }, {
2 });
tc.add_rule({
2 ,
7 }, {
2 });
tc.add_rule({
2 ,
8 }, {
2 });
tc.add_rule({
2 ,
9 }, {
2 });
tc.add_rule({
3 ,
0 }, {
3 });
tc.add_rule({
3 ,
1 }, {
3 });
tc.add_rule({
3 ,
2 }, {
3 });
tc.add_rule({
3 ,
3 }, {
3 });
tc.add_rule({
3 ,
4 }, {
3 });
tc.add_rule({
3 ,
5 }, {
3 });
tc.add_rule({
3 ,
6 }, {
3 });
tc.add_rule({
3 ,
7 }, {
3 });
tc.add_rule({
3 ,
8 }, {
3 });
tc.add_rule({
3 ,
9 }, {
3 });
tc.add_rule({
4 ,
0 }, {
4 });
tc.add_rule({
4 ,
1 }, {
4 });
tc.add_rule({
4 ,
2 }, {
4 });
tc.add_rule({
4 ,
3 }, {
4 });
tc.add_rule({
4 ,
4 }, {
4 });
tc.add_rule({
4 ,
5 }, {
4 });
tc.add_rule({
4 ,
6 }, {
4 });
tc.add_rule({
4 ,
7 }, {
4 });
tc.add_rule({
4 ,
8 }, {
4 });
tc.add_rule({
4 ,
9 }, {
4 });
tc.add_rule({
5 ,
0 }, {
5 });
tc.add_rule({
5 ,
1 }, {
5 });
tc.add_rule({
5 ,
2 }, {
5 });
tc.add_rule({
5 ,
3 }, {
5 });
tc.add_rule({
5 ,
4 }, {
5 });
tc.add_rule({
5 ,
5 }, {
5 });
tc.add_rule({
5 ,
6 }, {
5 });
tc.add_rule({
5 ,
7 }, {
5 });
tc.add_rule({
5 ,
8 }, {
5 });
tc.add_rule({
5 ,
9 }, {
5 });
tc.add_rule({
6 ,
0 }, {
6 });
tc.add_rule({
6 ,
1 }, {
6 });
tc.add_rule({
6 ,
2 }, {
6 });
tc.add_rule({
6 ,
3 }, {
6 });
tc.add_rule({
6 ,
4 }, {
6 });
tc.add_rule({
6 ,
5 }, {
6 });
tc.add_rule({
6 ,
6 }, {
6 });
tc.add_rule({
6 ,
7 }, {
6 });
tc.add_rule({
6 ,
8 }, {
6 });
tc.add_rule({
6 ,
9 }, {
6 });
tc.add_rule({
7 ,
0 }, {
7 });
tc.add_rule({
7 ,
1 }, {
7 });
tc.add_rule({
7 }, {
7 ,
2 });
tc.add_rule({
7 ,
3 }, {
7 });
tc.add_rule({
7 ,
4 }, {
7 });
tc.add_rule({
7 ,
5 }, {
7 });
tc.add_rule({
7 ,
6 }, {
7 });
tc.add_rule({
7 ,
7 }, {
7 });
tc.add_rule({
7 ,
8 }, {
7 });
tc.add_rule({
7 ,
9 }, {
7 });
tc.add_rule({
8 ,
0 }, {
8 });
tc.add_rule({
8 ,
1 }, {
8 });
tc.add_rule({
8 ,
2 }, {
8 });
tc.add_rule({
8 ,
3 }, {
8 });
tc.add_rule({
8 ,
4 }, {
8 });
tc.add_rule({
8 ,
5 }, {
8 });
tc.add_rule({
8 ,
6 }, {
8 });
tc.add_rule({
8 ,
7 }, {
8 });
tc.add_rule({
8 ,
8 }, {
8 });
tc.add_rule({
8 ,
9 }, {
8 });
tc.add_rule({
9 ,
0 }, {
9 });
tc.add_rule({
9 ,
0 ,
1 ,
2 ,
3 ,
4 ,
5 ,
5 ,
1 ,
5 ,
6 ,
9 ,
8 ,
8 ,
8 ,
8 ,
8 ,
0 }, {
9 });
tc.congruence().sort_generating_pairs(recursive_path_compare);
check_felsch(tc);
check_hlt(tc);
check_random(tc);
REQUIRE(tc.size() ==
10 );
REQUIRE_THROWS_AS(tc.congruence().sort_generating_pairs(shortlex_compare),
LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"099" ,
"short circuit size in obviously infinite" ,
"[todd-coxeter][quick]" ) {
auto rg = ReportGuard(REPORT);
ToddCoxeter tc;
tc.set_alphabet(
"abc" );
tc.add_rule(
"aaaa" ,
"a" );
REQUIRE(tc.size() == POSITIVE_INFINITY);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"100" ,
"http://brauer.maths.qmul.ac.uk/Atlas/misc/24A8/mag/24A8G1-P1.M ",
"[todd-coxeter][standard]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"X" );
tc.add_rule(
"yyyyyy" ,
"Y" );
tc.add_rule(
"YXyx" ,
"XYxy" );
tc.add_rule(
"xYYYxYYYxYY" ,
"yyXyyyXyyyX" );
tc.add_rule(
"xyxyyXyxYYxyyyx" ,
"yyyXyyy" );
tc.congruence()
.next_lookahead(
2 '000' 000 )
.strategy(options::strategy::hlt)
.sort_generating_pairs()
.lookahead(options::lookahead::partial)
.standardize(
true );
tc.congruence().run();
REQUIRE(tc.size() ==
322 '560);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"101" ,
"http://brauer.maths.qmul.ac.uk/Atlas/spor/M11/mag/M11G1-P1.M ",
"[todd-coxeter][quick][no-coverage][no-valgrind]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"xyyxyyxyyxyyxyyxyy" ,
"e" );
tc.add_rule(
"xyxyxYxyxyyxYxyxYxY" ,
"e" );
REQUIRE(tc.size() ==
7 '920);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"102" ,
"http://brauer.maths.qmul.ac.uk/Atlas/spor/M12/mag/M12G1-P1.M ",
"[todd-coxeter][standard]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"XYxyXYxyXYxyXYxyXYxyXYxy" ,
"e" );
tc.add_rule(
"xyxyxYxyxyxYxyxyxYxyxyxYxyxyxYxyxyxY" ,
"e" );
tc.add_rule(
"XYXYxyxyXYXYxyxyXYXYxyxyXYXYxyxyXYXYxyxy" ,
"e" );
REQUIRE(tc.size() ==
95 '040);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"103" ,
"http://brauer.maths.qmul.ac.uk/Atlas/spor/M22/mag/M22G1-P1.M ",
"[todd-coxeter][extreme]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"xyyxyyxyyxyyxyy" ,
"e" );
tc.add_rule(
"XYxyXYxyXYxyXYxyXYxyXYxy" ,
"e" );
tc.add_rule(
"XYXYxyxyXYXYxyxyXYXYxyxy" ,
"e" );
tc.add_rule(
"xyxyxYxyxyxYxyxyxYxyxyxYxyxyxY" ,
"e" );
REQUIRE(tc.size() ==
443 '520);
}
// Takes about 4 minutes (2021 - MacBook Air M1 - 8GB RAM)
// with Felsch (3.5mins or 2.5mins with lowerbound) or HLT (4.5mins)
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"104" ,
"http://brauer.maths.qmul.ac.uk/Atlas/spor/M23/mag/M23G1-P1.M ",
"[todd-coxeter][extreme]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"xyyxyyxyyxyyxyyxyy" ,
"e" );
tc.add_rule(
"XYxyXYxyXYxyXYxyXYxyXYxy" ,
"e" );
tc.add_rule(
"xyxYxyyxyxYxyyxyxYxyyxyxYxyy" ,
"e" );
tc.add_rule(
"xyxyxyxYxyyxyxYxyxYxyxyxyxYxYxY" ,
"e" );
tc.add_rule(
"xyxyyxyyxyxyyxyyxyxyyxyyxyxyyxyyxyxyyxyyxyxyyxyy" ,
"e" );
tc.add_rule(
"xyxyyxyxyyxyxyyxyyxYxyyxYxyxyyxyxYxyy" ,
"e" );
tc.congruence()
.sort_generating_pairs()
.strategy(options::strategy::felsch)
.use_relations_in_extra(
true )
.lower_bound(
10 '200' 960 )
.deduction_policy(options::deductions::v2
| options::deductions::no_stack_if_no_space)
.reserve(
50 '000' 000 );
std::cout << tc.congruence().settings_string();
tc.congruence().run();
REQUIRE(tc.size() ==
10 '200' 960 );
}
// Takes about 3 minutes
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"105" ,
"http://brauer.maths.qmul.ac.uk/Atlas/clas/S62/mag/S62G1-P1.M ",
"[todd-coxeter][extreme]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"XYxyXYxyXYxyXYxyXYxyXYxyXYxyXYxyXYxyXYxyXYxyXYxy" ,
"e" );
tc.add_rule(
"XYXYxyxyXYXYxyxyXYXYxyxyXYXYxyxyXYXYxyxy" ,
"e" );
tc.add_rule(
"xyxyxYxyxyxYxyxyxYxyxYxYxyxYxYxyxYxY" ,
"e" );
tc.add_rule(
"xyxyxYxyxYxyxYxyxyxYxyxYxyxYxyxyxYxyxYxyxYxyxyxYxyxYxyxY" ,
"e" );
congruence::ToddCoxeter tc2(congruence_kind::right, tc);
tc2.add_pair(tc.string_to_word(
"xy" ), tc.string_to_word(
"e" ));
REQUIRE(tc2.number_of_classes() ==
10 '644' 480 );
}
// Approx. 32 minutes (2021 - MacBook Air M1 - 8GB RAM)
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"106" ,
"http://brauer.maths.qmul.ac.uk/Atlas/spor/HS/mag/HSG1-P1.M ",
"[todd-coxeter][extreme]" ) {
auto rg = ReportGuard();
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyyyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"xyyxyyxyyxyyxyyxyyxyyxyyxyyxyy" ,
"e" );
tc.add_rule(
"XYxyXYxyXYxyXYxyXYxy" ,
"e" );
tc.add_rule(
"XYXYxyxyXYXYxyxyXYXYxyxy" ,
"e" );
tc.add_rule(
"XYYxyyXYYxyyXYYxyyXYYxyyXYYxyyXYYxyy" ,
"e" );
tc.add_rule(
"xyxyxyyxYxYYxYxyyxyxyxYYxYYxYYxYY" ,
"e" );
tc.add_rule(
"xyxyyxYYxYYxyyxYYxYYxyyxyxyyxYxyyxYxyy" ,
"e" );
tc.add_rule(
"xyxyxyyxyyxyxYxYxyxyyxyyxyxyxYYxYxYY" ,
"e" );
tc.add_rule(
"xyxyxyyxYxYYxyxyxYxyxyxyyxYxYYxyxyxY" ,
"e" );
tc.add_rule(
"xyxyxyyxyxyxyyxyxyxYxyxyxyyxyyxyyxyxyxY" ,
"e" );
tc.add_rule(
"xyxyxyyxyxyyxyxyyxyxyxyyxYxyxYYxyxYxyy" ,
"e" );
congruence::ToddCoxeter tc2(congruence_kind::right, tc);
tc2.add_pair(tc.string_to_word(
"xy" ), tc.string_to_word(
"e" ));
tc2.sort_generating_pairs()
.use_relations_in_extra(
true )
.strategy(options::strategy::hlt)
.lookahead(options::lookahead::felsch | options::lookahead::partial);
REQUIRE(tc2.number_of_classes() ==
4 '032' 000 );
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"107" ,
"http://brauer.maths.qmul.ac.uk/Atlas/spor/J1/mag/J1G1-P1.M ",
"[todd-coxeter][standard]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"xyxyxYxyxYxyxYxyxyxYxyxYxyxYxyxyxYxyxYxyxYxyxyxYxyxYxyxYxyxy"
"xYxyxYxyxY" ,
"e" );
tc.add_rule(
"xyxyxYxyxYxyxYxyxYxyxYxyxYxyxyxYxYxyxyxYxyxYxyxYxyxYxyxYxyxY"
"xyxyxYxY" ,
"e" );
REQUIRE(tc.size() ==
175 '560);
}
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"108" ,
"http://brauer.maths.qmul.ac.uk/Atlas/lin/L34/mag/L34G1-P1.M ",
"[todd-coxeter][quick][no-coverage][no-valgrind]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"xyyxyyxyyxyyxyy" ,
"e" );
tc.add_rule(
"XYxyXYxyXYxyXYxyXYxy" ,
"e" );
tc.add_rule(
"xyxyxYxyxyxYxyxyxYxyxyxYxyxyxY" ,
"e" );
tc.add_rule(
"xyxyxyyxYxyxyxyyxYxyxyxyyxYxyxyxyyxYxyxyxyyxY" ,
"e" );
REQUIRE(tc.size() ==
20 '160);
}
// Takes about 10 seconds (2021 - MacBook Air M1 - 8GB RAM)
LIBSEMIGROUPS_TEST_CASE(
"ToddCoxeter" ,
"109" ,
"http://brauer.maths.qmul.ac.uk/Atlas/clas/S62/mag/S62G1-P1.M ",
"[todd-coxeter][extreme]" ) {
ToddCoxeter tc;
tc.set_alphabet(
"xyXYe" );
tc.set_identity(
"e" );
tc.set_inverses(
"XYxye" );
tc.add_rule(
"xx" ,
"e" );
tc.add_rule(
"yyyyyyy" ,
"e" );
tc.add_rule(
"xyxyxyxyxyxyxyxyxy" ,
"e" );
tc.add_rule(
"xyyxyyxyyxyyxyyxyyxyyxyyxyyxyyxyyxyy" ,
"e" );
tc.add_rule(
"XYXYXYxyxyxyXYXYXYxyxyxy" ,
"e" );
tc.add_rule(
"XYxyXYxyXYxy" ,
"e" );
tc.add_rule(
"XYYxyyXYYxyy" ,
"e" );
REQUIRE(tc.size() ==
1 '451' 520 );
std::cout << tc.congruence().stats_string();
}
}
// namespace fpsemigroup
}
// namespace libsemigroups
Messung V0.5 in Prozent C=96 H=80 G=88
¤ Dauer der Verarbeitung: 0.188 Sekunden
(vorverarbeitet am 2026-06-06)
¤
*© Formatika GbR, Deutschland