libsemigroups  v3.3.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
todd-coxeter-impl.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2019-2025 James D. Mitchell
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17//
18
19// This file contains a declaration of a class for performing the Todd-Coxeter
20// algorithm for semigroups and monoids.
21//
22// TODO(1)
23// * re-implement reserve
24// * remove preferred_defs from FelschGraph etc (except where they are really
25// needed)? Or possibly reintroduce PrefDefs here
26
27#ifndef LIBSEMIGROUPS_DETAIL_TODD_COXETER_IMPL_HPP_
28#define LIBSEMIGROUPS_DETAIL_TODD_COXETER_IMPL_HPP_
29
30#include <chrono> // for nanoseconds
31#include <cstddef> // for size_t
32#include <cstdint> // for uint32_t
33#include <iterator> // for bidirect...
34#include <memory> // for unique_ptr
35#include <numeric> // for iota
36#include <string> // for string
37#include <utility> // for move, pair
38#include <vector> // for vector
39
40#include "libsemigroups/constants.hpp" // for operator!=
41#include "libsemigroups/debug.hpp" // for LIBSEMIG...
42#include "libsemigroups/forest.hpp" // for Forest
43#include "libsemigroups/order.hpp" // for Order
44#include "libsemigroups/presentation.hpp" // for Presenta...
45#include "libsemigroups/ranges.hpp" // for operator|
46#include "libsemigroups/runner.hpp" // for Reporter
47#include "libsemigroups/types.hpp" // for word_type
48#include "libsemigroups/word-graph.hpp" // for WordGraph
49
50#include "cong-common-class.hpp" // for Congruen...
51#include "felsch-graph.hpp" // for FelschGraph
52#include "node-managed-graph.hpp" // for NodeMana...
53#include "node-manager.hpp" // for NodeMana...
54#include "word-graph-with-sources.hpp" // for WordGrap...
55
57// This file is organised as follows:
58// 0. ToddCoxeterImpl - member types - public
59// 1. ToddCoxeterImpl - nested classes - private
60// 2. ToddCoxeterImpl - data members - private
61// 3. ToddCoxeterImpl - constructors + initializers - public
62// 4. ToddCoxeterImpl - interface requirements - add_generating_pair
63// 5. ToddCoxeterImpl - interface requirements - number_of_classes
64// 6. ToddCoxeterImpl - interface requirements - contains
65// 7. ToddCoxeterImpl - interface requirements - reduce
66// 8. ToddCoxeterImpl - settings - public
67// 9. ToddCoxeterImpl - accessors - public
68// 10. ToddCoxeterImpl - modifiers - public
69// 11. ToddCoxeterImpl - word -> index
70// 12. ToddCoxeterImpl - index -> word
71// 13. Runner - pure virtual member functions - private
72// 14. ToddCoxeterImpl - member functions - private
74
75namespace libsemigroups {
76
77 // NOTE: groups are defined here because the order they are declared is the
78 // order they appear in the output doc.
79
87
102
118
128
142
154
155 namespace detail {
156 class ToddCoxeterImpl : public CongruenceCommon,
157 public FelschGraphSettings<ToddCoxeterImpl> {
158 using FelschGraphSettings_ = FelschGraphSettings<ToddCoxeterImpl>;
159
160 public:
162 // 0. ToddCoxeterImpl - member types - public
164
165 struct options : public FelschGraphSettings_::options {
166 enum class strategy { hlt, felsch, CR, R_over_C, Cr, Rc };
167
168 enum class lookahead_extent { full, partial };
169
170 enum class lookahead_style { hlt, felsch };
171
172 enum class def_policy : uint8_t {
173 no_stack_if_no_space,
174 purge_from_top,
175 purge_all,
176 discard_all_if_no_space,
177 unlimited
178 };
179 }; // struct options
180
181 enum class state : uint8_t { none, hlt, felsch, lookahead };
182
183 using node_type = typename WordGraph<uint32_t>::node_type;
184 using index_type = node_type;
185 using label_type = typename WordGraph<uint32_t>::label_type;
186 using native_word_type = word_type;
187
188 private:
190 // 1. ToddCoxeterImpl - nested classes - private
192
193 struct Settings;
194
195 class SettingsGuard;
196 friend class SettingsGuard;
197
198 struct NonAtomicStats {
199 using time_point = std::chrono::high_resolution_clock::time_point;
200
201 // Data
202 time_point create_or_init_time;
203 std::chrono::nanoseconds all_runs_time;
204
205 std::chrono::nanoseconds all_hlt_phases_time;
206 std::chrono::nanoseconds all_felsch_phases_time;
207 std::chrono::nanoseconds all_lookahead_phases_time;
208
209 uint64_t all_num_hlt_phases;
210 uint64_t all_num_felsch_phases;
211 uint64_t all_num_lookahead_phases;
212
213 uint64_t run_index;
214 time_point run_start_time;
215
216 uint64_t run_edges_active_at_start;
217 uint64_t run_nodes_active_at_start;
218
219 std::chrono::nanoseconds run_hlt_phases_time;
220 std::chrono::nanoseconds run_felsch_phases_time;
221 std::chrono::nanoseconds run_lookahead_phases_time;
222
223 uint64_t run_num_hlt_phases;
224 uint64_t run_num_felsch_phases;
225 uint64_t run_num_lookahead_phases;
226
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;
234
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;
241
242 // Constructors + initializers
243
244 NonAtomicStats() {
245 init();
246 }
247
248 NonAtomicStats& init();
249
250 NonAtomicStats(NonAtomicStats const&) = default;
251 NonAtomicStats(NonAtomicStats&&) = default;
252 NonAtomicStats& operator=(NonAtomicStats const&) = default;
253 NonAtomicStats& operator=(NonAtomicStats&&) = default;
254 };
255
256 struct Stats : public NonAtomicStats {
257 // Data
258 std::atomic_uint64_t lookahead_nodes_killed;
259 std::atomic_uint64_t lookahead_position;
260
261 // Constructors + initialisers
262
263 Stats()
264 : NonAtomicStats(),
265 lookahead_nodes_killed(),
266 lookahead_position() {}
267
268 Stats& init() {
269 NonAtomicStats::init();
270 return *this;
271 }
272
273 Stats(Stats const& that)
274 : NonAtomicStats(that),
275 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
276 lookahead_position(that.lookahead_position.load()) {}
277
278 Stats(Stats&& that)
279 : NonAtomicStats(std::move(that)),
280 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
281 lookahead_position(that.lookahead_position.load()) {}
282
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();
287 return *this;
288 }
289
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();
294 return *this;
295 }
296 };
297
298 void stats_run_start() {
299 _stats.run_start_time = std::chrono::high_resolution_clock::now();
300
301 _stats.run_nodes_active_at_start
302 = current_word_graph().number_of_nodes_active();
303 _stats.run_edges_active_at_start
304 = current_word_graph().number_of_edges_active();
305 _stats.run_num_hlt_phases = 0;
306 _stats.run_num_felsch_phases = 0;
307 _stats.run_num_lookahead_phases = 0;
308
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);
312
313 _stats.phase_index = 0;
314 }
315
316 void stats_run_stop() {
317 _stats.run_index++;
318
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;
323
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;
327 }
328
329 void stats_phase_start() {
330 _stats.phase_start_time = std::chrono::high_resolution_clock::now();
331 _stats.report_index = 0;
332
333 _stats.phase_nodes_active_at_start
334 = current_word_graph().number_of_nodes_active();
335 _stats.phase_nodes_killed_at_start
336 = current_word_graph().number_of_nodes_killed();
337 _stats.phase_nodes_defined_at_start
338 = current_word_graph().number_of_nodes_defined();
339
340 _stats.phase_edges_active_at_start
341 = current_word_graph().number_of_edges_active();
342 _stats.phase_complete_at_start
344 }
345
346 void stats_phase_stop() {
347 _stats.phase_index++;
348
349 switch (_state) {
350 case state::none: {
351 break;
352 }
353 case state::hlt: {
354 _stats.run_num_hlt_phases++;
355 _stats.run_hlt_phases_time += delta(_stats.phase_start_time);
356 break;
357 }
358 case state::felsch: {
359 _stats.run_num_felsch_phases++;
360 _stats.run_felsch_phases_time += delta(_stats.phase_start_time);
361 break;
362 }
363 case state::lookahead: {
364 _stats.run_num_lookahead_phases++;
365 _stats.run_lookahead_phases_time += delta(_stats.phase_start_time);
366 break;
367 }
368 default: {
369 break;
370 }
371 }
372 }
373
374 void stats_report_stop() const {
375 _stats.report_index++;
376 }
377
378 // Simple struct that allows the "receivers" value to be set to "val" but
379 // only when the object goes out of scope. Useful in reporting when
380 // we want to do something with an old value, then update the data member
381 // of Stats.
382 class DeferSet {
383 uint64_t& _receiver;
384 uint64_t _val;
385
386 public:
387 DeferSet(uint64_t& receiver, uint64_t val)
388 : _receiver(receiver), _val(val) {}
389
390 operator uint64_t() {
391 return _val;
392 }
393
394 ~DeferSet() {
395 _receiver = _val;
396 }
397 };
398
399 public:
401 // ?. ToddCoxeterImpl - nested classes - public
403
404 class Definitions {
405 using Definition = std::pair<node_type, label_type>;
406
407 private:
408 bool _any_skipped;
409 std::vector<Definition> _definitions;
410 ToddCoxeterImpl const* _tc;
411
412 public:
413 Definitions() : _any_skipped(false), _definitions(), _tc(nullptr) {}
414 // TODO(1) init()
415
416 Definitions(Definitions const&) = default;
417 Definitions(Definitions&&) = default;
418 Definitions& operator=(Definitions const& that) = default;
419 Definitions& operator=(Definitions&&) = default;
420
421 // TODO(1) corresponding constructor
422 void init(ToddCoxeterImpl const* tc) {
423 _any_skipped = false;
424 _definitions.clear();
425 _tc = tc;
426 }
427
428 void emplace_back(node_type c, label_type x);
429
430 [[nodiscard]] bool any_skipped() const noexcept {
431 return _any_skipped;
432 }
433
434 [[nodiscard]] bool empty() const noexcept {
435 return _definitions.empty();
436 }
437
438 void pop(Definition& d) {
439 d = std::move(_definitions.back());
440 _definitions.pop_back();
441 }
442
443 void clear() {
444 _definitions.clear();
445 }
446
447 private:
448 bool is_active_node(node_type n) const noexcept {
449 return _tc->current_word_graph().is_active_node(n);
450 }
451 }; // class Definitions
452
453 class Graph
454 : public FelschGraph<NodeManagedGraph<node_type>, Definitions> {
455 using FelschGraph_
456 = FelschGraph<NodeManagedGraph<node_type>, Definitions>;
457
458 public:
459 Graph() = default;
460 Graph(Graph const&) = default;
461 Graph(Graph&&) = default;
462 Graph& operator=(Graph const&) = default;
463 Graph& operator=(Graph&&) = default;
464
465 Graph& operator=(WordGraph<node_type> const& wg) {
466 FelschGraph_::operator=(wg);
467 return *this;
468 }
469
470 using FelschGraph_::presentation;
471 using FelschGraph_::target_no_checks;
472
473 Graph& init();
474 Graph& init(Presentation<word_type>&& p);
475
476 Graph& init(Presentation<word_type> const& p,
477 WordGraph<node_type> const& wg) {
478 FelschGraph_::operator=(wg);
479 FelschGraph_::presentation_no_checks(p);
480 return *this;
481 }
482
483 Graph& presentation_no_checks(Presentation<word_type> const& p);
484
485 void process_definitions();
486
487 template <bool RegDefs>
488 void push_definition_hlt(node_type const& c,
489 word_type const& u,
490 word_type const& v);
491
492 template <typename Iterator>
493 void make_compatible(ToddCoxeterImpl* tc,
494 node_type& current,
495 Iterator first,
496 Iterator last,
497 bool stop_early);
498
499 private:
500 void report_lookahead_stop_early(ToddCoxeterImpl* tc,
501 size_t expected,
502 size_t killed_last_interval);
503 }; // class Graph
504
505 private:
507 // 2. ToddCoxeterImpl - data members - private
509
510 bool _finished;
511 Forest _forest;
512 std::vector<std::unique_ptr<Settings>> _settings_stack;
513 Order _standardized;
514 // _state must be atomic to avoid the situation where the ticker
515 // function is called concurrently with a new lookahead starting
516 std::atomic<state> _state;
517 Stats _stats;
518 bool _ticker_running;
519 Graph _word_graph;
520
521 public:
522 using word_graph_type = Graph;
523
525 // 3. ToddCoxeterImpl - constructors + initializers - public
527
528 ToddCoxeterImpl();
529 ToddCoxeterImpl& init();
530
531 ToddCoxeterImpl(ToddCoxeterImpl const& that);
532 ToddCoxeterImpl(ToddCoxeterImpl&&);
533 ToddCoxeterImpl& operator=(ToddCoxeterImpl const&);
534 ToddCoxeterImpl& operator=(ToddCoxeterImpl&&);
535
536 ~ToddCoxeterImpl();
537
538 ToddCoxeterImpl(congruence_kind knd, Presentation<word_type>&& p);
539 ToddCoxeterImpl& init(congruence_kind knd, Presentation<word_type>&& p);
540 ToddCoxeterImpl(congruence_kind knd, Presentation<word_type> const& p);
541 ToddCoxeterImpl& init(congruence_kind knd,
542 Presentation<word_type> const& p);
543
544 // TODO(1) a "to" function variant that throws if wg is not valid see
545 // below
546 template <typename Node>
547 ToddCoxeterImpl(congruence_kind knd, WordGraph<Node> const& wg)
548 : ToddCoxeterImpl() {
549 LIBSEMIGROUPS_ASSERT(!_settings_stack.empty());
550 init(knd, wg);
551 }
552
553 template <typename Node>
554 ToddCoxeterImpl& init(congruence_kind knd, WordGraph<Node> const& wg);
555
556 // TODO(1) rvalue ref WordGraph init + constructor
557
558 ToddCoxeterImpl(congruence_kind knd, ToddCoxeterImpl const& tc);
559
560 ToddCoxeterImpl& init(congruence_kind knd, ToddCoxeterImpl const& tc);
561
562 ToddCoxeterImpl& presentation_no_checks(Presentation<word_type> const& p);
563
564 // This is a constructor and not a helper so that everything that takes
565 // a presentation has the same constructors, regardless of what they use
566 // inside.
567
568#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
569 // Used in Sims
570 // TODO(1) could this and the next function be removed, and replaced
571 // with something else?
572 template <typename Node>
573 ToddCoxeterImpl(congruence_kind knd,
575 WordGraph<Node> const& wg) {
576 init(knd, p, wg);
577 }
578
579 // TODO(1) a to_todd_coxeter variant that throws if p is not valid
580 template <typename Node>
581 ToddCoxeterImpl& init(congruence_kind knd,
583 WordGraph<Node> const& wg);
584#endif
585
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);
590 }
591
593 // 4. ToddCoxeterImpl - interface requirements - add_generating_pair
595
596 template <typename Iterator1,
597 typename Iterator2,
598 typename Iterator3,
599 typename Iterator4>
600 ToddCoxeterImpl& add_generating_pair_no_checks(Iterator1 first1,
601 Iterator2 last1,
602 Iterator3 first2,
603 Iterator4 last2) {
604 return CongruenceCommon::add_internal_generating_pair_no_checks<
605 ToddCoxeterImpl>(first1, last1, first2, last2);
606 }
607
608 template <typename Iterator1,
609 typename Iterator2,
610 typename Iterator3,
611 typename Iterator4>
612 ToddCoxeterImpl& add_generating_pair(Iterator1 first1,
613 Iterator2 last1,
614 Iterator3 first2,
615 Iterator4 last2) {
616 return CongruenceCommon::add_generating_pair<ToddCoxeterImpl>(
617 first1, last1, first2, last2);
618 }
619
621 // 5. ToddCoxeterImpl - interface requirements - number_of_classes
623
637 [[nodiscard]] uint64_t number_of_classes();
638
640 // 6. ToddCoxeterImpl - interface requirements - contains
642
643 template <typename Iterator1,
644 typename Iterator2,
645 typename Iterator3,
646 typename Iterator4>
647 tril currently_contains_no_checks(Iterator1 first1,
648 Iterator2 last1,
649 Iterator3 first2,
650 Iterator4 last2) const;
651
652 template <typename Iterator1,
653 typename Iterator2,
654 typename Iterator3,
655 typename Iterator4>
656 tril currently_contains(Iterator1 first1,
657 Iterator2 last1,
658 Iterator3 first2,
659 Iterator4 last2) const {
660 return CongruenceCommon::currently_contains<ToddCoxeterImpl>(
661 first1, last1, first2, last2);
662 }
663
664 template <typename Iterator1,
665 typename Iterator2,
666 typename Iterator3,
667 typename Iterator4>
668 bool contains_no_checks(Iterator1 first1,
669 Iterator2 last1,
670 Iterator3 first2,
671 Iterator4 last2);
672
673 template <typename Iterator1,
674 typename Iterator2,
675 typename Iterator3,
676 typename Iterator4>
677 bool contains(Iterator1 first1,
678 Iterator2 last1,
679 Iterator3 first2,
680 Iterator4 last2);
681
683 // 7. ToddCoxeterImpl - interface requirements - reduce
685
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;
692
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);
701 }
702
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);
711 }
712
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);
720 }
721
723 // 8. ToddCoxeterImpl - settings - public
725
726#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
727 // This is documented in Reporter, so we don't duplicate the doc here.
728 template <typename Time>
729 [[deprecated]] void report_every(Time val) {
730#pragma GCC diagnostic push
731#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
733#pragma GCC diagnostic pop
734 }
735
736 [[deprecated]] [[nodiscard]] nanoseconds report_every() const noexcept {
737#pragma GCC diagnostic push
738#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
739 return Reporter::report_every();
740#pragma GCC diagnostic pop
741 }
742#endif
743
760 ToddCoxeterImpl& def_max(size_t val) noexcept;
761
771 [[nodiscard]] size_t def_max() const noexcept;
772
788 ToddCoxeterImpl& def_policy(options::def_policy val);
789
802 [[nodiscard]] options::def_policy def_policy() const noexcept;
803
827 ToddCoxeterImpl& f_defs(size_t val);
828
852 [[nodiscard]] size_t f_defs() const noexcept;
853
877 ToddCoxeterImpl& hlt_defs(size_t val);
878
902 [[nodiscard]] size_t hlt_defs() const noexcept;
903
937 ToddCoxeterImpl& large_collapse(size_t val) noexcept;
938
953 [[nodiscard]] size_t large_collapse() const noexcept;
954
972 ToddCoxeterImpl& lookahead_extent(options::lookahead_extent val) noexcept;
973
987 [[nodiscard]] options::lookahead_extent lookahead_extent() const noexcept;
988
1008 ToddCoxeterImpl& lookahead_growth_factor(float val);
1009
1021 [[nodiscard]] float lookahead_growth_factor() const noexcept;
1022
1042 ToddCoxeterImpl& lookahead_growth_threshold(size_t val) noexcept;
1043
1055 [[nodiscard]] size_t lookahead_growth_threshold() const noexcept;
1056
1077 ToddCoxeterImpl& lookahead_min(size_t val) noexcept;
1078
1092 [[nodiscard]] size_t lookahead_min() const noexcept;
1093
1109 ToddCoxeterImpl& lookahead_next(size_t val) noexcept;
1110
1123 [[nodiscard]] size_t lookahead_next() const noexcept;
1124
1146 ToddCoxeterImpl&
1148
1162
1184 ToddCoxeterImpl& lookahead_stop_early_ratio(float val);
1185
1197 float lookahead_stop_early_ratio() const noexcept;
1198
1216 ToddCoxeterImpl& lookahead_style(options::lookahead_style val) noexcept;
1217
1228 [[nodiscard]] options::lookahead_style lookahead_style() const noexcept;
1229
1251 ToddCoxeterImpl& lower_bound(size_t val) noexcept;
1252
1264 [[nodiscard]] size_t lower_bound() const noexcept;
1265
1281 ToddCoxeterImpl& save(bool val) noexcept;
1282
1293 [[nodiscard]] bool save() const noexcept;
1294
1309 ToddCoxeterImpl& strategy(options::strategy val) noexcept;
1310
1321 [[nodiscard]] options::strategy strategy() const noexcept;
1322
1341 ToddCoxeterImpl& use_relations_in_extra(bool val) noexcept;
1342
1355 [[nodiscard]] bool use_relations_in_extra() const noexcept;
1356
1357#ifdef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1373 ToddCoxeterImpl& def_version(options::def_version val);
1374
1387 [[nodiscard]] options::def_version def_version() const noexcept;
1388#else
1389 using FelschGraphSettings_::def_version;
1390 using FelschGraphSettings_::settings;
1391#endif
1392
1394 // 9. ToddCoxeterImpl - accessors - public
1396
1397#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1398 [[nodiscard]] Presentation<word_type> const&
1399 internal_presentation() const noexcept {
1400 return _word_graph.presentation();
1401 }
1402#endif
1403
1423 // This isn't really necessary in C++, but in the python bindings we don't
1424 // bind ToddCoxeter::Graph and so we expose this here.
1425 [[nodiscard]] uint64_t number_of_nodes_active() const noexcept {
1426 return current_word_graph().number_of_nodes_active();
1427 }
1428
1448 // This isn't really necessary in C++, but in the python bindings we don't
1449 // bind ToddCoxeter::Graph and so we expose this here.
1450 [[nodiscard]] uint64_t number_of_edges_active() const noexcept {
1451 return current_word_graph().number_of_edges_active();
1452 }
1453
1469 [[nodiscard]] float complete() const noexcept {
1471 }
1472
1473 // [[nodiscard]] bool empty() const {
1474 // return (internal_presentation().rules.empty() &&
1475 // generating_pairs().empty()
1476 // && current_word_graph().number_of_nodes_active() == 1);
1477 // // FIXME(1) there's an issue where the word graph can have 0
1478 // nodes but
1479 // 1
1480 // // active node.
1481 // }
1482
1513 word_graph_type const& current_word_graph() const noexcept {
1514 return _word_graph;
1515 }
1516
1543 word_graph_type const& word_graph();
1544
1568 Forest const& current_spanning_tree() const noexcept {
1569 return _forest;
1570 }
1571
1583
1627 inline Order standardization_order() const noexcept {
1628 return _standardized;
1629 }
1630
1646 bool is_standardized(Order val) const;
1647
1661 bool is_standardized() const;
1662
1675 [[nodiscard]] uint64_t number_of_large_collapses() const noexcept {
1676 return _word_graph.stats().num_large_collapses;
1677 }
1678
1680 // 10. ToddCoxeterImpl - modifiers - public
1682
1692
1717
1733 void perform_lookahead(bool stop_early);
1734
1736 // 11. ToddCoxeterImpl - word -> index
1738
1754
1781 // NOTE: the graph contains one more node than there are element
1782 // if the underlying presentation does not contain the empty word
1783 template <typename Iterator1, typename Iterator2>
1784 index_type current_index_of_no_checks(Iterator1 first,
1785 Iterator2 last) const;
1786
1812 template <typename Iterator1, typename Iterator2>
1813 index_type current_index_of(Iterator1 first, Iterator2 last) const {
1814 throw_if_letter_not_in_alphabet(first, last);
1815 return current_index_of_no_checks(first, last);
1816 }
1817
1843 template <typename Iterator1, typename Iterator2>
1844 index_type index_of_no_checks(Iterator1 first, Iterator2 last);
1845
1871 template <typename Iterator1, typename Iterator2>
1872 index_type index_of(Iterator1 first, Iterator2 last) {
1873 throw_if_letter_not_in_alphabet(first, last);
1874 return index_of_no_checks(first, last);
1875 }
1876
1878
1880 // 12. ToddCoxeterImpl - index -> word
1882
1899
1927 // NOTE THAT: the graph contains one more node than there are element
1928 // if the underlying presentation does not contain the empty word
1929 template <typename OutputIterator>
1930 OutputIterator current_word_of_no_checks(OutputIterator d_first,
1931 index_type i) const;
1932
1958 template <typename OutputIterator>
1959 OutputIterator current_word_of(OutputIterator d_first,
1960 index_type i) const;
1961
1984 template <typename Iterator>
1985 Iterator word_of_no_checks(Iterator d_first, index_type i) {
1986 run();
1987 LIBSEMIGROUPS_ASSERT(finished());
1988 return current_word_of_no_checks(d_first, i);
1989 }
1990
2015 template <typename Iterator>
2016 Iterator word_of(Iterator d_first, index_type i) {
2017 run();
2018 LIBSEMIGROUPS_ASSERT(finished());
2019 return current_word_of(d_first, i);
2020 }
2021
2023
2024 private:
2026 // 13. Runner - pure virtual member functions - private
2028
2029 void really_run_impl();
2030
2031 void run_impl() override;
2032
2033 [[nodiscard]] bool finished_impl() const override {
2034 return _finished;
2035 }
2036
2038 // 14. ToddCoxeterImpl - member functions - private
2040
2041 void copy_settings_into_graph();
2042
2043 // This function has prefix tc_ because there's already a settings
2044 // function in a base class
2045 Settings& tc_settings();
2046 Settings const& tc_settings() const;
2047
2048 void reset_settings_stack();
2049
2050 [[nodiscard]] bool any_change() const {
2051 return _stats.run_nodes_active_at_start
2052 != current_word_graph().number_of_nodes_active();
2053 }
2054
2055 // We take both values here, although we could compute them, so that in
2056 // report_progress_from_thread we do not report at one point in time with
2057 // some value, then within the same function call (if the graph is
2058 // changing a lot) report with another value
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)
2063 * current_word_graph().out_degree());
2064 }
2065
2066 [[nodiscard]] float complete(int64_t num_edges) const noexcept {
2068 num_edges);
2069 }
2070
2071 [[nodiscard]] bool lookahead_stop_early(
2072 bool stop_early,
2073 std::chrono::high_resolution_clock::time_point& last_stop_early_check,
2074 uint64_t& killed_at_prev_interval);
2075
2077 // ToddCoxeterImpl - main strategies - private
2079
2080 void init_run();
2081 void finalise_run();
2082
2083 void felsch();
2084 void hlt();
2085 void CR_style();
2086 void R_over_C_style();
2087 void Cr_style();
2088 void Rc_style();
2089
2091 // ToddCoxeterImpl - reporting - private
2093
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;
2105
2106 void add_timing_row(ReportCell<5>& rc) const;
2107
2108 // The 2nd (and 3rd) arguments for the next 2 functions are required
2109 // because we need the values at a fixed point in time (due to
2110 // multi-threaded reporting).
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;
2116
2118 // ToddCoxeterImpl - lookahead - private
2120
2121 static constexpr bool StopEarly = true;
2122 static constexpr bool DoNotStopEarly = false;
2123
2124 void hlt_lookahead(bool stop_early);
2125 void felsch_lookahead(bool stop_early);
2126 }; // class ToddCoxeterImpl
2127
2128 } // namespace detail
2129
2130} // namespace libsemigroups
2131
2132#include "todd-coxeter-impl.tpp"
2133#endif // LIBSEMIGROUPS_DETAIL_TODD_COXETER_IMPL_HPP_
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
T move(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44