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/types.hpp"
48#include "libsemigroups/word-graph.hpp"
50#include "cong-common-class.hpp"
51#include "felsch-graph.hpp"
52#include "node-managed-graph.hpp"
53#include "node-manager.hpp"
54#include "word-graph-with-sources.hpp"
156 class ToddCoxeterImpl :
public CongruenceCommon,
157 public FelschGraphSettings<ToddCoxeterImpl> {
158 using FelschGraphSettings_ = FelschGraphSettings<ToddCoxeterImpl>;
165 struct options :
public FelschGraphSettings_::options {
166 enum class strategy { hlt, felsch, CR, R_over_C, Cr, Rc };
168 enum class lookahead_extent { full, partial };
170 enum class lookahead_style { hlt, felsch };
172 enum class def_policy : uint8_t {
173 no_stack_if_no_space,
176 discard_all_if_no_space,
181 enum class state : uint8_t { none, hlt, felsch, lookahead };
184 using index_type = node_type;
196 friend class SettingsGuard;
198 struct NonAtomicStats {
199 using time_point = std::chrono::high_resolution_clock::time_point;
202 time_point create_or_init_time;
203 std::chrono::nanoseconds all_runs_time;
205 std::chrono::nanoseconds all_hlt_phases_time;
206 std::chrono::nanoseconds all_felsch_phases_time;
207 std::chrono::nanoseconds all_lookahead_phases_time;
209 uint64_t all_num_hlt_phases;
210 uint64_t all_num_felsch_phases;
211 uint64_t all_num_lookahead_phases;
214 time_point run_start_time;
216 uint64_t run_edges_active_at_start;
217 uint64_t run_nodes_active_at_start;
219 std::chrono::nanoseconds run_hlt_phases_time;
220 std::chrono::nanoseconds run_felsch_phases_time;
221 std::chrono::nanoseconds run_lookahead_phases_time;
223 uint64_t run_num_hlt_phases;
224 uint64_t run_num_felsch_phases;
225 uint64_t run_num_lookahead_phases;
227 uint64_t phase_index;
228 uint64_t phase_edges_active_at_start;
229 float phase_complete_at_start;
230 uint64_t phase_nodes_defined_at_start;
231 uint64_t phase_nodes_killed_at_start;
232 uint64_t phase_nodes_active_at_start;
233 time_point phase_start_time;
235 mutable uint64_t report_index;
236 mutable uint64_t report_edges_active_prev;
237 mutable float report_complete_prev;
238 mutable uint64_t report_nodes_defined_prev;
239 mutable uint64_t report_nodes_killed_prev;
240 mutable uint64_t report_nodes_active_prev;
248 NonAtomicStats& init();
250 NonAtomicStats(NonAtomicStats
const&) =
default;
251 NonAtomicStats(NonAtomicStats&&) =
default;
252 NonAtomicStats& operator=(NonAtomicStats
const&) =
default;
253 NonAtomicStats& operator=(NonAtomicStats&&) =
default;
256 struct Stats :
public NonAtomicStats {
258 std::atomic_uint64_t lookahead_nodes_killed;
259 std::atomic_uint64_t lookahead_position;
265 lookahead_nodes_killed(),
266 lookahead_position() {}
269 NonAtomicStats::init();
273 Stats(Stats
const& that)
274 : NonAtomicStats(that),
275 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
276 lookahead_position(that.lookahead_position.load()) {}
279 : NonAtomicStats(std::
move(that)),
280 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
281 lookahead_position(that.lookahead_position.load()) {}
283 Stats& operator=(Stats
const& that) {
284 NonAtomicStats::operator=(that);
285 lookahead_nodes_killed = that.lookahead_nodes_killed.load();
286 lookahead_position = that.lookahead_position.load();
290 Stats& operator=(Stats&& that) {
291 NonAtomicStats::operator=(
std::move(that));
292 lookahead_nodes_killed = that.lookahead_nodes_killed.load();
293 lookahead_position = that.lookahead_position.load();
298 void stats_run_start() {
301 _stats.run_nodes_active_at_start
303 _stats.run_edges_active_at_start
305 _stats.run_num_hlt_phases = 0;
306 _stats.run_num_felsch_phases = 0;
307 _stats.run_num_lookahead_phases = 0;
309 _stats.run_hlt_phases_time = std::chrono::nanoseconds(0);
310 _stats.run_felsch_phases_time = std::chrono::nanoseconds(0);
311 _stats.run_lookahead_phases_time = std::chrono::nanoseconds(0);
313 _stats.phase_index = 0;
316 void stats_run_stop() {
319 _stats.all_runs_time +=
delta(_stats.run_start_time);
320 _stats.all_num_hlt_phases += _stats.run_num_hlt_phases;
321 _stats.all_num_felsch_phases += _stats.run_num_felsch_phases;
322 _stats.all_num_lookahead_phases += _stats.run_num_lookahead_phases;
324 _stats.all_hlt_phases_time += _stats.run_hlt_phases_time;
325 _stats.all_felsch_phases_time += _stats.run_felsch_phases_time;
326 _stats.all_lookahead_phases_time += _stats.run_lookahead_phases_time;
329 void stats_phase_start() {
331 _stats.report_index = 0;
333 _stats.phase_nodes_active_at_start
335 _stats.phase_nodes_killed_at_start
337 _stats.phase_nodes_defined_at_start
340 _stats.phase_edges_active_at_start
342 _stats.phase_complete_at_start
346 void stats_phase_stop() {
347 _stats.phase_index++;
354 _stats.run_num_hlt_phases++;
355 _stats.run_hlt_phases_time +=
delta(_stats.phase_start_time);
358 case state::felsch: {
359 _stats.run_num_felsch_phases++;
360 _stats.run_felsch_phases_time +=
delta(_stats.phase_start_time);
363 case state::lookahead: {
364 _stats.run_num_lookahead_phases++;
365 _stats.run_lookahead_phases_time +=
delta(_stats.phase_start_time);
374 void stats_report_stop()
const {
375 _stats.report_index++;
387 DeferSet(uint64_t& receiver, uint64_t val)
388 : _receiver(receiver), _val(val) {}
390 operator uint64_t() {
405 using Definition = std::pair<node_type, label_type>;
409 std::vector<Definition> _definitions;
410 ToddCoxeterImpl
const* _tc;
413 Definitions() : _any_skipped(false), _definitions(), _tc(nullptr) {}
416 Definitions(Definitions
const&) =
default;
417 Definitions(Definitions&&) =
default;
418 Definitions& operator=(Definitions
const& that) =
default;
419 Definitions& operator=(Definitions&&) =
default;
422 void init(ToddCoxeterImpl
const* tc) {
423 _any_skipped =
false;
424 _definitions.clear();
428 void emplace_back(node_type c, label_type x);
430 [[nodiscard]]
bool any_skipped() const noexcept {
434 [[nodiscard]]
bool empty() const noexcept {
435 return _definitions.empty();
438 void pop(Definition& d) {
440 _definitions.pop_back();
444 _definitions.clear();
448 bool is_active_node(node_type n)
const noexcept {
449 return _tc->current_word_graph().is_active_node(n);
454 :
public FelschGraph<NodeManagedGraph<node_type>, Definitions> {
456 = FelschGraph<NodeManagedGraph<node_type>, Definitions>;
460 Graph(Graph
const&) =
default;
461 Graph(Graph&&) =
default;
462 Graph& operator=(Graph
const&) =
default;
463 Graph& operator=(Graph&&) =
default;
465 Graph& operator=(WordGraph<node_type>
const& wg) {
466 FelschGraph_::operator=(wg);
470 using FelschGraph_::presentation;
471 using FelschGraph_::target_no_checks;
477 WordGraph<node_type>
const& wg) {
478 FelschGraph_::operator=(wg);
479 FelschGraph_::presentation_no_checks(p);
485 void process_definitions();
487 template <
bool RegDefs>
488 void push_definition_hlt(node_type
const& c,
492 template <
typename Iterator>
493 void make_compatible(ToddCoxeterImpl* tc,
500 void report_lookahead_stop_early(ToddCoxeterImpl* tc,
502 size_t killed_last_interval);
512 std::vector<std::unique_ptr<Settings>> _settings_stack;
516 std::atomic<state> _state;
518 bool _ticker_running;
522 using word_graph_type = Graph;
529 ToddCoxeterImpl& init();
531 ToddCoxeterImpl(ToddCoxeterImpl
const& that);
532 ToddCoxeterImpl(ToddCoxeterImpl&&);
533 ToddCoxeterImpl& operator=(ToddCoxeterImpl
const&);
534 ToddCoxeterImpl& operator=(ToddCoxeterImpl&&);
546 template <
typename Node>
548 : ToddCoxeterImpl() {
549 LIBSEMIGROUPS_ASSERT(!_settings_stack.empty());
553 template <
typename Node>
568#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
572 template <
typename Node>
575 WordGraph<Node>
const& wg) {
580 template <
typename Node>
583 WordGraph<Node>
const& wg);
586 template <
typename Iterator1,
typename Iterator2>
587 void throw_if_letter_not_in_alphabet(Iterator1 first,
588 Iterator2 last)
const {
589 internal_presentation().throw_if_letter_not_in_alphabet(first, last);
596 template <
typename Iterator1,
600 ToddCoxeterImpl& add_generating_pair_no_checks(Iterator1 first1,
604 return CongruenceCommon::add_internal_generating_pair_no_checks<
605 ToddCoxeterImpl>(first1, last1, first2, last2);
608 template <
typename Iterator1,
612 ToddCoxeterImpl& add_generating_pair(Iterator1 first1,
616 return CongruenceCommon::add_generating_pair<ToddCoxeterImpl>(
617 first1, last1, first2, last2);
643 template <
typename Iterator1,
647 tril currently_contains_no_checks(Iterator1 first1,
650 Iterator4 last2)
const;
652 template <
typename Iterator1,
656 tril currently_contains(Iterator1 first1,
659 Iterator4 last2)
const {
660 return CongruenceCommon::currently_contains<ToddCoxeterImpl>(
661 first1, last1, first2, last2);
664 template <
typename Iterator1,
668 bool contains_no_checks(Iterator1 first1,
673 template <
typename Iterator1,
677 bool contains(Iterator1 first1,
686 template <
typename OutputIterator,
687 typename InputIterator1,
688 typename InputIterator2>
689 OutputIterator reduce_no_run_no_checks(OutputIterator d_first,
690 InputIterator1 first,
691 InputIterator2 last)
const;
693 template <
typename OutputIterator,
694 typename InputIterator1,
695 typename InputIterator2>
696 OutputIterator reduce_no_run(OutputIterator d_first,
697 InputIterator1 first,
698 InputIterator2 last)
const {
699 return CongruenceCommon::reduce_no_run<ToddCoxeterImpl>(
700 d_first, first, last);
703 template <
typename OutputIterator,
704 typename InputIterator1,
705 typename InputIterator2>
706 OutputIterator reduce_no_checks(OutputIterator d_first,
707 InputIterator1 first,
708 InputIterator2 last) {
709 return CongruenceCommon::reduce_no_checks<ToddCoxeterImpl>(
710 d_first, first, last);
713 template <
typename OutputIterator,
714 typename InputIterator1,
715 typename InputIterator2>
716 OutputIterator reduce(OutputIterator d_first,
717 InputIterator1 first,
718 InputIterator2 last) {
719 return CongruenceCommon::reduce<ToddCoxeterImpl>(d_first, first, last);
726#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
728 template <
typename Time>
730#pragma GCC diagnostic push
731#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
733#pragma GCC diagnostic pop
737#pragma GCC diagnostic push
738#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
740#pragma GCC diagnostic pop
760 ToddCoxeterImpl&
def_max(
size_t val)
noexcept;
771 [[nodiscard]]
size_t def_max() const noexcept;
852 [[nodiscard]]
size_t f_defs() const noexcept;
1281 ToddCoxeterImpl&
save(
bool val) noexcept;
1293 [[nodiscard]]
bool save() const noexcept;
1357#ifdef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1389 using FelschGraphSettings_::def_version;
1390 using FelschGraphSettings_::settings;
1397#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1399 internal_presentation() const noexcept {
1400 return _word_graph.presentation();
1628 return _standardized;
1676 return _word_graph.stats().num_large_collapses;
1783 template <
typename Iterator1,
typename Iterator2>
1785 Iterator2 last)
const;
1812 template <
typename Iterator1,
typename Iterator2>
1814 throw_if_letter_not_in_alphabet(first, last);
1843 template <
typename Iterator1,
typename Iterator2>
1871 template <
typename Iterator1,
typename Iterator2>
1873 throw_if_letter_not_in_alphabet(first, last);
1929 template <
typename OutputIterator>
1931 index_type i)
const;
1958 template <
typename OutputIterator>
1960 index_type i)
const;
1984 template <
typename Iterator>
2015 template <
typename Iterator>
2016 Iterator
word_of(Iterator d_first, index_type i) {
2029 void really_run_impl();
2031 void run_impl()
override;
2033 [[nodiscard]]
bool finished_impl()
const override {
2041 void copy_settings_into_graph();
2045 Settings& tc_settings();
2046 Settings
const& tc_settings()
const;
2048 void reset_settings_stack();
2050 [[nodiscard]]
bool any_change()
const {
2051 return _stats.run_nodes_active_at_start
2059 [[nodiscard]]
float complete(uint64_t num_nodes,
2060 int64_t num_edges)
const noexcept {
2061 return static_cast<float>(num_edges)
2062 / (
static_cast<uint64_t
>(num_nodes)
2066 [[nodiscard]]
float complete(int64_t num_edges)
const noexcept {
2071 [[nodiscard]]
bool lookahead_stop_early(
2073 std::chrono::high_resolution_clock::time_point& last_stop_early_check,
2074 uint64_t& killed_at_prev_interval);
2081 void finalise_run();
2086 void R_over_C_style();
2094 void report_after_phase()
const;
2095 void report_after_lookahead(
size_t old_lookahead_next)
const;
2096 void report_after_run()
const;
2097 void report_before_phase(std::string_view =
"")
const;
2098 void report_before_lookahead()
const;
2099 void report_before_run()
const;
2100 void report_lookahead_stop_early(
size_t expected,
2101 size_t killed_last_interval);
2102 void report_presentation()
const;
2103 void report_progress_from_thread(
bool divider)
const;
2104 void report_times()
const;
2106 void add_timing_row(ReportCell<5>& rc)
const;
2111 void add_nodes_rows(ReportCell<5>& rc, uint64_t num_active_nodes)
const;
2112 void add_edges_rows(ReportCell<5>& rc,
2113 uint64_t num_active_nodes,
2114 uint64_t num_active_edges)
const;
2115 void add_lookahead_row(ReportCell<5>& rc)
const;
2121 static constexpr bool StopEarly =
true;
2122 static constexpr bool DoNotStopEarly =
false;
2124 void hlt_lookahead(
bool stop_early);
2125 void felsch_lookahead(
bool stop_early);
2132#include "todd-coxeter-impl.tpp"
Class representing a collection of spanning trees of a word graph.
Definition forest.hpp:46
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:236
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:1469
Forest const & current_spanning_tree() const noexcept
Get the current possible spanning tree of the underlying word graph.
Definition todd-coxeter-impl.hpp:1568
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:1425
word_graph_type const & current_word_graph() const noexcept
Get the current word graph.
Definition todd-coxeter-impl.hpp:1513
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:1450
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:1627
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:1675
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:1985
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:2016
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:1813
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:1872
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:54
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