Skip to content

Commit

Permalink
Rename Pruno to SimsRefinerFaithful
Browse files Browse the repository at this point in the history
  • Loading branch information
reiniscirpons committed Jul 11, 2024
1 parent 3e9ab19 commit 17ce9d9
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 53 deletions.
19 changes: 9 additions & 10 deletions benchmarks/bench-sims1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,20 +725,19 @@ namespace libsemigroups {
};
}

void bench_pruno(std::string const& name,
Presentation<word_type> const& p,
std::vector<word_type> const& forbid,
size_t target_size) {
Pruno pruno;
pruno.forbid = forbid;
Sims1 sims;
void bench_sims_refiner_faithful(std::string const& name,
Presentation<word_type> const& p,
std::vector<word_type> const& forbid,
size_t target_size) {
SimsRefinerFaithful pruno(forbid);
Sims1 sims;
sims.presentation(p).add_pruner(pruno);

size_t offset = p.contains_empty_word() ? 0 : 1;
auto return_true = [](auto const&) { return true; };

for (size_t i = 1; i <= std::thread::hardware_concurrency(); i *= 2) {
BENCHMARK(fmt::format(name + " - Pruno - {} / {} threads",
BENCHMARK(fmt::format(name + " - SimsRefinerFaithful - {} / {} threads",
i,
std::thread::hardware_concurrency())) {
Sims1::word_graph_type wg;
Expand Down Expand Up @@ -816,7 +815,7 @@ namespace libsemigroups {
}
}

TEST_CASE("Pruno", "[Pruno]") {
TEST_CASE("SimsRefinerFaithful", "[SimsRefinerFaithful]") {
auto rg = ReportGuard(false);

FroidurePin<Bipartition> S;
Expand Down Expand Up @@ -852,7 +851,7 @@ namespace libsemigroups {
{5, 9},
{6, 9}};

bench_pruno("Singular Brauer", p, forbid, S.size());
bench_sims_refiner_faithful("Singular Brauer", p, forbid, S.size());
bench_filter("Singular Brauer", p, forbid, S.size());
bench_orc("Singular Brauer", p, S.size());

Expand Down
128 changes: 89 additions & 39 deletions include/libsemigroups/sims.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
// * gap bindings

// TODO(later):
// * use Pruno in RepOrc + MinimalRepOrc
// * use SimsRefinerFaithful in RepOrc + MinimalRepOrc
// * a version which allows specifying the word_graph to Sims1 too
// * implement maximum_2_sided_congruence_contained to compute the kernel of the
// associated homomorphism, which is the largest 2-sided congruence contained
Expand Down Expand Up @@ -1303,7 +1303,7 @@ namespace libsemigroups {

uint64_t number_of_congruences(size_type n) const;
}; // SimsBase
} // namespace detail
} // namespace detail

namespace sims {
class const_cgp_iterator;
Expand Down Expand Up @@ -1764,7 +1764,7 @@ namespace libsemigroups {

using SimsBase::IteratorBase::stats;
}; // class iterator_base
}; // Sims2
}; // Sims2

//! \ingroup congruences_group
//!
Expand Down Expand Up @@ -2046,42 +2046,6 @@ namespace libsemigroups {
[[nodiscard]] Sims1::word_graph_type word_graph() const;
};

// This struct provides an alternative way of doing MinimalRepOrc, when the
// generating pairs of the minimal 2-sided congruences are known. These pairs
// should be added to forbid, and then your Pruno instance should be passed to
// a Sims1 object via add_pruner.
// TODO: probably rename this to describe functionality better
// TODO: Probably change interface to be consistent with Ideal finding
struct Pruno {
std::vector<word_type> forbid;
// TODO to cpp
bool operator()(Sims1::word_graph_type const& wg) {
auto first = forbid.cbegin(), last = forbid.cend();
// TODO use 1 felsch tree per excluded pairs, and use it to check if
// paths containing newly added edges, lead to the same place
for (auto it = first; it != last; it += 2) {
bool this_rule_compatible = true;
for (uint32_t n = 0; n < wg.number_of_active_nodes(); ++n) {
auto l = word_graph::follow_path_no_checks(wg, n, *it);
if (l != UNDEFINED) {
auto r = word_graph::follow_path_no_checks(wg, n, *(it + 1));
if (r == UNDEFINED || (r != UNDEFINED && l != r)) {
this_rule_compatible = false;
break;
}
} else {
this_rule_compatible = false;
break;
}
}
if (this_rule_compatible) {
return false;
}
}
return true;
}
};

namespace sims {
class const_cgp_iterator;

Expand Down Expand Up @@ -3048,6 +3012,92 @@ namespace libsemigroups {
// }
} // namespace sims

//! \ingroup congruences_group
//!
//! \brief For pruning the search tree when looking for congruences arising
//! from right or two-sided congruences representing faithful actions.
//!
//! Defined in ``sims.hpp``.
//!
//! This class provides a pruner for pruning the search tree when looking for
//! right congruences representing faithful actions. A right congruence
//! represents a faithful action if and only if it does not contain any
//! non-trivial two-sided congruence. Equivalently, a word graph of a right
//! congruence represents a faithful action if and only if there is no
//! nontrivial pair of words \f$(u, v)\f$ such that every vertex of the word
//! graph is compatible with \f$(u, v)\f$.
//!
//! \sa \ref SimsSettings::pruners
//! \sa \ref SimsSettings::add_pruner
// This struct provides an alternative way of doing MinimalRepOrc, when the
// generating pairs of the minimal 2-sided congruences are known. These pairs
// should be added to forbid, and then your SimsRefinerFaithful instance
// should be passed to a Sims1 object via add_pruner.
// TODO: probably rename this to describe functionality better
// TODO: Probably change interface to be consistent with Ideal finding
class SimsRefinerFaithful {
private:
std::vector<word_type> _forbid;

public:
//! \brief Default constructor.
//!
//! Constructs a SimsRefinerFaithful pruner with respect to the set of
//! forbidden relations in \p forbid.
//!
//! If \p forbid contains no trivial pairs (i.e. pairs of words that are
//! equal in the underlying semigroup or monoid), then all word graphs
//! rejected by SimsRefinerFaithful are guaranteed to not be extendable to a
//! word graph representing a faithful congruence. Otherwise, the pruner
//! will incorrectly reject all word graphs.
//!
//! If in addition \p forbid is a set of relations
//! containing all minimal congruence generating pairs of a given semigroup
//! or monoid, then SimsRefinerFaithful will also correctly determine if a
//! complete word graph represents a faithful congruence. Otherwise, the
//! complete word graphs accepted by SimsRefinerFaithful are not guaranteed
//! to be faithful and must be checked by some other means.
//!
//! \warning
//! This method does not verify if \p forbid contains trivial pairs or not.
explicit SimsRefinerFaithful(std::vector<word_type> const& forbid)
: _forbid(forbid) {}

//! \brief Check if a word graph can be extended to one defining a faithful
//! congruence.
//!
//! Returns `false` if there is no way of adding edges and nodes to \par wg
//! which will result in a word graph defining a faithful congruence.
//! Otherwise returns `true`.
//!
// TODO to cpp
bool operator()(Sims1::word_graph_type const& wg) {
auto first = _forbid.cbegin(), last = _forbid.cend();
// TODO use 1 felsch tree per excluded pairs, and use it to check if
// paths containing newly added edges, lead to the same place
for (auto it = first; it != last; it += 2) {
bool this_rule_compatible = true;
for (uint32_t n = 0; n < wg.number_of_active_nodes(); ++n) {
auto l = word_graph::follow_path_no_checks(wg, n, *it);
if (l != UNDEFINED) {
auto r = word_graph::follow_path_no_checks(wg, n, *(it + 1));
if (r == UNDEFINED || (r != UNDEFINED && l != r)) {
this_rule_compatible = false;
break;
}
} else {
this_rule_compatible = false;
break;
}
}
if (this_rule_compatible) {
return false;
}
}
return true;
}
};

//! \ingroup congruences_group
//!
//! \brief For pruning the search tree when looking for congruences arising
Expand Down
37 changes: 33 additions & 4 deletions tests/test-sims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
#include "libsemigroups/detail/stl.hpp"
#include "libsemigroups/word-graph.hpp"
#include <cstdint>
#include <iterator>
#include <libsemigroups/constants.hpp>
#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
#define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER

#include <cstddef> // for size_t
#include <iostream> // for cout
#include <vector> // for vector
#include <random>
#include <vector> // for vector

#include "catch.hpp" // for REQUIRE, REQUIRE_THROWS_AS, REQUI...
#include "test-main.hpp" // for LIBSEMIGROUPS_TEST_CASE
Expand All @@ -42,6 +45,7 @@
#include "libsemigroups/types.hpp" // for word_type

#include "libsemigroups/detail/report.hpp"
#include "libsemigroups/ranges.hpp" // for operator|, to_vector

namespace libsemigroups {

Expand Down Expand Up @@ -894,8 +898,7 @@ namespace libsemigroups {
Sims1 sims;
sims.presentation(p);
{
Pruno pruno;
pruno.forbid = forbid;
SimsRefinerFaithful pruno(forbid);

auto const& wg = sims.number_of_threads(1).add_pruner(pruno).find_if(
82, [](auto const&) { return true; });
Expand Down Expand Up @@ -929,6 +932,20 @@ namespace libsemigroups {
REQUIRE(orc.target_size() == 82);
REQUIRE(orc.stats().total_pending_now == 3'626'612);
}
{
MinimalRepOrc orc;
SimsRefinerFaithful pruno(forbid);
p.contains_empty_word(true);
auto d
= orc.add_pruner(pruno)
.presentation(p)
.target_size(82)
// .number_of_threads(std::thread::hardware_concurrency())
.word_graph();
REQUIRE(d.number_of_nodes() == 18);
REQUIRE(orc.target_size() == 82);
REQUIRE(orc.stats().total_pending_now == 2'074'472);
}

// // p.contains_empty_word(false);

Expand Down Expand Up @@ -1096,7 +1113,7 @@ namespace libsemigroups {
{{4, 8}, {4, 5, 7}, {4, 7}, {5, 4, 7}};
Sims1 sims;
sims.presentation(p);
// TODO use Pruno instead
// TODO use SimsRefinerFaithful instead
for (auto it = forbid.cbegin(); it != forbid.cend(); it += 2) {
sims.exclude(*it, *(it + 1));
}
Expand Down Expand Up @@ -3837,6 +3854,12 @@ namespace libsemigroups {
Sims1 s(p);
s.number_of_threads(1).add_pruner(ip);
REQUIRE(s.number_of_congruences(15) == 15); // correct value is 15
REQUIRE(s.number_of_threads(2).number_of_congruences(15)
== 15); // correct value is 15
REQUIRE(s.number_of_threads(4).number_of_congruences(15)
== 15); // correct value is 15
REQUIRE(s.number_of_threads(8).number_of_congruences(15)
== 15); // correct value is 15

// p = partition_monoid(3, author::Machine);
// ip = SimsRefinerIdeals(to_presentation<std::string>(p));
Expand Down Expand Up @@ -3870,6 +3893,12 @@ namespace libsemigroups {
REQUIRE(s.number_of_congruences(7) == 12); // computed using GAP
for (size_t nr_classes = 8; nr_classes < 16; ++nr_classes)
REQUIRE(s.number_of_congruences(nr_classes) == 12); // computed using GAP
REQUIRE(s.number_of_threads(2).number_of_congruences(7)
== 12); // computed using GAP
REQUIRE(s.number_of_threads(4).number_of_congruences(7)
== 12); // computed using GAP
REQUIRE(s.number_of_threads(8).number_of_congruences(7)
== 12); // computed using GAP
}

// about 2 seconds
Expand Down

0 comments on commit 17ce9d9

Please sign in to comment.