//
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2022 James D. Mitchell
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
#include <cstddef>
// for size_t
#include "catch.hpp" // for REQUIRE, REQUIRE_THROWS_AS, REQUI...
#include "test-main.hpp" // for LIBSEMIGROUPS_TEST_CASE
#include "libsemigroups/bipart.hpp" // for Bipartition
#include "libsemigroups/containers.hpp" // for StaticVector1
#include "libsemigroups/froidure-pin.hpp" // for FroidurePin
#include "libsemigroups/int-range.hpp" // for IntegralRange
#include "libsemigroups/knuth-bendix.hpp" // for redundant_rule
#include "libsemigroups/make-present.hpp" // for make
#include "libsemigroups/present.hpp" // for Presentation
#include "libsemigroups/siso.hpp" // for Sislo
#include "libsemigroups/types.hpp" // for word_type
namespace libsemigroups {
struct LibsemigroupsException;
// forward decl
namespace {
template <
typename W>
void check_constructors(Presentation<W>& p) {
p.validate();
Presentation<W> pp(p);
pp.validate();
REQUIRE(pp.alphabet() == p.alphabet());
REQUIRE(pp.rules == p.rules);
Presentation<W> q(std::move(p));
q.validate();
REQUIRE(q.alphabet() == pp.alphabet());
REQUIRE(q.rules == pp.rules);
p = q;
p.validate();
REQUIRE(q.alphabet() == p.alphabet());
REQUIRE(q.rules == p.rules);
p = std::move(q);
p.validate();
REQUIRE(pp.alphabet() == p.alphabet());
REQUIRE(pp.rules == p.rules);
}
template <
typename W>
void check_alphabet_letters() {
Presentation<W> p;
p.alphabet({0, 1, 2});
REQUIRE(p.alphabet() == W({0, 1, 2}));
REQUIRE(p.letter(0) == 0);
REQUIRE(p.letter(1) == 1);
REQUIRE(p.letter(2) == 2);
p.alphabet(4);
REQUIRE(p.alphabet() == W({0, 1, 2, 3}));
p.validate();
REQUIRE_THROWS_AS(p.alphabet({0, 1, 1}), LibsemigroupsException);
presentation::add_rule(p, {0, 1, 2, 1}, {0, 0});
presentation::add_rule(p, {4, 1}, {0, 5});
presentation::add_rule(p, {4, 1}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1});
p.alphabet_from_rules();
REQUIRE(p.alphabet() == W({0, 1, 2, 4, 5}));
REQUIRE(p.index(0) == 0);
REQUIRE(p.index(1) == 1);
REQUIRE(p.index(2) == 2);
REQUIRE(p.index(4) == 3);
REQUIRE(p.index(5) == 4);
REQUIRE(!p.contains_empty_word());
presentation::add_rule(p, {4, 1}, {});
p.alphabet_from_rules();
REQUIRE(p.contains_empty_word());
p.alphabet({0, 1, 2, 3});
REQUIRE(p.alphabet() == W({0, 1, 2, 3}));
}
template <
typename W>
void check_contains_empty_word() {
Presentation<W> p;
REQUIRE(!p.contains_empty_word());
p.contains_empty_word(
true);
REQUIRE(p.contains_empty_word());
p.contains_empty_word(
false);
REQUIRE(!p.contains_empty_word());
}
template <
typename W>
void check_validate_rules_throws() {
Presentation<W> p;
p.rules.emplace_back();
REQUIRE_THROWS_AS(p.validate_rules(), LibsemigroupsException);
}
template <
typename W>
void check_add_rules() {
Presentation<W> p;
presentation::add_rule(p, {0, 1, 2, 1}, {0, 0});
Presentation<W> q;
presentation::add_rule(q, {4, 1}, {0, 5});
presentation::add_rule(q, {4, 1}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1});
presentation::add_rules(p, q);
REQUIRE(p.rules
== std::vector<W>({{0, 1, 2, 1},
{0, 0},
{4, 1},
{0, 5},
{4, 1},
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}));
REQUIRE(q.rules
== std::vector<W>(
{{4, 1}, {0, 5}, {4, 1}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}));
REQUIRE_THROWS_AS(p.validate(), LibsemigroupsException);
REQUIRE_THROWS_AS(q.validate(), LibsemigroupsException);
}
template <
typename W>
void check_add_identity_rules() {
Presentation<W> p;
presentation::add_rule(p, {0, 1, 2, 1}, {0, 0});
REQUIRE_THROWS_AS(presentation::add_identity_rules(p, 0),
LibsemigroupsException);
p.alphabet_from_rules();
presentation::add_identity_rules(p, 0);
REQUIRE(p.rules
== std::vector<W>({{0, 1, 2, 1},
{0, 0},
{0, 0},
{0},
{1, 0},
{1},
{0, 1},
{1},
{2, 0},
{2},
{0, 2},
{2}}));
}
template <
typename W>
void check_add_zero_rules() {
Presentation<W> p;
presentation::add_rule(p, {0, 1, 2, 1}, {0, 0});
REQUIRE_THROWS_AS(presentation::add_zero_rules(p, 0),
LibsemigroupsException);
p.alphabet_from_rules();
presentation::add_zero_rules(p, 0);
REQUIRE(p.rules
== std::vector<W>({{0, 1, 2, 1},
{0, 0},
{0, 0},
{0},
{1, 0},
{0},
{0, 1},
{0},
{2, 0},
{0},
{0, 2},
{0}}));
}
template <
typename W>
void check_add_inverse_rules() {
Presentation<W> p;
presentation::add_rule(p, {0, 1, 2, 1}, {0, 0});
p.alphabet_from_rules();
REQUIRE_THROWS_AS(presentation::add_inverse_rules(p, {0, 1, 1}, 0),
LibsemigroupsException);
REQUIRE_THROWS_AS(presentation::add_inverse_rules(p, {1, 2, 0}, 0),
LibsemigroupsException);
p.alphabet({0, 1, 2, 3});
REQUIRE_THROWS_AS(presentation::add_inverse_rules(p, {0, 2, 3, 1}, 0),
LibsemigroupsException);
REQUIRE_THROWS_AS(presentation::add_inverse_rules(p, {0, 2, 1}, 0),
LibsemigroupsException);
p.alphabet({0, 1, 2});
presentation::add_inverse_rules(p, {0, 2, 1}, 0);
REQUIRE(
p.rules
== std::vector<W>({{0, 1, 2, 1}, {0, 0}, {1, 2}, {0}, {2, 1}, {0}}));
// When id is UNDEFINED
presentation::add_inverse_rules(p, {0, 2, 1});
REQUIRE(p.rules
== std::vector<W>({{0, 1, 2, 1},
{0, 0},
{1, 2},
{0},
{2, 1},
{0},
{0, 0},
{},
{1, 2},
{},
{2, 1},
{}}));
}
template <
typename W>
void check_remove_duplicate_rules() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::remove_duplicate_rules(p),
LibsemigroupsException);
p.rules.push_back(W({0, 0}));
presentation::add_rule(p, {0, 0}, {0, 1, 2, 1});
p.alphabet_from_rules();
REQUIRE(p.rules.size() == 4);
presentation::remove_duplicate_rules(p);
REQUIRE(p.rules.size() == 2);
}
template <
typename W>
void check_reduce_complements() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::reduce_complements(p),
LibsemigroupsException);
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 2, 1}, {1, 1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
p.alphabet_from_rules();
presentation::reduce_complements(p);
presentation::sort_each_rule(p);
presentation::sort_rules(p);
REQUIRE(p.rules
== std::vector<W>({{1, 1},
{0},
{1, 2, 1},
{0},
{0, 1, 2, 1},
{0},
{1, 1, 2, 1},
{0}}));
}
template <
typename W>
void check_sort_each_rule() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::sort_each_rule(p),
LibsemigroupsException);
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 2, 1}, {1, 1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
p.alphabet_from_rules();
presentation::sort_each_rule(p);
REQUIRE(p.rules
== std::vector<W>({{0, 1, 2, 1},
{1, 2, 1},
{1, 1, 2, 1},
{1, 2, 1},
{1, 1, 2, 1},
{1, 1},
{1, 2, 1},
{1, 1},
{1, 2, 1},
{0}}));
}
template <
typename W>
void check_sort_rules() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::sort_rules(p), LibsemigroupsException);
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 2, 1}, {1, 1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
p.alphabet_from_rules();
presentation::sort_rules(p);
REQUIRE(p.rules
== std::vector<W>({{1, 2, 1},
{0},
{1, 1},
{1, 2, 1},
{1, 1, 2, 1},
{1, 1},
{0, 1, 2, 1},
{1, 2, 1},
{1, 2, 1},
{1, 1, 2, 1}}));
REQUIRE(presentation::are_rules_sorted(p));
}
template <
typename W>
void check_longest_common_subword() {
{
// Normalized alphabet
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_NOTHROW(presentation::longest_common_subword(p));
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 2, 1}, {1, 1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
p.alphabet_from_rules();
REQUIRE(presentation::longest_common_subword(p) == W({1, 2, 1}));
presentation::replace_subword(p, W({1, 2, 1}), W({3}));
presentation::add_rule(p, {3}, {1, 2, 1});
REQUIRE(p.rules
== std::vector<W>({{0, 3},
{3},
{3},
{1, 3},
{1, 3},
{1, 1},
{1, 1},
{3},
{3},
{0},
{3},
{1, 2, 1}}));
}
{
// Non-normalized alphabet
Presentation<W> p;
presentation::add_rule(p, {1, 2, 4, 2}, {2, 4, 2});
presentation::add_rule(p, {2, 4, 2}, {2, 2, 4, 2});
presentation::add_rule(p, {2, 2, 4, 2}, {2, 2});
presentation::add_rule(p, {2, 2}, {2, 4, 2});
presentation::add_rule(p, {2, 4, 2}, {1});
p.alphabet_from_rules();
REQUIRE(presentation::longest_common_subword(p) == W({2, 4, 2}));
presentation::replace_subword(p, W({2, 4, 2}), W({0}));
presentation::add_rule(p, W({0}), W({2, 4, 2}));
REQUIRE(p.rules
== std::vector<W>({{1, 0},
{0},
{0},
{2, 0},
{2, 0},
{2, 2},
{2, 2},
{0},
{0},
{1},
{0},
{2, 4, 2}}));
}
}
template <
typename W>
void check_redundant_rule() {
FroidurePin<Bipartition> S;
S.add_generator(Bipartition({{1, -1}, {2, -2}, {3, -3}, {4, -4}}));
S.add_generator(Bipartition({{1, -2}, {2, -3}, {3, -4}, {4, -1}}));
S.add_generator(Bipartition({{1, -2}, {2, -1}, {3, -3}, {4, -4}}));
S.add_generator(Bipartition({{1, 2}, {3, -3}, {4, -4}, {-1, -2}}));
REQUIRE(S.size() == 105);
auto p = make<Presentation<W>>(S);
REQUIRE(presentation::length(p) == 359);
presentation::remove_duplicate_rules(p);
REQUIRE(presentation::length(p) == 359);
presentation::reduce_complements(p);
REQUIRE(presentation::length(p) == 359);
presentation::sort_each_rule(p);
presentation::sort_rules(p);
REQUIRE(presentation::length(p) == 359);
REQUIRE(p.rules.size() == 86);
p.alphabet_from_rules();
auto it = presentation::redundant_rule(p, std::chrono::milliseconds(100));
REQUIRE(*it == W({2, 1, 3, 1, 1, 2, 1, 2}));
REQUIRE(*(it + 1) == W({1, 1, 2, 1, 3, 1, 2, 1}));
p.rules.erase(it, it + 2);
p.validate();
// while (it != p.rules.cend()) { // Too time consuming and indeterminant
// REQUIRE(std::distance(it, p.rules.cend()) % 2 == 0);
// p.rules.erase(it, it + 2);
// p.validate();
// it = presentation::redundant_rule(p, std::chrono::milliseconds(8));
// }
REQUIRE(presentation::length(p) == 343);
REQUIRE(p.rules.size() == 84);
}
template <
typename W>
void check_shortlex_compare_concat() {
REQUIRE(detail::shortlex_compare_concat(
W({0, 1, 2, 1}), W({0}), W({1, 1, 2, 1}), W({0})));
}
template <
typename W>
void check_remove_trivial_rules() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::remove_trivial_rules(p),
LibsemigroupsException);
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 2, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 2, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
presentation::add_rule(p, {0}, {0});
presentation::add_rule(p, {1}, {1});
presentation::add_rule(p, {2}, {2});
presentation::remove_trivial_rules(p);
REQUIRE(
p.rules
== std::vector<W>(
{{0, 1, 2, 1}, {1, 2, 1}, {1, 1, 2, 1}, {1, 1}, {1, 2, 1}, {0}}));
presentation::remove_trivial_rules(p);
REQUIRE(
p.rules
== std::vector<W>(
{{0, 1, 2, 1}, {1, 2, 1}, {1, 1, 2, 1}, {1, 1}, {1, 2, 1}, {0}}));
}
template <
typename W>
void check_replace_subword() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_NOTHROW(presentation::replace_subword(p, W({0}), W({1})));
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
presentation::replace_subword(p, W({0}), W({1}));
REQUIRE(
p.rules
== std::vector<W>(
{{1, 1, 2, 1}, {1, 2, 1}, {1, 1, 2, 1}, {1, 1}, {1, 2, 1}, {1}}));
presentation::replace_subword(p, W({0}), W({1}));
REQUIRE(
p.rules
== std::vector<W>(
{{1, 1, 2, 1}, {1, 2, 1}, {1, 1, 2, 1}, {1, 1}, {1, 2, 1}, {1}}));
presentation::replace_subword(p, W({1, 2, 1}), W({0}));
REQUIRE(p.rules
== std::vector<W>({{1, 0}, {0}, {1, 0}, {1, 1}, {0}, {1}}));
presentation::replace_subword(p, W({42, 42}), W({0}));
REQUIRE(p.rules
== std::vector<W>({{1, 0}, {0}, {1, 0}, {1, 1}, {0}, {1}}));
p.rules.clear();
presentation::add_rule(
p, {1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1}, {1, 2, 1, 1, 2, 1, 2, 1});
presentation::replace_subword(p, W({1, 2, 1}), W({1}));
REQUIRE(p.rules == std::vector<W>({{1, 2, 1, 1, 2, 1, 1}, {1, 1, 2, 1}}));
presentation::replace_subword(p, W({1, 2, 1}), W({1}));
REQUIRE(p.rules == std::vector<W>({{1, 1, 1}, {1, 1}}));
// Test for when existing is a suffix of replacement
p.rules.clear();
presentation::add_rule(
p, {1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1}, {1, 2, 1, 1, 2, 1, 2, 1});
presentation::replace_subword(p, W({1, 2}), W({1, 1, 2}));
REQUIRE(p.rules
== std::vector<W>(
{{1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1},
{1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1}}));
}
template <
typename W>
void check_replace_word() {
Presentation<W> p;
presentation::add_rule(p, {0, 1, 0}, {});
p.alphabet_from_rules();
presentation::replace_word(p, W({}), W({2}));
REQUIRE(p.rules == std::vector<W>{{0, 1, 0}, {2}});
p.rules.clear();
presentation::add_rule(p, {0, 1, 0}, {2, 1});
presentation::add_rule(p, {1, 1, 2}, {1, 2, 1});
presentation::add_rule(p, {2, 1, 2, 1}, {2, 2});
presentation::add_rule(p, {2, 1}, {0, 1, 1});
p.alphabet_from_rules();
presentation::replace_word(p, W({2, 1}), W({1, 2}));
REQUIRE(p.rules
== std::vector<W>{{0, 1, 0},
{1, 2},
{1, 1, 2},
{1, 2, 1},
{2, 1, 2, 1},
{2, 2},
{1, 2},
{0, 1, 1}});
p.rules.clear();
presentation::add_rule(p, {0, 1, 0}, {1, 0, 1});
presentation::add_rule(p, {0, 1, 1}, {1, 0, 1, 0});
p.alphabet_from_rules();
presentation::replace_word(p, W({1, 0, 1}), W({}));
REQUIRE(p.rules
== std::vector<W>{{0, 1, 0}, {}, {0, 1, 1}, {1, 0, 1, 0}});
}
template <
typename W>
void check_longest_rule() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::longest_rule(p), LibsemigroupsException);
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
REQUIRE(*presentation::longest_rule(p) == W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(*presentation::longest_rule(
presentation::longest_rule(p) + 1, p.rules.cend()),
LibsemigroupsException);
REQUIRE(*presentation::longest_rule(presentation::longest_rule(p) + 2,
p.rules.cend())
== W({1, 1, 2, 1}));
REQUIRE(*presentation::shortest_rule(p) == W({1, 2, 1}));
REQUIRE(*presentation::shortest_rule(p.rules.cbegin(),
presentation::shortest_rule(p))
== W({1, 1, 2, 1}));
REQUIRE_THROWS_AS(
*presentation::shortest_rule(p.rules.cbegin(),
presentation::shortest_rule(p) - 1),
LibsemigroupsException);
}
template <
typename W>
void check_longest_rule_length() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::longest_rule_length(p),
LibsemigroupsException);
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
REQUIRE(presentation::longest_rule_length(p) == 7);
REQUIRE_THROWS_AS(presentation::longest_rule_length(
presentation::longest_rule(p) + 1, p.rules.cend()),
LibsemigroupsException);
REQUIRE(presentation::longest_rule_length(
presentation::longest_rule(p) + 2, p.rules.cend())
== 6);
REQUIRE(presentation::shortest_rule_length(p) == 4);
REQUIRE_THROWS_AS(presentation::shortest_rule_length(
presentation::shortest_rule(p) + 1, p.rules.cend()),
LibsemigroupsException);
REQUIRE(presentation::shortest_rule_length(p.rules.cbegin(),
p.rules.cend() - 2)
== 6);
}
template <
typename W>
void check_remove_redundant_generators() {
Presentation<W> p;
p.rules.push_back(W({0, 1, 2, 1}));
REQUIRE_THROWS_AS(presentation::remove_redundant_generators(p),
LibsemigroupsException);
p.rules.push_back(W({1, 2, 1}));
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
presentation::remove_redundant_generators(p);
REQUIRE(p.rules
== std::vector<W>(
{{1, 2, 1, 1, 2, 1}, {1, 2, 1}, {1, 1, 2, 1}, {1, 1}}));
presentation::remove_redundant_generators(p);
REQUIRE(p.rules
== std::vector<W>(
{{1, 2, 1, 1, 2, 1}, {1, 2, 1}, {1, 1, 2, 1}, {1, 1}}));
p.rules.clear();
presentation::add_rule(p, {0, 1, 2, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1}, {0});
presentation::add_rule(p, {1, 2, 1}, {0});
presentation::remove_redundant_generators(p);
REQUIRE(
p.rules
== std::vector<W>(
{{0, 0, 2, 0}, {0, 2, 0}, {0, 0, 2, 0}, {0, 0}, {0, 2, 0}, {0}}));
p.rules.clear();
presentation::add_rule(p, {0, 1, 2, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {0}, {1});
presentation::add_rule(p, {1, 2, 1}, {0});
presentation::remove_redundant_generators(p);
REQUIRE(
p.rules
== std::vector<W>(
{{0, 0, 2, 0}, {0, 2, 0}, {0, 0, 2, 0}, {0, 0}, {0, 2, 0}, {0}}));
p.rules.clear();
presentation::add_rule(p, {0, 1, 2, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1}, {0});
presentation::add_rule(p, {1, 2, 1}, {0});
presentation::remove_redundant_generators(p);
REQUIRE(
p.rules
== std::vector<W>(
{{0, 0, 2, 0}, {0, 2, 0}, {0, 0, 2, 0}, {0, 0}, {0, 2, 0}, {0}}));
}
template <
typename W>
void check_reverse() {
Presentation<W> p;
presentation::add_rule(p, {0, 1, 2, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
presentation::reverse(p);
REQUIRE(
p.rules
== std::vector<W>(
{{1, 2, 1, 0}, {1, 2, 1}, {1, 2, 1, 1}, {1, 1}, {1, 2, 1}, {0}}));
presentation::reverse(p);
REQUIRE(
p.rules
== std::vector<W>(
{{0, 1, 2, 1}, {1, 2, 1}, {1, 1, 2, 1}, {1, 1}, {1, 2, 1}, {0}}));
}
template <
typename W>
void check_in_alphabet() {
Presentation<W> p;
presentation::add_rule(p, {0, 1, 2, 1}, {1, 2, 1});
presentation::add_rule(p, {1, 1, 2, 1}, {1, 1});
presentation::add_rule(p, {1, 2, 1}, {0});
// Alphabet not set, so everything false
REQUIRE(!p.in_alphabet(0));
REQUIRE(!p.in_alphabet(1));
REQUIRE(!p.in_alphabet(2));
REQUIRE(!p.in_alphabet(3));
REQUIRE(!p.in_alphabet(42));
p.alphabet_from_rules();
REQUIRE(p.in_alphabet(0));
REQUIRE(p.in_alphabet(1));
REQUIRE(p.in_alphabet(2));
REQUIRE(!p.in_alphabet(3));
REQUIRE(!p.in_alphabet(42));
}
template <
typename W>
void check_make_semigroup() {
Presentation<W> p;
presentation::add_rule(p, {0, 0}, {});
presentation::add_rule(p, {1, 1}, {});
presentation::add_rule(p, {2, 2}, {});
presentation::add_rule(p, {0, 1, 0, 1, 0, 1}, {});
presentation::add_rule(p, {1, 2, 1, 0, 1, 2, 1, 0}, {});
presentation::add_rule(p, {2, 0, 2, 1, 2, 0, 2, 1}, {0, 3});
p.alphabet_from_rules();
auto e = presentation::make_semigroup(p);
REQUIRE(p.rules
== std::vector<W>({{0, 0},
{e},
{1, 1},
{e},
{2, 2},
{e},
{0, 1, 0, 1, 0, 1},
{e},
{1, 2, 1, 0, 1, 2, 1, 0},
{e},
{2, 0, 2, 1, 2, 0, 2, 1},
{0, 3},
{0, e},
{0},
{e, 0},
{0},
{1, e},
{1},
{e, 1},
{1},
{2, e},
{2},
{e, 2},
{2},
{3, e},
{3},
{e, 3},
{3},
{e, e},
{e}}));
REQUIRE(presentation::make_semigroup(p) == UNDEFINED);
}
}
// namespace
using detail::StaticVector1;
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"000",
"vectors of ints",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<word_type> p;
p.alphabet({0, 1, 2});
REQUIRE(p.alphabet() == word_type({0, 1, 2}));
REQUIRE_THROWS_AS(p.alphabet({0, 0}), LibsemigroupsException);
REQUIRE(p.alphabet() == word_type({0, 1, 2}));
presentation::add_rule(p, {0, 0, 0}, {0});
REQUIRE(std::distance(p.rules.cbegin(), p.rules.cend()) == 2);
REQUIRE(std::vector<word_type>(p.rules.cbegin(), p.rules.cend())
== std::vector<word_type>({{0, 0, 0}, {0}}));
presentation::add_rule_and_check(p, {0, 0, 0}, {0});
REQUIRE_THROWS_AS(presentation::add_rule_and_check(p, {0, 5, 0}, {0}),
LibsemigroupsException);
REQUIRE_THROWS_AS(presentation::add_rule_and_check(p, {}, {0}),
LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"001",
"strings",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
p.alphabet(
"abc");
REQUIRE(p.alphabet() ==
"abc");
REQUIRE_THROWS_AS(p.alphabet(
"aa"), LibsemigroupsException);
REQUIRE(p.alphabet() ==
"abc");
presentation::add_rule(p,
"aaa",
"a");
REQUIRE(std::distance(p.rules.cbegin(), p.rules.cend()) == 2);
REQUIRE(std::vector<std::string>(p.rules.cbegin(), p.rules.cend())
== std::vector<std::string>({
"aaa",
"a"}));
REQUIRE_THROWS_AS(presentation::add_rule_and_check(p,
"abz",
"a"),
LibsemigroupsException);
REQUIRE_THROWS_AS(presentation::add_rule_and_check(p,
"",
"a"),
LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"002",
"constructors (word_type)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<word_type> p;
p.alphabet({0, 1, 2});
presentation::add_rule(p, {0, 0, 0}, {0});
REQUIRE(p.rules.size() == 2);
presentation::add_rule_and_check(p, {0, 0, 0}, {0});
p.validate();
check_constructors(p);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"003",
"constructors (StaticVector1)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<StaticVector1<uint16_t, 16>> p;
p.alphabet({0, 1, 2});
presentation::add_rule(p, {0, 0, 0}, {0});
REQUIRE(p.rules.size() == 2);
presentation::add_rule_and_check(p, {0, 0, 0}, {0});
p.validate();
check_constructors(p);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"004",
"constructors (std::string)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
p.alphabet(
"abc");
presentation::add_rule(p,
"aaaa",
"aa");
REQUIRE(p.rules.size() == 2);
presentation::add_rule_and_check(p,
"aaa",
"aa");
p.validate();
check_constructors(p);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"005",
"alphabet + letters (word_type)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_alphabet_letters<word_type>();
check_alphabet_letters<StaticVector1<uint16_t, 16>>();
check_alphabet_letters<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"006",
"alphabet + letters (std::string)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
p.alphabet(
"abc");
REQUIRE(p.alphabet() ==
"abc");
REQUIRE(p.letter(0) ==
'a');
REQUIRE(p.letter(1) ==
'b');
REQUIRE(p.letter(2) ==
'c');
p.alphabet(4);
REQUIRE(p.alphabet().size() == 4);
p.validate();
REQUIRE_THROWS_AS(p.alphabet(
"abb"), LibsemigroupsException);
presentation::add_rule(p,
"abca",
"aa");
presentation::add_rule(p,
"eb",
"af");
presentation::add_rule(p,
"eb",
"abbbbbb");
p.alphabet_from_rules();
REQUIRE(p.alphabet() ==
"abcef");
REQUIRE(p.index(
'a') == 0);
REQUIRE(p.index(
'b') == 1);
REQUIRE(p.index(
'c') == 2);
REQUIRE(p.index(
'e') == 3);
REQUIRE(p.index(
'f') == 4);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"007",
"contains_empty_word",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_contains_empty_word<word_type>();
check_contains_empty_word<StaticVector1<uint16_t, 16>>();
check_contains_empty_word<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"008",
"validate_rules throws",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_validate_rules_throws<word_type>();
check_validate_rules_throws<StaticVector1<uint16_t, 16>>();
check_validate_rules_throws<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"009",
"helpers add_rule(s)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_add_rules<word_type>();
check_add_rules<StaticVector1<uint16_t, 10>>();
check_add_rules<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"010",
"helpers add_rule(s) (std::string)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
presentation::add_rule(p,
"abcb",
"aa");
Presentation<std::string> q;
presentation::add_rule(q,
"eb",
"af");
presentation::add_rule(q,
"eb",
"abbbbbbbbb");
presentation::add_rules(p, q);
REQUIRE(p.rules
== std::vector<std::string>(
{
"abcb",
"aa",
"eb",
"af",
"eb",
"abbbbbbbbb"}));
REQUIRE(q.rules
== std::vector<std::string>({
"eb",
"af",
"eb",
"abbbbbbbbb"}));
REQUIRE_THROWS_AS(p.validate(), LibsemigroupsException);
REQUIRE_THROWS_AS(q.validate(), LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"011",
"helpers add_identity_rules (std::vector/StaticVector1)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_add_identity_rules<word_type>();
check_add_identity_rules<StaticVector1<uint16_t, 10>>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"035",
"helpers add_zero_rules (std::vector/StaticVector1)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_add_zero_rules<word_type>();
check_add_zero_rules<StaticVector1<uint16_t, 10>>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"012",
"helpers add_identity_rules (std::string)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
presentation::add_rule(p,
"abcb",
"aa");
REQUIRE_THROWS_AS(presentation::add_identity_rules(p,
'a'),
LibsemigroupsException);
p.alphabet_from_rules();
presentation::add_identity_rules(p,
'a');
REQUIRE(p.rules
== std::vector<std::string>({
"abcb",
"aa",
"aa",
"a",
"ba",
"b",
"ab",
"b",
"ca",
"c",
"ac",
"c"}));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"036",
"helpers add_zero_rules (std::string)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
presentation::add_rule(p,
"abcb",
"aa");
REQUIRE_THROWS_AS(presentation::add_zero_rules(p,
'0'),
LibsemigroupsException);
p.alphabet(
"abc0");
presentation::add_zero_rules(p,
'0');
REQUIRE(p.rules
== std::vector<std::string>({
"abcb",
"aa",
"a0",
"0",
"0a",
"0",
"b0",
"0",
"0b",
"0",
"c0",
"0",
"0c",
"0",
"00",
"0"}));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"013",
"helpers add_inverse_rules (all)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_add_inverse_rules<word_type>();
check_add_inverse_rules<StaticVector1<uint16_t, 10>>();
check_add_inverse_rules<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"014",
"helpers add_inverse_rules (std::string)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
p.contains_empty_word(
false);
p.alphabet(
"aAbBcCe");
presentation::add_identity_rules(p,
'e');
presentation::add_inverse_rules(p,
"AaBbCce",
'e');
presentation::add_rule_and_check(p,
"aaCac",
"e");
presentation::add_rule_and_check(p,
"acbbACb",
"e");
presentation::add_rule_and_check(p,
"ABabccc",
"e");
REQUIRE(
p.rules
== std::vector<std::string>(
{
"ae",
"a",
"ea",
"a",
"Ae",
"A",
"eA",
"A",
"be",
"b",
"eb",
"b",
"Be",
"B",
"eB",
"B",
"ce",
"c",
"ec",
"c",
"Ce",
"C",
"eC",
"C",
"ee",
"e",
"aA",
"e",
"Aa",
"e",
"bB",
"e",
"Bb",
"e",
"cC",
"e",
"Cc",
"e",
"aaCac",
"e",
"acbbACb",
"e",
"ABabccc",
"e"}));
REQUIRE(!presentation::are_rules_sorted(p));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"015",
"helpers remove_duplicate_rules",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_remove_duplicate_rules<word_type>();
check_remove_duplicate_rules<StaticVector1<uint16_t, 10>>();
check_remove_duplicate_rules<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"016",
"helpers reduce_complements",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_reduce_complements<word_type>();
check_reduce_complements<StaticVector1<uint16_t, 10>>();
Presentation<std::string> p;
presentation::add_rule(p,
"abcb",
"bcb");
presentation::add_rule(p,
"bcb",
"bbcb");
presentation::add_rule(p,
"bbcb",
"bb");
presentation::add_rule(p,
"bb",
"bcb");
presentation::add_rule(p,
"bcb",
"a");
p.alphabet_from_rules();
presentation::reduce_complements(p);
presentation::sort_each_rule(p);
presentation::sort_rules(p);
REQUIRE(p.rules
== std::vector<std::string>(
{
"bb",
"a",
"bcb",
"a",
"abcb",
"a",
"bbcb",
"a"}));
REQUIRE(p.alphabet() ==
"abc");
presentation::normalize_alphabet(p);
REQUIRE(p.letter(0) == presentation::letter(p, 0));
REQUIRE(p.letter(1) == presentation::letter(p, 1));
REQUIRE(p.letter(2) == presentation::letter(p, 2));
p.validate();
presentation::add_rule(p,
"abcb",
"ecb");
REQUIRE(!p.in_alphabet(
'e'));
// Not valid
REQUIRE_THROWS_AS(presentation::normalize_alphabet(p),
LibsemigroupsException);
p.alphabet_from_rules();
presentation::add_rule(p,
"abcd",
"bcb");
REQUIRE_THROWS_AS(presentation::normalize_alphabet(p),
LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"017",
"helpers sort_each_rule",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_sort_each_rule<word_type>();
check_sort_each_rule<StaticVector1<uint16_t, 10>>();
check_sort_each_rule<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"018",
"helpers sort_rules",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_sort_rules<word_type>();
check_sort_rules<StaticVector1<uint16_t, 10>>();
check_sort_rules<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"019",
"helpers longest_common_subword/replace_subword",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_longest_common_subword<word_type>();
check_longest_common_subword<StaticVector1<uint16_t, 10>>();
check_longest_common_subword<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"020",
"helpers redundant_rule",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_redundant_rule<word_type>();
check_redundant_rule<StaticVector1<uint16_t, 10>>();
check_redundant_rule<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"021",
"helpers shortlex_compare_concat",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_shortlex_compare_concat<word_type>();
check_shortlex_compare_concat<StaticVector1<uint16_t, 10>>();
check_shortlex_compare_concat<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"022",
"helpers remove_trivial_rules",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_remove_trivial_rules<word_type>();
check_remove_trivial_rules<StaticVector1<uint16_t, 10>>();
check_remove_trivial_rules<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"023",
"helpers replace_subword (existing, replacement)",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_replace_subword<word_type>();
check_replace_subword<StaticVector1<uint16_t, 64>>();
check_replace_subword<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"030",
"helpers replace_word",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_replace_word<word_type>();
check_replace_word<StaticVector1<uint16_t, 10>>();
check_replace_word<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"024",
"helpers longest_rule",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_longest_rule<word_type>();
check_longest_rule<StaticVector1<uint16_t, 10>>();
check_longest_rule<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"025",
"helpers longest_rule_length",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_longest_rule_length<word_type>();
check_longest_rule_length<StaticVector1<uint16_t, 10>>();
check_longest_rule_length<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"026",
"helpers remove_redundant_generators",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_remove_redundant_generators<word_type>();
check_remove_redundant_generators<StaticVector1<uint16_t, 64>>();
check_remove_redundant_generators<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"027",
"helpers reverse",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_reverse<word_type>();
check_reverse<StaticVector1<uint16_t, 10>>();
check_reverse<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"028",
"in_alphabet",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
check_in_alphabet<word_type>();
check_in_alphabet<StaticVector1<uint16_t, 10>>();
check_in_alphabet<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"029",
"replace_subword with empty word",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
p.alphabet(2);
p.contains_empty_word(
true);
presentation::add_rule(p, {0, 0, 0}, {});
p.validate();
REQUIRE_THROWS_AS(presentation::replace_subword(p, {}, {2}),
LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"031",
"clear",
"[quick][presentation]") {
auto rg = ReportGuard(
false);
Presentation<std::string> p;
p.alphabet(2);
p.contains_empty_word(
true);
presentation::add_rule(p, {0, 0, 0}, {});
p.validate();
p.clear();
REQUIRE(p.alphabet().empty());
REQUIRE(p.rules.empty());
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"040",
"change_alphabet",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"ab");
presentation::add_rule_and_check(p,
"ba",
"abaaabaa");
presentation::replace_subword(p,
"ba");
presentation::change_alphabet(p,
"abc");
REQUIRE(p.rules == std::vector<std::string>({
"c",
"acaaca",
"c",
"ba"}));
REQUIRE(p.alphabet() ==
"abc");
REQUIRE_NOTHROW(p.validate());
// Alphabet wrong size
REQUIRE_THROWS_AS(presentation::change_alphabet(p,
"ab"),
LibsemigroupsException);
REQUIRE_THROWS_AS(presentation::change_alphabet(p,
"aab"),
LibsemigroupsException);
REQUIRE(p.alphabet() ==
"abc");
REQUIRE(p.rules == std::vector<std::string>({
"c",
"acaaca",
"c",
"ba"}));
presentation::change_alphabet(p,
"bac");
REQUIRE(p.rules == std::vector<std::string>({
"c",
"bcbbcb",
"c",
"ab"}));
REQUIRE(p.alphabet() ==
"bac");
presentation::change_alphabet(p,
"xyz");
REQUIRE(p.rules == std::vector<std::string>({
"z",
"xzxxzx",
"z",
"yx"}));
REQUIRE(p.alphabet() ==
"xyz");
presentation::change_alphabet(p,
"xyt");
REQUIRE(p.rules == std::vector<std::string>({
"t",
"xtxxtx",
"t",
"yx"}));
REQUIRE(p.alphabet() ==
"xyt");
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"032",
"letter",
"[quick][presentation]") {
Presentation<std::vector<uint16_t>> p;
REQUIRE_THROWS_AS(presentation::letter(p, 65536), LibsemigroupsException);
REQUIRE(presentation::letter(p, 10) == 10);
REQUIRE_THROWS_AS(presentation::character(65536), LibsemigroupsException);
REQUIRE(presentation::character(0) ==
'a');
REQUIRE(presentation::character(10) ==
'k');
IntegralRange<size_t> ir(0, 255);
Presentation<std::string> q;
REQUIRE(std::all_of(ir.cbegin(), ir.cend(), [&q](size_t i) {
return presentation::character(i) == presentation::letter(q, i);
}));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"033",
"normalize_alphabet",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"axy");
presentation::normalize_alphabet(p);
REQUIRE(p.alphabet() ==
"abc");
Presentation<word_type> q;
q.alphabet({0, 10, 12});
presentation::normalize_alphabet(q);
REQUIRE(q.alphabet() == word_type({0, 1, 2}));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"042",
"first_unused_letter/letter",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"ab");
presentation::add_rule_and_check(p,
"baabaa",
"ababa");
REQUIRE(presentation::first_unused_letter(p) ==
'c');
p.alphabet(
"abcdefghijklmnopq");
REQUIRE(presentation::first_unused_letter(p) ==
'r');
p.alphabet(
"abcdefghijklmnopqrstuvwxyz");
REQUIRE(presentation::first_unused_letter(p) ==
'A');
p.alphabet(
"abcdefgijklmnopqrstuvwxyz");
REQUIRE(presentation::first_unused_letter(p) ==
'h');
p.alphabet(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
REQUIRE(presentation::first_unused_letter(p) ==
'0');
p.alphabet(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ02");
REQUIRE(presentation::first_unused_letter(p) ==
'1');
std::string
const letters
=
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
std::unordered_set<letter_type> set;
for (size_t i = 0; i < letters.size(); ++i) {
REQUIRE(letters[i] == presentation::letter(p, i));
REQUIRE(set.insert(letters[i]).second);
}
for (size_t i = letters.size(); i < 255; ++i) {
REQUIRE(set.insert(presentation::letter(p, i)).second);
}
REQUIRE_THROWS_AS(presentation::letter(p, 255), LibsemigroupsException);
p.alphabet(255);
REQUIRE_THROWS_AS(presentation::first_unused_letter(p),
LibsemigroupsException);
REQUIRE_THROWS_AS(p.alphabet(256), LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"034",
"longest_common_subword issue",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"a");
presentation::add_rule_and_check(p,
"aaaaaaaaaaaaaaaaaaa",
"a");
REQUIRE(presentation::longest_common_subword(p) ==
"aaaaaa");
presentation::replace_subword(p,
"aaaaaa");
REQUIRE(presentation::longest_common_subword(p) ==
"");
REQUIRE(p.rules == std::vector<std::string>({
"bbba",
"a",
"b",
"aaaaaa"}));
REQUIRE(presentation::length(p) == 12);
p.rules = std::vector<std::string>({
"bba",
"a",
"b",
"aaaaaaaa"});
REQUIRE(presentation::length(p) == 13);
p.alphabet(
"ab");
presentation::add_rule_and_check(p,
"baaaaaaaaaaaaaaaaaaa",
"a");
REQUIRE(presentation::longest_common_subword(p) ==
"aaaaaa");
p.alphabet(
"ab");
p.rules.clear();
presentation::add_rule_and_check(p,
"aaaaaaaaaaaaaaaa",
"a");
presentation::add_rule_and_check(p,
"bbbbbbbbbbbbbbbb",
"b");
presentation::add_rule_and_check(p,
"abb",
"baa");
REQUIRE(presentation::length(p) == 40);
auto w = presentation::longest_common_subword(p);
REQUIRE(w ==
"bbbb");
presentation::replace_subword(p, w);
REQUIRE(presentation::length(p) == 33);
REQUIRE(
p.rules
== std::vector<std::string>(
{
"aaaaaaaaaaaaaaaa",
"a",
"cccc",
"b",
"abb",
"baa",
"c",
"bbbb"}));
w = presentation::longest_common_subword(p);
REQUIRE(w ==
"aaaa");
presentation::replace_subword(p, w);
REQUIRE(presentation::length(p) == 26);
REQUIRE(p.rules
== std::vector<std::string>({
"dddd",
"a",
"cccc",
"b",
"abb",
"baa",
"c",
"bbbb",
"d",
"aaaa"}));
w = presentation::longest_common_subword(p);
REQUIRE(w ==
"");
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"037",
"make_semigroup",
"[quick][presentation]") {
check_make_semigroup<word_type>();
check_make_semigroup<StaticVector1<uint16_t, 10>>();
check_make_semigroup<std::string>();
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"038",
"greedy_reduce_length",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"ab");
p.rules.clear();
presentation::add_rule_and_check(p,
"aaaaaaaaaaaaaaaa",
"a");
presentation::add_rule_and_check(p,
"bbbbbbbbbbbbbbbb",
"b");
presentation::add_rule_and_check(p,
"abb",
"baa");
REQUIRE(presentation::length(p) == 40);
presentation::greedy_reduce_length(p);
REQUIRE(presentation::length(p) == 26);
REQUIRE(p.rules
== std::vector<std::string>({
"dddd",
"a",
"cccc",
"b",
"abb",
"baa",
"c",
"bbbb",
"d",
"aaaa"}));
REQUIRE(presentation::longest_common_subword(p) ==
"");
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"039",
"aaaaaaaab = aaaaaaaaab strong compression",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"ab");
presentation::add_rule_and_check(p,
"aaaaaaaab",
"aaaaaaaaab");
REQUIRE(presentation::strongly_compress(p));
REQUIRE(p.rules == decltype(p.rules)({
"a",
"aa"}));
p.rules = {
"adadnadnasnamdnamdna",
"akdjskadjksajdaldja"};
p.alphabet_from_rules();
REQUIRE(presentation::strongly_compress(p));
REQUIRE(presentation::reduce_to_2_generators(p));
REQUIRE(
p.rules
== decltype(p.rules)({
"aaaaaaaaaaaaaaaaaaa",
"baaaaaaaaaaaaaaaaa"}));
// Only works for 1-relation monoids at present
p.alphabet(
"ab");
presentation::add_rule_and_check(p,
"aaaaaaaab",
"aaaaaaaaab");
presentation::add_rule_and_check(p,
"aaaaaaaab",
"aaaaaaaaab");
REQUIRE(!presentation::strongly_compress(p));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"043",
"case where strong compression doesn't work",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"ab");
presentation::add_rule_and_check(p,
"abaaaabab",
"abbabaaaab");
REQUIRE(presentation::strongly_compress(p));
REQUIRE(p.rules == decltype(p.rules)({
"abccdae",
"fgeabccd"}));
auto q = p;
REQUIRE(presentation::reduce_to_2_generators(q));
REQUIRE(q.rules == decltype(q.rules)({
"aaaaaaa",
"baaaaaaa"}));
q = p;
REQUIRE(presentation::reduce_to_2_generators(q, 1));
REQUIRE(q.rules == decltype(q.rules)({
"abbbbab",
"bbbabbbb"}));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"044",
"proof that",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"ab");
presentation::add_rule_and_check(p,
"aabb",
"aaabaaab");
REQUIRE(presentation::strongly_compress(p));
presentation::reverse(p);
REQUIRE(p.rules == decltype(p.rules)({
"cba",
"baadbaa"}));
auto q = p;
REQUIRE(presentation::reduce_to_2_generators(q));
REQUIRE(q.rules == decltype(q.rules)({
"aba",
"baaabaa"}));
q = p;
REQUIRE(presentation::reduce_to_2_generators(q, 1));
REQUIRE(q.rules == decltype(q.rules)({
"abb",
"bbbbbbb"}));
// Wrong index
REQUIRE_THROWS_AS(presentation::reduce_to_2_generators(q, 2),
LibsemigroupsException);
q = p;
presentation::add_rule_and_check(q,
"aabb",
"aaabaaab");
// not 1-relation
REQUIRE(!presentation::reduce_to_2_generators(q, 1));
q.rules = {
"aaaaa",
"a"};
REQUIRE(!presentation::reduce_to_2_generators(q));
q.rules = {
"aaaaa",
""};
REQUIRE(!presentation::reduce_to_2_generators(q));
q.rules = {
"abcacbabab",
""};
REQUIRE(!presentation::reduce_to_2_generators(q));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"045",
"decompression",
"[quick][presentation]") {
Presentation<std::string> p;
p.alphabet(
"ab");
p.rules = {
"aabb",
"aaabaab"};
REQUIRE(presentation::strongly_compress(p));
REQUIRE(p.rules == decltype(p.rules)({
"abc",
"aabdab"}));
REQUIRE(!presentation::reduce_to_2_generators(p));
presentation::reverse(p);
REQUIRE(presentation::reduce_to_2_generators(p));
REQUIRE(p.rules == decltype(p.rules)({
"aba",
"baabaa"}));
}
LIBSEMIGROUPS_TEST_CASE(
"Presentation",
"041",
"sort_rules bug",
"[quick][presentation]") {
std::string prefix1 =
"dabd", suffix1 =
"cbb", prefix2 =
"abbaba",
suffix2 =
"c";
REQUIRE(
!detail::shortlex_compare_concat(prefix1, suffix1, prefix2, suffix2));
Presentation<std::string> p;
p.alphabet(
"bacd");
p.rules = {
"baabbabaa",
"abaaba",
"abbaba",
"c",
"abb",
"d",
"daba",
"c",
"dabd",
"cbb",
"dbaca",
"caba",
"dbacc",
"cabc",
"dbacd",
"cabd",
"abaaba",
"baca",
"abaabc",
"bacc",
"abaabd",
"bacd",
"cbaaba",
"ddaca",
"cbaabc",
"ddacc",
"cbaabd",
"ddacd",
"cbbaba",
"dabc",
"dabcbb",
"cbbabd",
"bacaaba",
"ababaca",
"bacaabc",
"ababacc",
"bacaabd",
"ababacd",
"bacbaca",
"abadaca",
"bacbacc",
"abadacc",
"bacbacd",
"abadacd",
"dabcaba",
"cbbbaca",
"dabcabc",
"cbbbacc",
"dabcabd",
"cbbbacd",
"ddacaaba",
"cbabaca",
"ddacaabc",
"cbabacc",
"ddacaabd",
"cbabacd",
"ddacbaca",
"cbadaca",
"ddacbacc",
"cbadacc",
"ddacbacd",
"cbadacd",
"abababaca",
"dacaaba",
"abababacc",
"dacaabc",
"abababacd",
"dacaabd",
"ababadaca",
"dacbaca",
"ababadacc",
"dacbacc",
"ababadacd",
"dacbacd",
"daababaca",
"ccaaba",
"daababacc",
"ccaabc",
"daababacd",
"ccaabd",
"daabadaca",
"ccbaca",
"daabadacc",
"ccbacc",
"daabadacd",
"ccbacd",
"bacababaca",
"abadacaaba",
"bacababacc",
"abadacaabc",
"bacababacd",
"abadacaabd",
"bacabadaca",
"abadacbaca",
"bacabadacc",
"abadacbacc",
"bacabadacd",
"abadacbacd",
"dabcbabaca",
"cbbdacaaba",
"dabcbabacc",
"cbbdacaabc",
"dabcbabacd",
"cbbdacaabd",
"dabcbadaca",
"cbbdacbaca",
"dabcbadacc",
"cbbdacbacc",
"dabcbadacd",
"cbbdacbacd",
"abaaababaca",
"bacacaaba",
"abaaababacc",
"bacacaabc",
"abaaababacd",
"bacacaabd",
"abaaabadaca",
"bacacbaca",
"abaaabadacc",
"bacacbacc",
"abaaabadacd",
"bacacbacd",
"cbaaababaca",
"ddacacaaba",
"cbaaababacc",
"ddacacaabc",
"cbaaababacd",
"ddacacaabd",
"cbaaabadaca",
"ddacacbaca",
"cbaaabadacc",
"ddacacbacc",
"cbaaabadacd",
"ddacacbacd",
"cbbaababaca",
"dabccaaba",
"cbbaababacc",
"dabccaabc",
"cbbaababacd",
"dabccaabd",
"cbbaabadaca",
"dabccbaca",
"cbbaabadacc",
"dabccbacc",
"cbbaabadacd",
"dabccbacd",
"ddacababaca",
"cbadacaaba",
"ddacababacc",
"cbadacaabc",
"ddacababacd",
"cbadacaabd",
"ddacabadaca",
"cbadacbaca",
"ddacabadacc",
"cbadacbacc",
"ddacabadacd",
"cbadacbacd",
"ababadacbaca",
"dacabadaca",
"ababadacbacc",
"dacabadacc",
"ababadacbacd",
"dacabadacd",
"bacaaababaca",
"ababacacaaba",
"bacaaababacc",
"ababacacaabc",
"bacaaababacd",
"ababacacaabd",
"bacaaabadaca",
"ababacacbaca",
"bacaaabadacc",
"ababacacbacc",
"bacaaabadacd",
"ababacacbacd",
"daabadacbaca",
"ccabadaca",
"daabadacbacc",
"ccabadacc",
"daabadacbacd",
"ccabadacd",
"bacabadacbaca",
"abadacabadaca",
"bacabadacbacc",
"abadacabadacc",
"bacabadacbacd",
"abadacabadacd",
"dabcbadacaaba",
"cbbdacababaca",
"dabcbadacaabc",
"cbbdacababacc",
"dabcbadacaabd",
"cbbdacababacd",
"dabcbadacbaca",
"cbbdacabadaca",
"dabcbadacbacc",
"cbbdacabadacc",
"dabcbadacbacd",
"cbbdacabadacd",
"ddacaaababaca",
"cbabacacaaba",
"ddacaaababacc",
"cbabacacaabc",
"ddacaaababacd",
"cbabacacaabd",
"ddacaaabadaca",
"cbabacacbaca",
"ddacaaabadacc",
"cbabacacbacc",
"ddacaaabadacd",
"cbabacacbacd",
"abaaabadacbaca",
"bacacabadaca",
"abaaabadacbacc",
"bacacabadacc",
"abaaabadacbacd",
"bacacabadacd",
"cbaaabadacbaca",
"ddacacabadaca",
"cbaaabadacbacc",
"ddacacabadacc",
"cbaaabadacbacd",
"ddacacabadacd",
"cbbaabadacbaca",
"dabccabadaca",
"cbbaabadacbacc",
"dabccabadacc",
"cbbaabadacbacd",
"dabccabadacd",
"ddacabadacbaca",
"cbadacabadaca",
"ddacabadacbacc",
"cbadacabadacc",
"ddacabadacbacd",
"cbadacabadacd",
"bacaaabadacbaca",
"ababacacabadaca",
"bacaaabadacbacc",
"ababacacabadacc",
"bacaaabadacbacd",
"ababacacabadacd",
"dabcbabacacaaba",
"cbbdacaaababaca",
"dabcbabacacaabc",
"cbbdacaaababacc",
"dabcbabacacaabd",
"cbbdacaaababacd",
"dabcbabacacbaca",
"cbbdacaaabadaca",
"dabcbabacacbacc",
"cbbdacaaabadacc",
"dabcbabacacbacd",
"cbbdacaaabadacd",
"dabcbadacabadaca",
"cbbdacabadacbaca",
"dabcbadacabadacc",
"cbbdacabadacbacc"};
REQUIRE(p.rules.size() == 258);
p.validate();
presentation::sort_each_rule(p);
presentation::sort_rules(p);
REQUIRE(presentation::are_rules_sorted(p));
--> --------------------
--> maximum size reached
--> --------------------