libsemigroups  v3.2.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/to-presentation.hpp" // for to_prese...
48#include "libsemigroups/types.hpp" // for word_type
49#include "libsemigroups/word-graph.hpp" // for WordGraph
50
51#include "cong-common-class.hpp" // for Congruen...
52#include "felsch-graph.hpp" // for FelschGraph
53#include "node-managed-graph.hpp" // for NodeMana...
54#include "node-manager.hpp" // for NodeMana...
55#include "word-graph-with-sources.hpp" // for WordGrap...
56
58// This file is organised as follows:
59// 0. ToddCoxeterImpl - member types - public
60// 1. ToddCoxeterImpl - nested classes - private
61// 2. ToddCoxeterImpl - data members - private
62// 3. ToddCoxeterImpl - constructors + initializers - public
63// 4. ToddCoxeterImpl - interface requirements - add_generating_pair
64// 5. ToddCoxeterImpl - interface requirements - number_of_classes
65// 6. ToddCoxeterImpl - interface requirements - contains
66// 7. ToddCoxeterImpl - interface requirements - reduce
67// 8. ToddCoxeterImpl - settings - public
68// 9. ToddCoxeterImpl - accessors - public
69// 10. ToddCoxeterImpl - modifiers - public
70// 11. ToddCoxeterImpl - word -> index
71// 12. ToddCoxeterImpl - index -> word
72// 13. Runner - pure virtual member functions - private
73// 14. ToddCoxeterImpl - member functions - private
75
76namespace libsemigroups {
77
78 // NOTE: groups are defined here because the order they are declared is the
79 // order they appear in the output doc.
80
88
103
119
129
143
155
156 namespace detail {
157 class ToddCoxeterImpl : public CongruenceCommon,
158 public FelschGraphSettings<ToddCoxeterImpl> {
159 using FelschGraphSettings_ = FelschGraphSettings<ToddCoxeterImpl>;
160
161 public:
163 // 0. ToddCoxeterImpl - member types - public
165
166 struct options : public FelschGraphSettings_::options {
167 enum class strategy { hlt, felsch, CR, R_over_C, Cr, Rc };
168
169 enum class lookahead_extent { full, partial };
170
171 enum class lookahead_style { hlt, felsch };
172
173 enum class def_policy : uint8_t {
174 no_stack_if_no_space,
175 purge_from_top,
176 purge_all,
177 discard_all_if_no_space,
178 unlimited
179 };
180 }; // struct options
181
182 enum class state : uint8_t { none, hlt, felsch, lookahead };
183
184 using node_type = typename WordGraph<uint32_t>::node_type;
185 using index_type = node_type;
186 using label_type = typename WordGraph<uint32_t>::label_type;
187 using native_word_type = word_type;
188
189 private:
191 // 1. ToddCoxeterImpl - nested classes - private
193
194 struct Settings;
195
196 class SettingsGuard;
197 friend class SettingsGuard;
198
199 struct NonAtomicStats {
200 using time_point = std::chrono::high_resolution_clock::time_point;
201
202 // Data
203 time_point create_or_init_time;
204 std::chrono::nanoseconds all_runs_time;
205
206 std::chrono::nanoseconds all_hlt_phases_time;
207 std::chrono::nanoseconds all_felsch_phases_time;
208 std::chrono::nanoseconds all_lookahead_phases_time;
209
210 uint64_t all_num_hlt_phases;
211 uint64_t all_num_felsch_phases;
212 uint64_t all_num_lookahead_phases;
213
214 uint64_t run_index;
215 time_point run_start_time;
216
217 uint64_t run_edges_active_at_start;
218 uint64_t run_nodes_active_at_start;
219
220 std::chrono::nanoseconds run_hlt_phases_time;
221 std::chrono::nanoseconds run_felsch_phases_time;
222 std::chrono::nanoseconds run_lookahead_phases_time;
223
224 uint64_t run_num_hlt_phases;
225 uint64_t run_num_felsch_phases;
226 uint64_t run_num_lookahead_phases;
227
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;
235
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;
242
243 // Constructors + initializers
244
245 NonAtomicStats() {
246 init();
247 }
248
249 NonAtomicStats& init();
250
251 NonAtomicStats(NonAtomicStats const&) = default;
252 NonAtomicStats(NonAtomicStats&&) = default;
253 NonAtomicStats& operator=(NonAtomicStats const&) = default;
254 NonAtomicStats& operator=(NonAtomicStats&&) = default;
255 };
256
257 struct Stats : public NonAtomicStats {
258 // Data
259 std::atomic_uint64_t lookahead_nodes_killed;
260 std::atomic_uint64_t lookahead_position;
261
262 // Constructors + initialisers
263
264 Stats()
265 : NonAtomicStats(),
266 lookahead_nodes_killed(),
267 lookahead_position() {}
268
269 Stats& init() {
270 NonAtomicStats::init();
271 return *this;
272 }
273
274 Stats(Stats const& that)
275 : NonAtomicStats(that),
276 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
277 lookahead_position(that.lookahead_position.load()) {}
278
279 Stats(Stats&& that)
280 : NonAtomicStats(std::move(that)),
281 lookahead_nodes_killed(that.lookahead_nodes_killed.load()),
282 lookahead_position(that.lookahead_position.load()) {}
283
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();
288 return *this;
289 }
290
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();
295 return *this;
296 }
297 };
298
299 void stats_run_start() {
300 _stats.run_start_time = std::chrono::high_resolution_clock::now();
301
302 _stats.run_nodes_active_at_start
303 = current_word_graph().number_of_nodes_active();
304 _stats.run_edges_active_at_start
305 = current_word_graph().number_of_edges_active();
306 _stats.run_num_hlt_phases = 0;
307 _stats.run_num_felsch_phases = 0;
308 _stats.run_num_lookahead_phases = 0;
309
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);
313
314 _stats.phase_index = 0;
315 }
316
317 void stats_run_stop() {
318 _stats.run_index++;
319
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;
324
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;
328 }
329
330 void stats_phase_start() {
331 _stats.phase_start_time = std::chrono::high_resolution_clock::now();
332 _stats.report_index = 0;
333
334 _stats.phase_nodes_active_at_start
335 = current_word_graph().number_of_nodes_active();
336 _stats.phase_nodes_killed_at_start
337 = current_word_graph().number_of_nodes_killed();
338 _stats.phase_nodes_defined_at_start
339 = current_word_graph().number_of_nodes_defined();
340
341 _stats.phase_edges_active_at_start
342 = current_word_graph().number_of_edges_active();
343 _stats.phase_complete_at_start
345 }
346
347 void stats_phase_stop() {
348 _stats.phase_index++;
349
350 switch (_state) {
351 case state::none: {
352 break;
353 }
354 case state::hlt: {
355 _stats.run_num_hlt_phases++;
356 _stats.run_hlt_phases_time += delta(_stats.phase_start_time);
357 break;
358 }
359 case state::felsch: {
360 _stats.run_num_felsch_phases++;
361 _stats.run_felsch_phases_time += delta(_stats.phase_start_time);
362 break;
363 }
364 case state::lookahead: {
365 _stats.run_num_lookahead_phases++;
366 _stats.run_lookahead_phases_time += delta(_stats.phase_start_time);
367 break;
368 }
369 default: {
370 break;
371 }
372 }
373 }
374
375 void stats_report_stop() const {
376 _stats.report_index++;
377 }
378
379 // Simple struct that allows the "receivers" value to be set to "val" but
380 // only when the object goes out of scope. Useful in reporting when
381 // we want to do something with an old value, then update the data member
382 // of Stats.
383 class DeferSet {
384 uint64_t& _receiver;
385 uint64_t _val;
386
387 public:
388 DeferSet(uint64_t& receiver, uint64_t val)
389 : _receiver(receiver), _val(val) {}
390
391 operator uint64_t() {
392 return _val;
393 }
394
395 ~DeferSet() {
396 _receiver = _val;
397 }
398 };
399
400 public:
402 // ?. ToddCoxeterImpl - nested classes - public
404
405 class Definitions {
406 using Definition = std::pair<node_type, label_type>;
407
408 private:
409 bool _any_skipped;
410 std::vector<Definition> _definitions;
411 ToddCoxeterImpl const* _tc;
412
413 public:
414 Definitions() : _any_skipped(false), _definitions(), _tc(nullptr) {}
415 // TODO(1) init()
416
417 Definitions(Definitions const&) = default;
418 Definitions(Definitions&&) = default;
419 Definitions& operator=(Definitions const& that) = default;
420 Definitions& operator=(Definitions&&) = default;
421
422 // TODO(1) corresponding constructor
423 void init(ToddCoxeterImpl const* tc) {
424 _any_skipped = false;
425 _definitions.clear();
426 _tc = tc;
427 }
428
429 void emplace_back(node_type c, label_type x);
430
431 [[nodiscard]] bool any_skipped() const noexcept {
432 return _any_skipped;
433 }
434
435 [[nodiscard]] bool empty() const noexcept {
436 return _definitions.empty();
437 }
438
439 void pop(Definition& d) {
440 d = std::move(_definitions.back());
441 _definitions.pop_back();
442 }
443
444 void clear() {
445 _definitions.clear();
446 }
447
448 private:
449 bool is_active_node(node_type n) const noexcept {
450 return _tc->current_word_graph().is_active_node(n);
451 }
452 }; // class Definitions
453
454 class Graph
455 : public FelschGraph<NodeManagedGraph<node_type>, Definitions> {
456 using FelschGraph_
457 = FelschGraph<NodeManagedGraph<node_type>, Definitions>;
458
459 public:
460 Graph() = default;
461 Graph(Graph const&) = default;
462 Graph(Graph&&) = default;
463 Graph& operator=(Graph const&) = default;
464 Graph& operator=(Graph&&) = default;
465
466 Graph& operator=(WordGraph<node_type> const& wg) {
467 FelschGraph_::operator=(wg);
468 return *this;
469 }
470
471 using FelschGraph_::presentation;
472 using FelschGraph_::target_no_checks;
473
474 Graph& init();
475 Graph& init(Presentation<word_type>&& p);
476
477 Graph& init(Presentation<word_type> const& p,
478 WordGraph<node_type> const& wg) {
479 FelschGraph_::operator=(wg);
480 FelschGraph_::presentation_no_checks(p);
481 return *this;
482 }
483
484 Graph& presentation_no_checks(Presentation<word_type> const& p);
485
486 void process_definitions();
487
488 template <bool RegDefs>
489 void push_definition_hlt(node_type const& c,
490 word_type const& u,
491 word_type const& v);
492
493 template <typename Iterator>
494 void make_compatible(ToddCoxeterImpl* tc,
495 node_type& current,
496 Iterator first,
497 Iterator last,
498 bool stop_early);
499
500 private:
501 void report_lookahead_stop_early(ToddCoxeterImpl* tc,
502 size_t expected,
503 size_t killed_last_interval);
504 }; // class Graph
505
506 private:
508 // 2. ToddCoxeterImpl - data members - private
510
511 bool _finished;
512 Forest _forest;
513 std::vector<std::unique_ptr<Settings>> _settings_stack;
514 Order _standardized;
515 // _state must be atomic to avoid the situation where the ticker
516 // function is called concurrently with a new lookahead starting
517 std::atomic<state> _state;
518 Stats _stats;
519 bool _ticker_running;
520 Graph _word_graph;
521
522 public:
523 using word_graph_type = Graph;
524
526 // 3. ToddCoxeterImpl - constructors + initializers - public
528
529 ToddCoxeterImpl();
530 ToddCoxeterImpl& init();
531
532 ToddCoxeterImpl(ToddCoxeterImpl const& that);
533 ToddCoxeterImpl(ToddCoxeterImpl&&);
534 ToddCoxeterImpl& operator=(ToddCoxeterImpl const&);
535 ToddCoxeterImpl& operator=(ToddCoxeterImpl&&);
536
537 ~ToddCoxeterImpl();
538
539 ToddCoxeterImpl(congruence_kind knd, Presentation<word_type>&& p);
540 ToddCoxeterImpl& init(congruence_kind knd, Presentation<word_type>&& p);
541 ToddCoxeterImpl(congruence_kind knd, Presentation<word_type> const& p);
542 ToddCoxeterImpl& init(congruence_kind knd,
543 Presentation<word_type> const& p);
544
545 // TODO(1) a "to" function variant that throws if wg is not valid see
546 // below
547 template <typename Node>
548 ToddCoxeterImpl(congruence_kind knd, WordGraph<Node> const& wg)
549 : ToddCoxeterImpl() {
550 LIBSEMIGROUPS_ASSERT(!_settings_stack.empty());
551 init(knd, wg);
552 }
553
554 template <typename Node>
555 ToddCoxeterImpl& init(congruence_kind knd, WordGraph<Node> const& wg);
556
557 // TODO(1) rvalue ref WordGraph init + constructor
558
559 ToddCoxeterImpl(congruence_kind knd, ToddCoxeterImpl const& tc);
560
561 ToddCoxeterImpl& init(congruence_kind knd, ToddCoxeterImpl const& tc);
562
563 ToddCoxeterImpl& presentation_no_checks(Presentation<word_type> const& p);
564
565 // This is a constructor and not a helper so that everything that takes
566 // a presentation has the same constructors, regardless of what they use
567 // inside.
568
569#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
570 // Used in Sims
571 // TODO(1) could this and the next function be removed, and replaced
572 // with something else?
573 template <typename Node>
574 ToddCoxeterImpl(congruence_kind knd,
576 WordGraph<Node> const& wg) {
577 init(knd, p, wg);
578 }
579
580 // TODO(1) a to_todd_coxeter variant that throws if p is not valid
581 template <typename Node>
582 ToddCoxeterImpl& init(congruence_kind knd,
584 WordGraph<Node> const& wg);
585#endif
586
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);
591 }
592
594 // 4. ToddCoxeterImpl - interface requirements - add_generating_pair
596
597 template <typename Iterator1,
598 typename Iterator2,
599 typename Iterator3,
600 typename Iterator4>
601 ToddCoxeterImpl& add_generating_pair_no_checks(Iterator1 first1,
602 Iterator2 last1,
603 Iterator3 first2,
604 Iterator4 last2) {
605 return CongruenceCommon::add_internal_generating_pair_no_checks<
606 ToddCoxeterImpl>(first1, last1, first2, last2);
607 }
608
609 template <typename Iterator1,
610 typename Iterator2,
611 typename Iterator3,
612 typename Iterator4>
613 ToddCoxeterImpl& add_generating_pair(Iterator1 first1,
614 Iterator2 last1,
615 Iterator3 first2,
616 Iterator4 last2) {
617 return CongruenceCommon::add_generating_pair<ToddCoxeterImpl>(
618 first1, last1, first2, last2);
619 }
620
622 // 5. ToddCoxeterImpl - interface requirements - number_of_classes
624
638 [[nodiscard]] uint64_t number_of_classes();
639
641 // 6. ToddCoxeterImpl - interface requirements - contains
643
644 template <typename Iterator1,
645 typename Iterator2,
646 typename Iterator3,
647 typename Iterator4>
648 tril currently_contains_no_checks(Iterator1 first1,
649 Iterator2 last1,
650 Iterator3 first2,
651 Iterator4 last2) const;
652
653 template <typename Iterator1,
654 typename Iterator2,
655 typename Iterator3,
656 typename Iterator4>
657 tril currently_contains(Iterator1 first1,
658 Iterator2 last1,
659 Iterator3 first2,
660 Iterator4 last2) const {
661 return CongruenceCommon::currently_contains<ToddCoxeterImpl>(
662 first1, last1, first2, last2);
663 }
664
665 template <typename Iterator1,
666 typename Iterator2,
667 typename Iterator3,
668 typename Iterator4>
669 bool contains_no_checks(Iterator1 first1,
670 Iterator2 last1,
671 Iterator3 first2,
672 Iterator4 last2);
673
674 template <typename Iterator1,
675 typename Iterator2,
676 typename Iterator3,
677 typename Iterator4>
678 bool contains(Iterator1 first1,
679 Iterator2 last1,
680 Iterator3 first2,
681 Iterator4 last2);
682
684 // 7. ToddCoxeterImpl - interface requirements - reduce
686
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;
693
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);
702 }
703
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);
712 }
713
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);
721 }
722
724 // 8. ToddCoxeterImpl - settings - public
726
727#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
728 // This is documented in Reporter, so we don't duplicate the doc here.
729 template <typename Time>
730 void report_every(Time val) {
732 }
733
734 [[nodiscard]] nanoseconds report_every() const noexcept {
735 return Reporter::report_every();
736 }
737#endif
738
755 ToddCoxeterImpl& def_max(size_t val) noexcept;
756
766 [[nodiscard]] size_t def_max() const noexcept;
767
783 ToddCoxeterImpl& def_policy(options::def_policy val);
784
797 [[nodiscard]] options::def_policy def_policy() const noexcept;
798
822 ToddCoxeterImpl& f_defs(size_t val);
823
847 [[nodiscard]] size_t f_defs() const noexcept;
848
872 ToddCoxeterImpl& hlt_defs(size_t val);
873
897 [[nodiscard]] size_t hlt_defs() const noexcept;
898
932 ToddCoxeterImpl& large_collapse(size_t val) noexcept;
933
948 [[nodiscard]] size_t large_collapse() const noexcept;
949
967 ToddCoxeterImpl& lookahead_extent(options::lookahead_extent val) noexcept;
968
982 [[nodiscard]] options::lookahead_extent lookahead_extent() const noexcept;
983
1003 ToddCoxeterImpl& lookahead_growth_factor(float val);
1004
1016 [[nodiscard]] float lookahead_growth_factor() const noexcept;
1017
1037 ToddCoxeterImpl& lookahead_growth_threshold(size_t val) noexcept;
1038
1050 [[nodiscard]] size_t lookahead_growth_threshold() const noexcept;
1051
1072 ToddCoxeterImpl& lookahead_min(size_t val) noexcept;
1073
1087 [[nodiscard]] size_t lookahead_min() const noexcept;
1088
1104 ToddCoxeterImpl& lookahead_next(size_t val) noexcept;
1105
1118 [[nodiscard]] size_t lookahead_next() const noexcept;
1119
1141 ToddCoxeterImpl&
1143
1157
1179 ToddCoxeterImpl& lookahead_stop_early_ratio(float val);
1180
1192 float lookahead_stop_early_ratio() const noexcept;
1193
1211 ToddCoxeterImpl& lookahead_style(options::lookahead_style val) noexcept;
1212
1223 [[nodiscard]] options::lookahead_style lookahead_style() const noexcept;
1224
1246 ToddCoxeterImpl& lower_bound(size_t val) noexcept;
1247
1259 [[nodiscard]] size_t lower_bound() const noexcept;
1260
1276 ToddCoxeterImpl& save(bool val) noexcept;
1277
1288 [[nodiscard]] bool save() const noexcept;
1289
1304 ToddCoxeterImpl& strategy(options::strategy val) noexcept;
1305
1316 [[nodiscard]] options::strategy strategy() const noexcept;
1317
1336 ToddCoxeterImpl& use_relations_in_extra(bool val) noexcept;
1337
1350 [[nodiscard]] bool use_relations_in_extra() const noexcept;
1351
1352#ifdef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1368 ToddCoxeterImpl& def_version(options::def_version val);
1369
1382 [[nodiscard]] options::def_version def_version() const noexcept;
1383#else
1384 using FelschGraphSettings_::def_version;
1385 using FelschGraphSettings_::settings;
1386#endif
1387
1389 // 9. ToddCoxeterImpl - accessors - public
1391
1392#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
1393 [[nodiscard]] Presentation<word_type> const&
1394 internal_presentation() const noexcept {
1395 return _word_graph.presentation();
1396 }
1397#endif
1398
1418 // This isn't really necessary in C++, but in the python bindings we don't
1419 // bind ToddCoxeter::Graph and so we expose this here.
1420 [[nodiscard]] uint64_t number_of_nodes_active() const noexcept {
1421 return current_word_graph().number_of_nodes_active();
1422 }
1423
1443 // This isn't really necessary in C++, but in the python bindings we don't
1444 // bind ToddCoxeter::Graph and so we expose this here.
1445 [[nodiscard]] uint64_t number_of_edges_active() const noexcept {
1446 return current_word_graph().number_of_edges_active();
1447 }
1448
1464 [[nodiscard]] float complete() const noexcept {
1466 }
1467
1468 // [[nodiscard]] bool empty() const {
1469 // return (internal_presentation().rules.empty() &&
1470 // generating_pairs().empty()
1471 // && current_word_graph().number_of_nodes_active() == 1);
1472 // // FIXME(1) there's an issue where the word graph can have 0
1473 // nodes but
1474 // 1
1475 // // active node.
1476 // }
1477
1508 word_graph_type const& current_word_graph() const noexcept {
1509 return _word_graph;
1510 }
1511
1538 word_graph_type const& word_graph();
1539
1563 Forest const& current_spanning_tree() const noexcept {
1564 return _forest;
1565 }
1566
1578
1622 inline Order standardization_order() const noexcept {
1623 return _standardized;
1624 }
1625
1641 bool is_standardized(Order val) const;
1642
1656 bool is_standardized() const;
1657
1670 [[nodiscard]] uint64_t number_of_large_collapses() const noexcept {
1671 return _word_graph.stats().num_large_collapses;
1672 }
1673
1675 // 10. ToddCoxeterImpl - modifiers - public
1677
1687
1712
1728 void perform_lookahead(bool stop_early);
1729
1731 // 11. ToddCoxeterImpl - word -> index
1733
1749
1776 // NOTE: the graph contains one more node than there are element
1777 // if the underlying presentation does not contain the empty word
1778 template <typename Iterator1, typename Iterator2>
1779 index_type current_index_of_no_checks(Iterator1 first,
1780 Iterator2 last) const;
1781
1807 template <typename Iterator1, typename Iterator2>
1808 index_type current_index_of(Iterator1 first, Iterator2 last) const {
1809 throw_if_letter_not_in_alphabet(first, last);
1810 return current_index_of_no_checks(first, last);
1811 }
1812
1838 template <typename Iterator1, typename Iterator2>
1839 index_type index_of_no_checks(Iterator1 first, Iterator2 last);
1840
1866 template <typename Iterator1, typename Iterator2>
1867 index_type index_of(Iterator1 first, Iterator2 last) {
1868 throw_if_letter_not_in_alphabet(first, last);
1869 return index_of_no_checks(first, last);
1870 }
1871
1873
1875 // 12. ToddCoxeterImpl - index -> word
1877
1894
1922 // NOTE THAT: the graph contains one more node than there are element
1923 // if the underlying presentation does not contain the empty word
1924 template <typename OutputIterator>
1925 OutputIterator current_word_of_no_checks(OutputIterator d_first,
1926 index_type i) const;
1927
1953 template <typename OutputIterator>
1954 OutputIterator current_word_of(OutputIterator d_first,
1955 index_type i) const;
1956
1980 template <typename Iterator>
1981 Iterator word_of_no_checks(Iterator d_first, index_type i) {
1982 run();
1983 LIBSEMIGROUPS_ASSERT(finished());
1984 return current_word_of_no_checks(d_first, i);
1985 }
1986
2011 template <typename Iterator>
2012 Iterator word_of(Iterator d_first, index_type i) {
2013 run();
2014 LIBSEMIGROUPS_ASSERT(finished());
2015 return current_word_of(d_first, i);
2016 }
2017
2019
2020 private:
2022 // 13. Runner - pure virtual member functions - private
2024
2025 void really_run_impl();
2026
2027 void run_impl() override;
2028
2029 [[nodiscard]] bool finished_impl() const override {
2030 return _finished;
2031 }
2032
2034 // 14. ToddCoxeterImpl - member functions - private
2036
2037 void copy_settings_into_graph();
2038
2039 // This function has prefix tc_ because there's already a settings
2040 // function in a base class
2041 Settings& tc_settings();
2042 Settings const& tc_settings() const;
2043
2044 void reset_settings_stack();
2045
2046 [[nodiscard]] bool any_change() const {
2047 return _stats.run_nodes_active_at_start
2048 != current_word_graph().number_of_nodes_active();
2049 }
2050
2051 // We take both values here, although we could compute them, so that in
2052 // report_progress_from_thread we do not report at one point in time with
2053 // some value, then within the same function call (if the graph is
2054 // changing a lot) report with another value
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)
2059 * current_word_graph().out_degree());
2060 }
2061
2062 [[nodiscard]] float complete(int64_t num_edges) const noexcept {
2064 num_edges);
2065 }
2066
2067 [[nodiscard]] bool lookahead_stop_early(
2068 bool stop_early,
2069 std::chrono::high_resolution_clock::time_point& last_stop_early_check,
2070 uint64_t& killed_at_prev_interval);
2071
2073 // ToddCoxeterImpl - main strategies - private
2075
2076 void init_run();
2077 void finalise_run();
2078
2079 void felsch();
2080 void hlt();
2081 void CR_style();
2082 void R_over_C_style();
2083 void Cr_style();
2084 void Rc_style();
2085
2087 // ToddCoxeterImpl - reporting - private
2089
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;
2101
2102 void add_timing_row(ReportCell<5>& rc) const;
2103
2104 // The 2nd (and 3rd) arguments for the next 2 functions are required
2105 // because we need the values at a fixed point in time (due to
2106 // multi-threaded reporting).
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;
2112
2114 // ToddCoxeterImpl - lookahead - private
2116
2117 static constexpr bool StopEarly = true;
2118 static constexpr bool DoNotStopEarly = false;
2119
2120 void hlt_lookahead(bool stop_early);
2121 void felsch_lookahead(bool stop_early);
2122 }; // class ToddCoxeterImpl
2123
2124 } // namespace detail
2125
2126} // namespace libsemigroups
2127
2128#include "todd-coxeter-impl.tpp"
2129#endif // LIBSEMIGROUPS_DETAIL_TODD_COXETER_IMPL_HPP_
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
T move(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44