27#ifndef LIBSEMIGROUPS_DETAIL_TODD_COXETER_IMPL_HPP_
28#define LIBSEMIGROUPS_DETAIL_TODD_COXETER_IMPL_HPP_
40#include "libsemigroups/constants.hpp"
41#include "libsemigroups/debug.hpp"
42#include "libsemigroups/forest.hpp"
43#include "libsemigroups/order.hpp"
44#include "libsemigroups/presentation.hpp"
45#include "libsemigroups/ranges.hpp"
46#include "libsemigroups/runner.hpp"
47#include "libsemigroups/to-presentation.hpp"
48#include "libsemigroups/types.hpp"
49#include "libsemigroups/word-graph.hpp"
51#include "cong-common-class.hpp"
52#include "felsch-graph.hpp"
53#include "node-managed-graph.hpp"
54#include "node-manager.hpp"
55#include "word-graph-with-sources.hpp"
157 class ToddCoxeterImpl :
public CongruenceCommon,
158 public FelschGraphSettings<ToddCoxeterImpl> {
159 using FelschGraphSettings_ = FelschGraphSettings<ToddCoxeterImpl>;
166 struct options :
public FelschGraphSettings_::options {
167 enum class strategy { hlt, felsch, CR, R_over_C, Cr, Rc };
169 enum class lookahead_extent { full, partial };
171 enum class lookahead_style { hlt, felsch };
173 enum class def_policy : uint8_t {
174 no_stack_if_no_space,
177 discard_all_if_no_space,
182 enum class state : uint8_t { none, hlt, felsch, lookahead };
185 using index_type = node_type;
197 friend class SettingsGuard;
199 struct NonAtomicStats {
200 using time_point = std::chrono::high_resolution_clock::time_point;
203 time_point create_or_init_time;
204 std::chrono::nanoseconds all_runs_time;
206 std::chrono::nanoseconds all_hlt_phases_time;
207 std::chrono::nanoseconds all_felsch_phases_time;
208 std::chrono::nanoseconds all_lookahead_phases_time;
210 uint64_t all_num_hlt_phases;
211 uint64_t all_num_felsch_phases;
212 uint64_t all_num_lookahead_phases;
215 time_point run_start_time;
217 uint64_t run_edges_active_at_start;
218 uint64_t run_nodes_active_at_start;
220 std::chrono::nanoseconds run_hlt_phases_time;
221 std::chrono::nanoseconds run_felsch_phases_time;
222 std::chrono::nanoseconds run_lookahead_phases_time;
224 uint64_t run_num_hlt_phases;
225 uint64_t run_num_felsch_phases;
226 uint64_t run_num_lookahead_phases;
228 uint64_t phase_index;
229 uint64_t phase_edges_active_at_start;
230 float phase_complete_at_start;
231 uint64_t phase_nodes_defined_at_start;
232 uint64_t phase_nodes_killed_at_start;
233 uint64_t phase_nodes_active_at_start;
234 time_point phase_start_time;
236 mutable uint64_t report_index;
237 mutable uint64_t report_edges_active_prev;
238 mutable float report_complete_prev;
239 mutable uint64_t report_nodes_defined_prev;
240 mutable uint64_t report_nodes_killed_prev;
241 mutable uint64_t report_nodes_active_prev;
249 NonAtomicStats& init();
251 NonAtomicStats(NonAtomicStats
const&) =
default;
252 NonAtomicStats(NonAtomicStats&&) =
default;
253 NonAtomicStats& operator=(NonAtomicStats
const&) =
default;
254 NonAtomicStats& operator=(NonAtomicStats&&) =
default;
257 struct Stats :
public NonAtomicStats {
259 std::atomic_uint64_t lookahead_nodes_killed;
260 std::atomic_uint64_t lookahead_position;
266 lookahead_nodes_killed(),
267 lookahead_position() {}
270 NonAtomicStats::init();
274 Stats(Stats
const& that)
275 : NonAtomicStats(that),
276 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
277 lookahead_position(that.lookahead_position.load()) {}
280 : NonAtomicStats(std::
move(that)),
281 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
282 lookahead_position(that.lookahead_position.load()) {}
284 Stats& operator=(Stats
const& that) {
285 NonAtomicStats::operator=(that);
286 lookahead_nodes_killed = that.lookahead_nodes_killed.load();
287 lookahead_position = that.lookahead_position.load();
291 Stats& operator=(Stats&& that) {
292 NonAtomicStats::operator=(
std::move(that));
293 lookahead_nodes_killed = that.lookahead_nodes_killed.load();
294 lookahead_position = that.lookahead_position.load();
299 void stats_run_start() {
302 _stats.run_nodes_active_at_start
304 _stats.run_edges_active_at_start
306 _stats.run_num_hlt_phases = 0;
307 _stats.run_num_felsch_phases = 0;
308 _stats.run_num_lookahead_phases = 0;
310 _stats.run_hlt_phases_time = std::chrono::nanoseconds(0);
311 _stats.run_felsch_phases_time = std::chrono::nanoseconds(0);
312 _stats.run_lookahead_phases_time = std::chrono::nanoseconds(0);
314 _stats.phase_index = 0;
317 void stats_run_stop() {
320 _stats.all_runs_time +=
delta(_stats.run_start_time);
321 _stats.all_num_hlt_phases += _stats.run_num_hlt_phases;
322 _stats.all_num_felsch_phases += _stats.run_num_felsch_phases;
323 _stats.all_num_lookahead_phases += _stats.run_num_lookahead_phases;
325 _stats.all_hlt_phases_time += _stats.run_hlt_phases_time;
326 _stats.all_felsch_phases_time += _stats.run_felsch_phases_time;
327 _stats.all_lookahead_phases_time += _stats.run_lookahead_phases_time;
330 void stats_phase_start() {
332 _stats.report_index = 0;
334 _stats.phase_nodes_active_at_start
336 _stats.phase_nodes_killed_at_start
338 _stats.phase_nodes_defined_at_start
341 _stats.phase_edges_active_at_start
343 _stats.phase_complete_at_start
347 void stats_phase_stop() {
348 _stats.phase_index++;
355 _stats.run_num_hlt_phases++;
356 _stats.run_hlt_phases_time +=
delta(_stats.phase_start_time);
359 case state::felsch: {
360 _stats.run_num_felsch_phases++;
361 _stats.run_felsch_phases_time +=
delta(_stats.phase_start_time);
364 case state::lookahead: {
365 _stats.run_num_lookahead_phases++;
366 _stats.run_lookahead_phases_time +=
delta(_stats.phase_start_time);
375 void stats_report_stop()
const {
376 _stats.report_index++;
388 DeferSet(uint64_t& receiver, uint64_t val)
389 : _receiver(receiver), _val(val) {}
391 operator uint64_t() {
406 using Definition = std::pair<node_type, label_type>;
410 std::vector<Definition> _definitions;
411 ToddCoxeterImpl
const* _tc;
414 Definitions() : _any_skipped(false), _definitions(), _tc(nullptr) {}
417 Definitions(Definitions
const&) =
default;
418 Definitions(Definitions&&) =
default;
419 Definitions& operator=(Definitions
const& that) =
default;
420 Definitions& operator=(Definitions&&) =
default;
423 void init(ToddCoxeterImpl
const* tc) {
424 _any_skipped =
false;
425 _definitions.clear();
429 void emplace_back(node_type c, label_type x);
431 [[nodiscard]]
bool any_skipped() const noexcept {
435 [[nodiscard]]
bool empty() const noexcept {
436 return _definitions.empty();
439 void pop(Definition& d) {
441 _definitions.pop_back();
445 _definitions.clear();
449 bool is_active_node(node_type n)
const noexcept {
450 return _tc->current_word_graph().is_active_node(n);
455 :
public FelschGraph<NodeManagedGraph<node_type>, Definitions> {
457 = FelschGraph<NodeManagedGraph<node_type>, Definitions>;
461 Graph(Graph
const&) =
default;
462 Graph(Graph&&) =
default;
463 Graph& operator=(Graph
const&) =
default;
464 Graph& operator=(Graph&&) =
default;
466 Graph& operator=(WordGraph<node_type>
const& wg) {
467 FelschGraph_::operator=(wg);
471 using FelschGraph_::presentation;
472 using FelschGraph_::target_no_checks;
478 WordGraph<node_type>
const& wg) {
479 FelschGraph_::operator=(wg);
480 FelschGraph_::presentation_no_checks(p);
486 void process_definitions();
488 template <
bool RegDefs>
489 void push_definition_hlt(node_type
const& c,
493 template <
typename Iterator>
494 void make_compatible(ToddCoxeterImpl* tc,
501 void report_lookahead_stop_early(ToddCoxeterImpl* tc,
503 size_t killed_last_interval);
513 std::vector<std::unique_ptr<Settings>> _settings_stack;
517 std::atomic<state> _state;
519 bool _ticker_running;
523 using word_graph_type = Graph;
530 ToddCoxeterImpl& init();
532 ToddCoxeterImpl(ToddCoxeterImpl
const& that);
533 ToddCoxeterImpl(ToddCoxeterImpl&&);
534 ToddCoxeterImpl& operator=(ToddCoxeterImpl
const&);
535 ToddCoxeterImpl& operator=(ToddCoxeterImpl&&);
547 template <
typename Node>
549 : ToddCoxeterImpl() {
550 LIBSEMIGROUPS_ASSERT(!_settings_stack.empty());
554 template <
typename Node>
569#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
573 template <
typename Node>
576 WordGraph<Node>
const& wg) {
581 template <
typename Node>
584 WordGraph<Node>
const& wg);
587 template <
typename Iterator1,
typename Iterator2>
588 void throw_if_letter_not_in_alphabet(Iterator1 first,
589 Iterator2 last)
const {
590 internal_presentation().throw_if_letter_not_in_alphabet(first, last);
597 template <
typename Iterator1,
601 ToddCoxeterImpl& add_generating_pair_no_checks(Iterator1 first1,
605 return CongruenceCommon::add_internal_generating_pair_no_checks<
606 ToddCoxeterImpl>(first1, last1, first2, last2);
609 template <
typename Iterator1,
613 ToddCoxeterImpl& add_generating_pair(Iterator1 first1,
617 return CongruenceCommon::add_generating_pair<ToddCoxeterImpl>(
618 first1, last1, first2, last2);
644 template <
typename Iterator1,
648 tril currently_contains_no_checks(Iterator1 first1,
651 Iterator4 last2)
const;
653 template <
typename Iterator1,
657 tril currently_contains(Iterator1 first1,
660 Iterator4 last2)
const {
661 return CongruenceCommon::currently_contains<ToddCoxeterImpl>(
662 first1, last1, first2, last2);
665 template <
typename Iterator1,
669 bool contains_no_checks(Iterator1 first1,
674 template <
typename Iterator1,
678 bool contains(Iterator1 first1,
687 template <
typename OutputIterator,
688 typename InputIterator1,
689 typename InputIterator2>
690 OutputIterator reduce_no_run_no_checks(OutputIterator d_first,
691 InputIterator1 first,
692 InputIterator2 last)
const;
694 template <
typename OutputIterator,
695 typename InputIterator1,
696 typename InputIterator2>
697 OutputIterator reduce_no_run(OutputIterator d_first,
698 InputIterator1 first,
699 InputIterator2 last)
const {
700 return CongruenceCommon::reduce_no_run<ToddCoxeterImpl>(
701 d_first, first, last);
704 template <
typename OutputIterator,
705 typename InputIterator1,
706 typename InputIterator2>
707 OutputIterator reduce_no_checks(OutputIterator d_first,
708 InputIterator1 first,
709 InputIterator2 last) {
710 return CongruenceCommon::reduce_no_checks<ToddCoxeterImpl>(
711 d_first, first, last);
714 template <
typename OutputIterator,
715 typename InputIterator1,
716 typename InputIterator2>
717 OutputIterator reduce(OutputIterator d_first,
718 InputIterator1 first,
719 InputIterator2 last) {
720 return CongruenceCommon::reduce<ToddCoxeterImpl>(d_first, first, last);
727#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
729 template <
typename Time>
755 ToddCoxeterImpl&
def_max(
size_t val)
noexcept;
766 [[nodiscard]]
size_t def_max() const noexcept;
847 [[nodiscard]]
size_t f_defs() const noexcept;
1276 ToddCoxeterImpl&
save(
bool val) noexcept;
1288 [[nodiscard]]
bool save() const noexcept;
1352#ifdef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1384 using FelschGraphSettings_::def_version;
1385 using FelschGraphSettings_::settings;
1392#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1394 internal_presentation() const noexcept {
1395 return _word_graph.presentation();
1623 return _standardized;
1671 return _word_graph.stats().num_large_collapses;
1778 template <
typename Iterator1,
typename Iterator2>
1780 Iterator2 last)
const;
1807 template <
typename Iterator1,
typename Iterator2>
1809 throw_if_letter_not_in_alphabet(first, last);
1838 template <
typename Iterator1,
typename Iterator2>
1866 template <
typename Iterator1,
typename Iterator2>
1868 throw_if_letter_not_in_alphabet(first, last);
1924 template <
typename OutputIterator>
1926 index_type i)
const;
1953 template <
typename OutputIterator>
1955 index_type i)
const;
1980 template <
typename Iterator>
2011 template <
typename Iterator>
2012 Iterator
word_of(Iterator d_first, index_type i) {
2025 void really_run_impl();
2027 void run_impl()
override;
2029 [[nodiscard]]
bool finished_impl()
const override {
2037 void copy_settings_into_graph();
2041 Settings& tc_settings();
2042 Settings
const& tc_settings()
const;
2044 void reset_settings_stack();
2046 [[nodiscard]]
bool any_change()
const {
2047 return _stats.run_nodes_active_at_start
2055 [[nodiscard]]
float complete(uint64_t num_nodes,
2056 int64_t num_edges)
const noexcept {
2057 return static_cast<float>(num_edges)
2058 / (
static_cast<uint64_t
>(num_nodes)
2062 [[nodiscard]]
float complete(int64_t num_edges)
const noexcept {
2067 [[nodiscard]]
bool lookahead_stop_early(
2069 std::chrono::high_resolution_clock::time_point& last_stop_early_check,
2070 uint64_t& killed_at_prev_interval);
2077 void finalise_run();
2082 void R_over_C_style();
2090 void report_after_phase()
const;
2091 void report_after_lookahead(
size_t old_lookahead_next)
const;
2092 void report_after_run()
const;
2093 void report_before_phase(std::string_view =
"")
const;
2094 void report_before_lookahead()
const;
2095 void report_before_run()
const;
2096 void report_lookahead_stop_early(
size_t expected,
2097 size_t killed_last_interval);
2098 void report_presentation()
const;
2099 void report_progress_from_thread(
bool divider)
const;
2100 void report_times()
const;
2102 void add_timing_row(ReportCell<5>& rc)
const;
2107 void add_nodes_rows(ReportCell<5>& rc, uint64_t num_active_nodes)
const;
2108 void add_edges_rows(ReportCell<5>& rc,
2109 uint64_t num_active_nodes,
2110 uint64_t num_active_edges)
const;
2111 void add_lookahead_row(ReportCell<5>& rc)
const;
2117 static constexpr bool StopEarly =
true;
2118 static constexpr bool DoNotStopEarly =
false;
2120 void hlt_lookahead(
bool stop_early);
2121 void felsch_lookahead(
bool stop_early);
2128#include "todd-coxeter-impl.tpp"
Class representing a collection of spanning trees of a word graph.
Definition forest.hpp:42
For an implementation of presentations for semigroups or monoids.
Definition presentation.hpp:103
nanoseconds report_every() const noexcept
Get the minimum elapsed time between reports.
Definition runner.hpp:227
static std::chrono::nanoseconds delta(std::chrono::high_resolution_clock::time_point const &t)
The time between a given point and now.
Definition runner.hpp:70
std::chrono::nanoseconds nanoseconds
Alias for std::chrono::nanoseconds.
Definition runner.hpp:102
void run()
Run until finished.
bool finished() const
Check if run has been run to completion or not.
Node node_type
The type of nodes in a word graph.
Definition word-graph.hpp:99
Node label_type
The type of edge labels in a word graph.
Definition word-graph.hpp:102
Presentation(Presentation< Word > const &) -> Presentation< Word >
Deduction guide.
float complete() const noexcept
Return the proportion of edges defined in the active part of the word graph.
Definition todd-coxeter-impl.hpp:1464
Forest const & current_spanning_tree() const noexcept
Get the current possible spanning tree of the underlying word graph.
Definition todd-coxeter-impl.hpp:1563
Forest const & spanning_tree()
Get the spanning tree of the underlying word graph.
uint64_t number_of_nodes_active() const noexcept
Return the number of nodes in the active part of the current word graph.
Definition todd-coxeter-impl.hpp:1420
word_graph_type const & current_word_graph() const noexcept
Get the current word graph.
Definition todd-coxeter-impl.hpp:1508
word_graph_type const & word_graph()
Get the word graph after performing a full congruence enumeration.
uint64_t number_of_edges_active() const noexcept
Return the number of edges in the active part of the current word graph.
Definition todd-coxeter-impl.hpp:1445
bool is_standardized(Order val) const
Check if the word graph is currently standardized with respect to a given order.
Order standardization_order() const noexcept
Get the current standardization order of the underlying word graph.
Definition todd-coxeter-impl.hpp:1622
bool is_standardized() const
Check if the word graph is currently standardized with respect to any order.
uint64_t number_of_large_collapses() const noexcept
Return the number of large collapses that have occurred.
Definition todd-coxeter-impl.hpp:1670
OutputIterator current_word_of(OutputIterator d_first, index_type i) const
Insert a current word representing a class with given index into an output iterator.
Iterator word_of_no_checks(Iterator d_first, index_type i)
Insert the word representing a class with given index into an output iterator.
Definition todd-coxeter-impl.hpp:1981
Iterator word_of(Iterator d_first, index_type i)
Insert the word representing a class with given index into an output iterator.
Definition todd-coxeter-impl.hpp:2012
OutputIterator current_word_of_no_checks(OutputIterator d_first, index_type i) const
Insert a current word representing a class with given index into an output iterator.
uint64_t number_of_classes()
Compute the number of classes in the congruence.
void perform_lookahead(bool stop_early)
Perform a lookahead.
void shrink_to_fit()
Shrink the underlying word graph to remove all dead nodes.
bool standardize(Order val)
Standardize the current_word_graph.
options::def_version def_version() const noexcept
Get the current value of the definition version setting.
ToddCoxeterImpl & lookahead_extent(options::lookahead_extent val) noexcept
Set the lookahead extent.
ToddCoxeterImpl & lookahead_growth_factor(float val)
Set the lookahead growth factor.
ToddCoxeterImpl & lookahead_style(options::lookahead_style val) noexcept
Set the style of lookahead.
ToddCoxeterImpl & lookahead_stop_early_ratio(float val)
Set the lookahead stop early ratio.
ToddCoxeterImpl & lookahead_next(size_t val) noexcept
Set the threshold that will trigger a lookahead.
ToddCoxeterImpl & lookahead_min(size_t val) noexcept
Set the minimum value of lookahead_next.
ToddCoxeterImpl & use_relations_in_extra(bool val) noexcept
Set whether or not to perform an HLT-style push of the defining relations at the identity.
size_t def_max() const noexcept
Get the current value of the setting for the maximum number of definitions.
ToddCoxeterImpl & def_version(options::def_version val)
Set the value of the definition version setting.
ToddCoxeterImpl & lookahead_growth_threshold(size_t val) noexcept
Set the lookahead growth threshold.
ToddCoxeterImpl & strategy(options::strategy val) noexcept
Specify the congruence enumeration strategy.
ToddCoxeterImpl & def_max(size_t val) noexcept
Set the maximum number of definitions in the stack.
ToddCoxeterImpl & def_policy(options::def_policy val)
Set the definition policy.
ToddCoxeterImpl & lookahead_stop_early_interval(std::chrono::nanoseconds val) noexcept
Set the lookahead stop early interval.
ToddCoxeterImpl & save(bool val) noexcept
Set whether or not to process definitions during HLT.
ToddCoxeterImpl & f_defs(size_t val)
Set the number of Felsch style definitions in ACE strategies.
ToddCoxeterImpl & lower_bound(size_t val) noexcept
Specify the minimum number of classes that may permit any enumeration early stop.
ToddCoxeterImpl & large_collapse(size_t val) noexcept
Set the size of a large collapse.
ToddCoxeterImpl & hlt_defs(size_t val)
Set the number of HLT style definitions in ACE strategies.
index_type current_index_of(Iterator1 first, Iterator2 last) const
Returns the current index of the class containing a word.
Definition todd-coxeter-impl.hpp:1808
index_type current_index_of_no_checks(Iterator1 first, Iterator2 last) const
Returns the current index of the class containing a word.
index_type index_of_no_checks(Iterator1 first, Iterator2 last)
Returns the index of the class containing a word.
index_type index_of(Iterator1 first, Iterator2 last)
Returns the index of the class containing a word.
Definition todd-coxeter-impl.hpp:1867
std::vector< letter_type > word_type
Type for a word over the generators of a semigroup.
Definition types.hpp:99
Order
The possible orderings of words and strings.
Definition order.hpp:45
tril
Enum to indicate true, false or not currently knowable.
Definition types.hpp:54
congruence_kind
Enum to indicate the sided-ness of a congruence.
Definition types.hpp:67
Namespace for everything in the libsemigroups library.
Definition action.hpp:44