libsemigroups  v3.6.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
presentation.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2022-2026 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 the declaration of a class template for semigroup or
20// monoid presentations. The idea is to provide a shallow wrapper around a
21// vector of words, with some checks that the vector really defines a
22// presentation, (i.e. it's consistent with its alphabet etc), and some related
23// functionality.
24
25#ifndef LIBSEMIGROUPS_PRESENTATION_HPP_
26#define LIBSEMIGROUPS_PRESENTATION_HPP_
27
28#include <algorithm> // for reverse, sort
29#include <cmath> // for pow
30#include <cstring> // for size_t, strlen
31#include <initializer_list> // for initializer_list
32#include <iterator> // for distance
33#include <limits> // for numeric_limits
34#include <map> // for map
35#include <numeric> // for accumulate
36#include <string> // for basic_string, operator==
37#include <tuple> // for tie, tuple
38#include <type_traits> // for enable_if_t
39#include <unordered_map> // for operator==, operator!=
40#include <unordered_set> // for unordered_set
41#include <utility> // for move, pair
42#include <vector> // for vector, operator!=
43
44#include "adapters.hpp" // for Hash, EqualTo
45#include "constants.hpp" // for Max, UNDEFINED, operator==
46#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
47#include "is_specialization_of.hpp" // for is_specialization_of
48#include "order.hpp" // for ShortLexCompare
49#include "ranges.hpp" // for seq, operator|, rx, take, chain, is_sorted
50#include "types.hpp" // for word_type
51#include "ukkonen.hpp" // for GreedyReduceHelper, Ukkonen
52#include "word-range.hpp" // for operator+
53
54#include "detail/fmt.hpp" // for format
55#include "detail/print.hpp" // for isprint etc
56#include "detail/string.hpp" // for maximum_common_prefix
57#include "detail/uf.hpp" // for Duf
58
59namespace libsemigroups {
60
76
79
102 template <typename Word>
104 public:
106 using word_type = Word;
107
110 using letter_type = typename word_type::value_type;
111
114
117
120
121 private:
122 word_type _alphabet;
124 bool _contains_empty_word;
125
126 public:
133
138
150
155
160
165
170
172
184 [[nodiscard]] word_type const& alphabet() const noexcept {
185 return _alphabet;
186 }
187
188 // TODO(later) alphabet_no_checks
189
210 // TODO(1) Rename alphabet_size
212
232
252
259 template <typename Return = Presentation&>
260 auto alphabet(std::string_view lphbt)
261 -> std::enable_if_t<std::is_same_v<std::string, word_type>, Return&> {
262 return alphabet(std::string(lphbt));
263 }
264
271 template <typename Return = Presentation&>
272 auto alphabet(char const* lphbt)
273 -> std::enable_if_t<std::is_same_v<std::string, word_type>, Return> {
274 return alphabet(std::string(lphbt));
275 }
276
281 // There's some weirdness with {0} being interpreted as a string_view, which
282 // means that the next overload is required
287
305
319 [[nodiscard]] letter_type letter_no_checks(size_type i) const {
320 LIBSEMIGROUPS_ASSERT(i < _alphabet.size());
321 return _alphabet[i];
322 }
323
334 [[nodiscard]] letter_type letter(size_type i) const;
335
352 [[nodiscard]] size_type index_no_checks(letter_type val) const {
353 return _alphabet_map.find(val)->second;
354 }
355
366 [[nodiscard]] size_type index(letter_type val) const;
367
381 [[nodiscard]] bool in_alphabet(letter_type val) const {
382 return _alphabet_map.find(val) != _alphabet_map.cend();
383 }
384
420 template <typename Iterator1, typename Iterator2>
421 Presentation& add_rule_no_checks(Iterator1 lhs_begin,
422 Iterator1 lhs_end,
423 Iterator2 rhs_begin,
424 Iterator2 rhs_end) {
425 rules.emplace_back(lhs_begin, lhs_end);
426 rules.emplace_back(rhs_begin, rhs_end);
427 return *this;
428 }
429
444 template <typename Iterator1, typename Iterator2>
445 Presentation& add_rule(Iterator1 lhs_begin,
446 Iterator1 lhs_end,
447 Iterator2 rhs_begin,
448 Iterator2 rhs_end) {
449 throw_if_letter_not_in_alphabet(lhs_begin, lhs_end);
450 throw_if_letter_not_in_alphabet(rhs_begin, rhs_end);
451 return add_rule_no_checks(lhs_begin, lhs_end, rhs_begin, rhs_end);
452 }
453
464
476
487
507
522
539 [[nodiscard]] bool contains_empty_word() const noexcept {
540 return _contains_empty_word;
541 }
542
562 Presentation& contains_empty_word(bool val) noexcept {
563 _contains_empty_word = val;
564 return *this;
565 }
566
577 decltype(_alphabet_map) alphabet_map;
579 }
580
592
607 template <typename Iterator1, typename Iterator2>
608 void throw_if_letter_not_in_alphabet(Iterator1 first, Iterator2 last) const;
609
626 void throw_if_bad_rules() const;
627
643
644 private:
645 void try_set_alphabet(decltype(_alphabet_map)& alphabet_map,
646 word_type& old_alphabet);
648 decltype(_alphabet_map)& alphabet_map) const;
649 }; // class Presentation
650
659 template <typename Word>
661
670 template <typename Word>
672
683 namespace presentation {
684
697 template <typename Iterator>
698 void throw_if_odd_number_of_rules(Iterator first, Iterator last) {
699 if ((std::distance(first, last) % 2) == 1) {
701 "expected even number of words in \"rules\", found {}",
702 std::distance(first, last));
703 }
704 }
705
717 template <typename Word>
721
740 template <typename Word>
742 std::string_view arg = "1st");
743
757 template <typename Word>
758 [[nodiscard]] bool is_normalized(Presentation<Word> const& p);
759
778 template <typename Word, typename Iterator>
780 Iterator first,
781 Iterator last) {
782 // TODO(0) check if there are an odd number of rules
783 for (auto it = first; it != last; ++it) {
784 p.throw_if_letter_not_in_alphabet(it->cbegin(), it->cend());
785 }
786 }
787
802 template <typename Word>
803 void throw_if_contains_duplicates(Word const& word, std::string_view where);
804
820 // TODO(1): This is very similar to the checks done in
821 // throw_if_letter_not_in_alphabet, except there is no alphabet_map here. It
822 // would be good if there was not duplication
823 template <typename Word>
824 void throw_if_word_not_over_alphabet(Word const& alphabet,
825 Word const& word);
826
845 template <typename Word>
846 void throw_if_bad_inverses(Word const& alphabet, Word const& inverses);
847
870 template <typename Word1, typename Word2>
872 Word2 const& inverses) {
873 p.throw_if_letter_not_in_alphabet(inverses.begin(), inverses.end());
874 throw_if_bad_inverses(p.alphabet(), inverses);
875 }
876
901 template <typename Word1, typename Word2>
903 Word2 const& letters,
904 Word2 const& inverses);
905
930 template <typename Word>
932
949 template <typename Word>
951 Word const& lhop,
952 Word const& rhop) {
953 p.add_rule_no_checks(lhop.begin(), lhop.end(), rhop.begin(), rhop.end());
954 }
955
969 template <typename Word>
970 void add_rule(Presentation<Word>& p, Word const& lhop, Word const& rhop) {
971 p.add_rule(lhop.begin(), lhop.end(), rhop.begin(), rhop.end());
972 }
973
990 char const* lhop,
991 char const* rhop);
992
1005 char const* lhop,
1006 char const* rhop);
1007
1021 std::string const& lhop,
1022 char const* rhop);
1023
1037 char const* lhop,
1038 std::string const& rhop);
1039
1057 std::string const& lhop,
1058 char const* rhop);
1059
1077 char const* lhop,
1078 std::string const& rhop);
1079
1097 template <typename Word, typename Letter>
1101 p.add_rule_no_checks(lhop.begin(), lhop.end(), rhop.begin(), rhop.end());
1102 }
1103
1117 template <typename Word, typename Letter>
1121 p.add_rule(lhop.begin(), lhop.end(), rhop.begin(), rhop.end());
1122 }
1123
1142 template <typename Word, typename Iterator>
1143 void add_rules(Presentation<Word>& p, Iterator first, Iterator last) {
1144 for (auto it = first; it != last; it += 2) {
1145 add_rule(p, *it, *(it + 1));
1146 }
1147 }
1148
1166 template <typename Word, typename Iterator>
1168 Iterator first,
1169 Iterator last) {
1170 for (auto it = first; it != last; it += 2) {
1171 add_rule_no_checks(p, *it, *(it + 1));
1172 }
1173 }
1174
1190 template <typename Word>
1195
1212 template <typename Word>
1214 add_rules(p, q.rules.cbegin(), q.rules.cend());
1215 }
1216
1234 template <typename Word>
1235 [[nodiscard]] bool contains_rule(Presentation<Word>& p,
1236 Word const& lhs,
1237 Word const& rhs);
1238
1253 template <typename Word>
1256
1271 template <typename Word>
1274
1298 template <typename Word>
1300 Word const& vals,
1302 = UNDEFINED);
1303
1328 char const* vals,
1329 char e = UNDEFINED);
1330
1345 template <typename Word>
1347
1360 template <typename Word>
1362
1383 template <typename Word>
1385
1398 template <typename Word>
1400
1416 template <typename Word, typename Compare>
1417 bool sort_each_rule(Presentation<Word>& p, Compare cmp);
1418
1419 // TODO(later) is_each_rule_sorted?
1420
1433 template <typename Word, typename Compare>
1434 void sort_rules(Presentation<Word>& p, Compare cmp);
1435
1445 template <typename Word>
1449
1467 template <typename Word, typename Compare>
1468 bool are_rules_sorted(Presentation<Word> const& p, Compare cmp);
1469
1484 template <typename Word>
1486 return are_rules_sorted(p, ShortLexCompare());
1487 }
1488
1505 // TODO(later) complexity
1506 template <typename Word>
1508
1523 // TODO(later) complexity
1524 template <typename Word, typename Iterator>
1527 Iterator first,
1528 Iterator last);
1529
1546 // TODO(later) complexity
1547 template <typename Word>
1550 return replace_word_with_new_generator(p, w.cbegin(), w.cend());
1551 }
1552
1569 char const* w);
1570
1583 // TODO(later) complexity
1584 template <typename Word>
1586 Word const& existing,
1587 Word const& replacement);
1588
1612 template <typename Word, typename Iterator1, typename Iterator2>
1614 Iterator1 first_existing,
1615 Iterator1 last_existing,
1616 Iterator2 first_replacement,
1617 Iterator2 last_replacement);
1618
1632 char const* existing,
1633 char const* replacement) {
1635 existing,
1636 existing + std::strlen(existing),
1637 replacement,
1638 replacement + std::strlen(replacement));
1639 }
1640
1657 template <typename Word>
1659 Word const& existing,
1660 Word const& replacement);
1661
1678 template <typename Iterator>
1679 size_t length(Iterator first, Iterator last);
1680
1692 template <typename Word>
1693 size_t length(Presentation<Word> const& p) {
1694 return length(p.rules.cbegin(), p.rules.cend());
1695 }
1696
1706 template <typename Word>
1708 for (auto& rule : p.rules) {
1709 std::reverse(rule.begin(), rule.end());
1710 }
1711 }
1712
1724 // This is the only place that JDE can find where a helper that modifies its
1725 // first argument is not void. This is deliberate, since if we weren't to
1726 // return anything, the first parameter would go out of scope immediately
1727 // after this call and this function would be pointless .
1728 template <typename Word>
1730 for (auto& rule : p.rules) {
1731 std::reverse(rule.begin(), rule.end());
1732 }
1733 return std::move(p);
1734 }
1735
1750 template <typename Word>
1752
1766 template <typename Word>
1767 void change_alphabet(Presentation<Word>& p, Word const& new_alphabet);
1768
1781 char const* new_alphabet) {
1782 change_alphabet(p, std::string(new_alphabet));
1783 }
1784
1802 template <typename Iterator>
1803 Iterator longest_rule(Iterator first, Iterator last);
1804
1820 template <typename Word>
1823 return longest_rule(p.rules.cbegin(), p.rules.cend());
1824 }
1825
1843 template <typename Iterator>
1844 Iterator shortest_rule(Iterator first, Iterator last);
1845
1861 template <typename Word>
1864 return shortest_rule(p.rules.cbegin(), p.rules.cend());
1865 }
1866
1881 template <typename Iterator>
1882 typename Iterator::value_type::size_type longest_rule_length(Iterator first,
1883 Iterator last);
1884
1898 template <typename Word>
1899 typename Word::size_type longest_rule_length(Presentation<Word> const& p) {
1900 return longest_rule_length(p.rules.cbegin(), p.rules.cend());
1901 }
1902
1917 template <typename Iterator>
1918 typename Iterator::value_type::size_type
1919 shortest_rule_length(Iterator first, Iterator last);
1920
1934 template <typename Word>
1935 typename Word::size_type shortest_rule_length(Presentation<Word> const& p) {
1936 return shortest_rule_length(p.rules.cbegin(), p.rules.cend());
1937 }
1938
1953 template <typename Word>
1955
1971 template <typename Word>
1974
1991 template <typename Word>
1994
2011 template <typename Word>
2013
2036 template <typename Word>
2038
2061 // not noexcept because std::vector::operator[] isn't
2062 template <typename Word>
2064
2084 // not noexcept because is_strongly_compressible isn't
2085 template <typename Word>
2087
2116 template <typename Word>
2117 bool reduce_to_2_generators(Presentation<Word>& p, size_t index = 0);
2118
2144 template <typename Word>
2146 Word& letters,
2147 Word& inverses);
2148
2178 template <typename Word>
2179 [[deprecated]] void try_detect_inverses(Presentation<Word> const& p,
2180 Word& letters,
2181 Word& inverses) {
2182 try_detect_group_inverses(p, letters, inverses);
2183 }
2184
2205 template <typename Word>
2208
2232 template <typename Word>
2233 [[deprecated]] std::pair<Word, Word>
2237
2253 template <typename Word>
2255 Word const& letters) {
2256 for (auto x : letters) {
2257 add_rule_no_checks(p, {x, x}, {x});
2258 }
2259 }
2260
2276 template <typename Word>
2278 word_type const& letters) {
2279 for (auto x : letters) {
2280 add_rule_no_checks(p, {x, x}, {});
2281 }
2282 }
2283
2300 template <typename Word>
2302 Word const& letters1,
2303 Word const& letters2);
2304
2320 template <typename Word>
2322 Word const& letters) {
2323 add_commutes_rules_no_checks(p, letters, letters);
2324 }
2325
2342 template <typename Word>
2344 Word const& letters,
2346
2348 // commutator - Word
2350
2372 template <typename Word>
2373 Word commutator_no_checks(Word const& x,
2374 Word const& y,
2375 Word const& alphabet,
2376 Word const& inverses);
2377
2398 template <typename Word>
2400 Word const& x,
2401 Word const& y,
2402 Word const& inverses) {
2403 return commutator_no_checks(x, y, p.alphabet(), inverses);
2404 }
2405
2423 template <typename Word>
2425 Word const& x,
2426 Word const& y) {
2427 auto [alphabet, inverses] = try_detect_group_inverses(p);
2428 return commutator_no_checks(x, y, alphabet, inverses);
2429 }
2430
2453 template <typename Word>
2454 Word commutator(Word const& x,
2455 Word const& y,
2456 Word const& alphabet,
2457 Word const& inverses);
2458
2481 template <typename Word>
2483 Word const& x,
2484 Word const& y,
2485 Word const& inverses);
2486
2507 template <typename Word>
2508 Word commutator(Presentation<Word> const& p, Word const& x, Word const& y);
2509
2511 // add_commutator_rules - Word
2513
2536 // TODO(1): InversePresentation specific implementation
2537 template <typename Word>
2540 Word const& x,
2541 Word const& y,
2542 Word const& alphabet,
2543 Word const& inverses,
2545 Word lhs = commutator_no_checks(x, y, alphabet, inverses);
2546 Word rhs = (id == UNDEFINED ? Word({}) : Word({id}));
2547 add_rule_no_checks(p, lhs, rhs);
2548 }
2549
2570 template <typename Word>
2573 Word const& x,
2574 Word const& y,
2575 Word const& inverses,
2577 add_commutator_rule_no_checks(p, x, y, p.alphabet(), inverses, id);
2578 }
2579
2598 template <typename Word>
2601 Word const& x,
2602 Word const& y,
2604 auto [alphabet, inverses] = try_detect_group_inverses(p);
2605 add_commutator_rule_no_checks(p, x, y, alphabet, inverses, id);
2606 }
2607
2635 template <typename Word>
2637 Word const& x,
2638 Word const& y,
2639 Word const& alphabet,
2640 Word const& inverses,
2642 = UNDEFINED);
2643
2666 template <typename Word>
2668 Word const& x,
2669 Word const& y,
2670 Word const& inverses,
2672 = UNDEFINED);
2673
2696 template <typename Word>
2698 Word const& x,
2699 Word const& y,
2701 = UNDEFINED);
2702
2730 template <typename Word1, typename Word2>
2732 Word2 const& letters,
2733 Word2 const& inverses);
2734
2741 // Note that this doesn't work when Word = std::string and so we also
2742 // require an overload specifically taking initializer_list's too.
2743 template <typename Word>
2745 Word const& letters,
2746 Word const& inverses) {
2747 balance_no_checks<Word, Word>(p, letters, inverses);
2748 }
2749
2770 template <typename Word>
2771 void balance_no_checks(Presentation<Word>& p, Word const& inverses) {
2772 balance_no_checks(p, p.alphabet(), inverses);
2773 }
2774
2782 // clang-format off
2783 // NOLINTNEXTLINE(whitespace/line_length)
2785 // clang-format on
2786 static inline void balance_no_checks
2787 [[deprecated]] (Presentation<std::string>& p,
2788 std::string_view letters,
2789 std::string_view inverses) {
2791 }
2792
2800 // clang-format off
2801 // NOLINTNEXTLINE(whitespace/line_length)
2803 // clang-format on
2804 static inline void balance_no_checks
2805 [[deprecated]] (Presentation<std::string>& p,
2806 char const* letters,
2807 char const* inverses) {
2808 balance_no_checks(p, std::string(letters), std::string(inverses));
2809 }
2810
2831 template <typename Word1, typename Word2>
2833 Word2 const& letters,
2834 Word2 const& inverses) {
2836 throw_if_bad_inverses(p, letters, inverses);
2837
2838 balance_no_checks(p, letters, inverses);
2839 }
2840
2859 template <typename Word>
2860 void balance(Presentation<Word>& p, Word const& inverses) {
2861 throw_if_bad_inverses(p, p.alphabet(), inverses);
2862 balance_no_checks(p, p.alphabet(), inverses);
2863 }
2864
2871 // Note that this doesn't work when Word = std::string and so we also
2872 // require an overload specifically taking initializer_list's too.
2873 template <typename Word>
2875 Word const& letters,
2876 Word const& inverses) {
2877 balance<Word, Word>(p, letters, inverses);
2878 }
2879
2895 // There's no no_check version of this function because we need to try and
2896 // detect the inverse and if we cannot we have to throw an exception.
2897 template <typename Word>
2899
2922 template <typename Word1, typename Word2>
2924 Word2 const& relator);
2925
2933 template <typename Word>
2935 Word const& relator) {
2937 }
2938
2946 char const* relator) {
2948 p, std::string_view(relator));
2949 }
2950
2971 template <typename Word1, typename Word2>
2972 void add_cyclic_conjugates(Presentation<Word1>& p, Word2 const& relator);
2973
2981 template <typename Word>
2982 void add_cyclic_conjugates(Presentation<Word>& p, Word const& relator) {
2984 }
2985
2993 char const* relator) {
2995 p, std::string_view(relator));
2996 }
2997
3010 std::string const& var_name);
3011
3024 std::string const& var_name);
3025
3043 template <typename Word>
3044 [[nodiscard]] typename std::vector<Word>::iterator
3046 Word const& lhs,
3047 Word const& rhs);
3048
3063 template <typename Word>
3064 [[nodiscard]] typename std::vector<Word>::iterator
3065 find_rule(Presentation<Word>& p, Word const& lhs, Word const& rhs) {
3067 return find_rule_no_checks(p, lhs, rhs);
3068 }
3069
3087 template <typename Word>
3088 [[nodiscard]] typename std::vector<Word>::const_iterator
3090 Word const& lhs,
3091 Word const& rhs) {
3092 return find_rule_no_checks(const_cast<Presentation<Word>&>(p), lhs, rhs);
3093 }
3094
3109 template <typename Word>
3110 [[nodiscard]] typename std::vector<Word>::const_iterator
3111 find_rule(Presentation<Word> const& p, Word const& lhs, Word const& rhs) {
3112 return find_rule(const_cast<Presentation<Word>&>(p), lhs, rhs);
3113 }
3114
3132 template <typename Word>
3133 [[nodiscard]] size_t index_rule_no_checks(Presentation<Word> const& p,
3134 Word const& lhs,
3135 Word const& rhs);
3136
3151 template <typename Word>
3152 [[nodiscard]] size_t index_rule(Presentation<Word> const& p,
3153 Word const& lhs,
3154 Word const& rhs) {
3156 return index_rule_no_checks(p, lhs, rhs);
3157 }
3158
3176 template <typename Word>
3177 [[nodiscard]] bool is_rule_no_checks(Presentation<Word> const& p,
3178 Word const& lhs,
3179 Word const& rhs) {
3180 return find_rule_no_checks(p, lhs, rhs) != p.rules.end();
3181 }
3182
3197 template <typename Word>
3198 [[nodiscard]] bool is_rule(Presentation<Word> const& p,
3199 Word const& lhs,
3200 Word const& rhs) {
3201 return find_rule(p, lhs, rhs) != p.rules.end();
3202 }
3203
3204 } // namespace presentation
3205
3219 template <typename Word>
3220 class InversePresentation : public Presentation<Word> {
3221 public:
3225
3229
3232
3235
3238
3239 private:
3240 word_type _inverses;
3241
3242 public:
3243 using Presentation<Word>::Presentation;
3244
3245 // TODO(later) init functions
3246
3255 : Presentation<Word>(p), _inverses() {}
3256
3266 : Presentation<Word>(p), _inverses() {}
3267
3284
3311
3320 word_type const& inverses() const noexcept {
3321 return _inverses;
3322 }
3323
3335
3352 // TODO(0) check if this is used appropriately after rename
3355 }
3356 };
3357
3376 // TODO(later) also we could do a more sophisticated version of this
3377 template <typename Word>
3379 Presentation<Word> const& rhop) {
3380 return lhop.alphabet() == rhop.alphabet() && lhop.rules == rhop.rules;
3381 }
3382
3401 // TODO(later) also we could do a more sophisticated version of this
3402 template <typename Word>
3404 InversePresentation<Word> const& rhop) {
3405 return lhop.alphabet() == rhop.alphabet() && lhop.rules == rhop.rules
3406 && lhop.inverses() == rhop.inverses();
3407 }
3408
3427 template <typename Word>
3429 Presentation<Word> const& rhop) {
3430 return !(lhop == rhop);
3431 }
3432
3451 template <typename Word>
3453 InversePresentation<Word> const& rhop) {
3454 return !(lhop == rhop);
3455 }
3456
3468 template <typename Word>
3470
3482 template <typename Word>
3484
3485 namespace v4 {
3487 // Presentation + function -> Presentation
3489
3490 template <typename Result, typename Word, typename Func>
3491 auto to(Presentation<Word> const& p, Func&& f) -> std::enable_if_t<
3492 std::is_same_v<Presentation<typename Result::word_type>, Result>,
3493 Result>;
3494
3496 // InversePresentation + function -> InversePresentation
3498
3499 template <typename Result, typename Word, typename Func>
3500 auto to(InversePresentation<Word> const& ip, Func&& f) -> std::enable_if_t<
3501 std::is_same_v<InversePresentation<typename Result::word_type>, Result>,
3502 Result>;
3503
3505 // Presentation -> Presentation
3507
3508 template <typename Result, typename Word>
3509 auto to(Presentation<Word> const& p) -> std::enable_if_t<
3510 std::is_same_v<Presentation<typename Result::word_type>, Result>
3511 && !std::is_same_v<typename Result::word_type, Word>,
3512 Result>;
3513
3514 // This function is documented above because Doxygen conflates these two
3515 // functions.
3516 template <typename Result, typename Word>
3517 auto to(Presentation<Word> const& p) noexcept
3518 -> std::enable_if_t<std::is_same_v<Presentation<Word>, Result>,
3519 Result const&> {
3520 return p;
3521 }
3522
3524 // InversePresentation -> InversePresentation
3526
3527 template <typename Result, typename Word>
3528 auto to(InversePresentation<Word> const& ip) noexcept -> std::enable_if_t<
3529 std::is_same_v<InversePresentation<typename Result::word_type>, Result>
3530 && !std::is_same_v<Word, typename Result::word_type>,
3531 Result> {
3532 using WordOutput = typename Result::word_type;
3533 return v4::to<InversePresentation<WordOutput>>(ip, [&ip](auto val) {
3534 return words::human_readable_letter<WordOutput>(ip.index(val));
3535 });
3536 }
3537
3538 // This function is documented above because Doxygen conflates these two
3539 // functions.
3540 template <typename Result, typename Word>
3541 auto to(InversePresentation<Word> const& ip) noexcept
3542 -> std::enable_if_t<std::is_same_v<InversePresentation<Word>, Result>,
3543 Result const&> {
3544 return ip;
3545 }
3546
3548 // Presentation -> InversePresentation
3550
3551 template <template <typename...> typename Thing, typename Word>
3552 auto to(Presentation<Word> const& p) -> std::enable_if_t<
3553 std::is_same_v<InversePresentation<Word>, Thing<Word>>,
3554 InversePresentation<Word>>;
3555 } // namespace v4
3556
3557 namespace detail {
3558
3559 class GreedyReduceHelper {
3560 private:
3561 size_t _best;
3562 int _best_goodness;
3563 std::vector<size_t> _distance_from_root;
3564 std::vector<size_t> _num_leafs;
3565 std::vector<size_t> _scratch;
3566 std::vector<size_t> _suffix_index;
3567
3568 public:
3569 using const_iterator = typename Ukkonen::const_iterator;
3570
3571 explicit GreedyReduceHelper(Ukkonen const& u);
3572
3573 GreedyReduceHelper() = delete;
3574 GreedyReduceHelper(GreedyReduceHelper const&) = delete;
3575 GreedyReduceHelper(GreedyReduceHelper&&) = delete;
3576 GreedyReduceHelper& operator=(GreedyReduceHelper const&) = delete;
3577 GreedyReduceHelper& operator=(GreedyReduceHelper&&) = delete;
3578 ~GreedyReduceHelper();
3579
3580 void pre_order(Ukkonen const& u, size_t v);
3581 void post_order(Ukkonen const& u, size_t v);
3582 std::pair<const_iterator, const_iterator> yield(Ukkonen const& u);
3583 };
3584 } // namespace detail
3585
3596 // clang-format off
3597 // NOLINTNEXTLINE(whitespace/line_length)
3599 // clang-format on
3600 template <typename Thing>
3601 static constexpr bool IsInversePresentation [[deprecated]]
3603
3616 template <typename Thing>
3617 static constexpr bool IsPresentation [[deprecated]]
3619
3620} // namespace libsemigroups
3621
3622#include "presentation.tpp"
3623
3624#endif // LIBSEMIGROUPS_PRESENTATION_HPP_
T cbegin(T... args)
For an implementation of inverse presentations for semigroups or monoids.
Definition presentation.hpp:3220
typename Presentation< Word >::size_type size_type
Size type for rules.
Definition presentation.hpp:3237
typename Presentation< Word >::letter_type letter_type
Type of the letters in the words that constitute the rules of an InversePresentation object.
Definition presentation.hpp:3228
void throw_if_bad_alphabet_rules_or_inverses() const
Check if the InversePresentation is valid.
Definition presentation.hpp:3351
typename Presentation< Word >::iterator iterator
Type of an iterator to either side of a rule.
Definition presentation.hpp:3234
InversePresentation(Presentation< Word > const &p)
Construct an InversePresentation from a Presentation reference.
Definition presentation.hpp:3254
typename Presentation< Word >::word_type word_type
Type of the words in the rules of an InversePresentation object.
Definition presentation.hpp:3224
letter_type inverse(letter_type x) const
Return the inverse of a letter in the alphabet.
InversePresentation & inverses(word_type const &w)
Set the inverse of each letter in the alphabet.
Definition presentation.hpp:3306
InversePresentation(Presentation< Word > &&p)
Construct an InversePresentation from a Presentation rvalue reference.
Definition presentation.hpp:3265
word_type const & inverses() const noexcept
Return the inverse of each letter in the alphabet.
Definition presentation.hpp:3320
InversePresentation & inverses_no_checks(word_type const &w)
Set the inverse of each letter in the alphabet.
typename Presentation< Word >::const_iterator const_iterator
Type of a const iterator to either side of a rule.
Definition presentation.hpp:3231
For an implementation of presentations for semigroups or monoids.
Definition presentation.hpp:103
letter_type add_generator()
Add a generator.
Presentation & remove_generator(letter_type x)
Remove x as a generator.
Presentation & alphabet(word_type &&lphbt)
Set the alphabet from rvalue reference.
void throw_if_bad_alphabet_or_rules() const
Check if the alphabet and rules are valid.
Definition presentation.hpp:639
void throw_if_bad_rules() const
Check if every word in every rule consists only of letters belonging to the alphabet.
Presentation & add_generator_no_checks(letter_type x)
Add x as a generator.
Presentation & add_generator(letter_type x)
Add x as a generator.
Presentation & contains_empty_word(bool val) noexcept
Set whether whether the empty word is a valid relation word.
Definition presentation.hpp:562
typename std::vector< word_type >::size_type size_type
Size type for rules.
Definition presentation.hpp:119
auto alphabet(char const *lphbt) -> std::enable_if_t< std::is_same_v< std::string, word_type >, Return >
Set the alphabet from string literal.
Definition presentation.hpp:272
void throw_if_letter_not_in_alphabet(letter_type c) const
Check if a letter belongs to the alphabet or not.
size_type index_no_checks(letter_type val) const
Return the index of a letter in the alphabet.
Definition presentation.hpp:352
Presentation & alphabet(size_type n)
Set the alphabet by size.
Presentation & alphabet_from_rules()
Set the alphabet to be the letters in the rules.
Presentation & operator=(Presentation &&)
Default move assignment operator.
Presentation & add_rule_no_checks(Iterator1 lhs_begin, Iterator1 lhs_end, Iterator2 rhs_begin, Iterator2 rhs_end)
Add a rule to the presentation.
Definition presentation.hpp:421
typename std::vector< word_type >::iterator iterator
Type of an iterator to either side of a rule.
Definition presentation.hpp:116
Presentation(Presentation const &)
Default copy constructor.
Presentation & alphabet(std::initializer_list< typename word_type::value_type > const &lphbt)
Set the alphabet from std::initializer_list.
Definition presentation.hpp:283
void throw_if_alphabet_has_duplicates() const
Check if the alphabet is valid.
Definition presentation.hpp:576
letter_type letter_no_checks(size_type i) const
Return a letter in the alphabet by index.
Definition presentation.hpp:319
auto alphabet(std::string_view lphbt) -> std::enable_if_t< std::is_same_v< std::string, word_type >, Return & >
Set the alphabet from string_view.
Definition presentation.hpp:260
void throw_if_letter_not_in_alphabet(Iterator1 first, Iterator2 last) const
Check if every letter in a range belongs to the alphabet.
Presentation(Presentation &&)
Default move constructor.
letter_type letter(size_type i) const
Return a letter in the alphabet by index.
std::vector< word_type > rules
Data member holding the rules of the presentation.
Definition presentation.hpp:132
Presentation & operator=(Presentation const &)
Default copy assignment operator.
bool contains_empty_word() const noexcept
Return whether the empty word is a valid relation word.
Definition presentation.hpp:539
Presentation & alphabet(word_type const &lphbt)
Set the alphabet const reference.
size_type index(letter_type val) const
Return the index of a letter in the alphabet.
Presentation & init()
Remove the alphabet and all rules.
word_type const & alphabet() const noexcept
Return the alphabet of the presentation.
Definition presentation.hpp:184
Word word_type
Type of the words in the rules of a Presentation object.
Definition presentation.hpp:106
typename word_type::value_type letter_type
Type of the letters in the words that constitute the rules of a Presentation object.
Definition presentation.hpp:110
Presentation & remove_generator_no_checks(letter_type x)
Remove x as a generator.
Presentation()
Default constructor.
typename std::vector< word_type >::const_iterator const_iterator
Type of a const iterator to either side of a rule.
Definition presentation.hpp:113
Presentation & add_rule(Iterator1 lhs_begin, Iterator1 lhs_end, Iterator2 rhs_begin, Iterator2 rhs_end)
Add a rule to the presentation and check it is valid.
Definition presentation.hpp:445
bool in_alphabet(letter_type val) const
Check if a letter belongs to the alphabet or not.
Definition presentation.hpp:381
typename word_type::const_iterator const_iterator
Alias for word_type iterators.
Definition ukkonen.hpp:106
T distance(T... args)
T cend(T... args)
std::string to_human_readable_repr(Action< Element, Point, Func, Traits, LeftOrRight > const &action)
Return a human readable representation of an Action object.
bool operator!=(Bipartition const &x, Bipartition const &y)
Check bipartitions for inequality.
Definition bipart.hpp:1727
Undefined const UNDEFINED
Value for something undefined.
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:99
Presentation(Presentation< Word > const &) -> Presentation< Word >
Deduction guide.
bool operator==(Presentation< Word > const &lhop, Presentation< Word > const &rhop)
Compare for equality.
Definition presentation.hpp:3378
static constexpr bool IsPresentation
Helper variable template.
Definition presentation.hpp:3618
static constexpr bool IsInversePresentation
Helper variable template.
Definition presentation.hpp:3602
constexpr bool is_specialization_of_v
Helper variable template for is_specialization_of.
Definition is_specialization_of.hpp:84
std::vector< letter_type > word_type
Type for a word over the generators of a semigroup.
Definition types.hpp:99
T move(T... args)
Namespace for Presentation helper functions.
Definition obvinf.hpp:61
std::vector< Word >::iterator find_rule(Presentation< Word > &p, Word const &lhs, Word const &rhs)
Find a rule.
Definition presentation.hpp:3065
Iterator::value_type::size_type longest_rule_length(Iterator first, Iterator last)
Return the maximum length of a rule in the given range.
void add_commutes_rules_no_checks(Presentation< Word > &p, Word const &letters1, Word const &letters2)
Add rules so specific letters commute.
Presentation< Word >::letter_type replace_word_with_new_generator(Presentation< Word > &p, Iterator first, Iterator last)
Replace non-overlapping instances of a subword via iterators.
bool reduce_to_2_generators(Presentation< Word > &p, size_t index=0)
Reduce the number of generators in a -relation presentation to 2.
void add_idempotent_rules_no_checks(Presentation< Word > &p, Word const &letters)
Add rules that define each letter as an idempotent.
Definition presentation.hpp:2254
Iterator longest_rule(Iterator first, Iterator last)
Return an iterator pointing at the left-hand side of the first rule of maximal length in the given ra...
void add_involution_rules_no_checks(Presentation< Word > &p, word_type const &letters)
Add rules that define involution.
Definition presentation.hpp:2277
void throw_if_odd_number_of_rules(Iterator first, Iterator last)
Throw if the distance between iterators is not even.
Definition presentation.hpp:698
Word commutator_no_checks(Word const &x, Word const &y, Word const &alphabet, Word const &inverses)
Return the commutator of two words without checks.
size_t index_rule_no_checks(Presentation< Word > const &p, Word const &lhs, Word const &rhs)
Returns the index of a rule or UNDEFINED.
void add_commutator_rule_no_checks(Presentation< Word > &p, Word const &x, Word const &y, Word const &alphabet, Word const &inverses, typename Presentation< Word >::letter_type id=UNDEFINED)
Add a commutator rule without checks.
Definition presentation.hpp:2538
void reverse(Presentation< Word > &p)
Reverse every rule.
Definition presentation.hpp:1707
bool contains_rule(Presentation< Word > &p, Word const &lhs, Word const &rhs)
Check if a presentation contains a rule.
void greedy_reduce_length_and_number_of_gens(Presentation< Word > &p)
Greedily reduce the length and number of generators of the presentation.
Word longest_subword_reducing_length(Presentation< Word > &p)
Return the longest common subword of the rules.
bool sort_each_rule(Presentation< Word > &p)
Sort the left-hand and right-hand side of each rule by shortlex.
bool is_rule(Presentation< Word > const &p, Word const &lhs, Word const &rhs)
Check whether a rule belongs to a presentation.
Definition presentation.hpp:3198
bool are_rules_sorted(Presentation< Word > const &p, Compare cmp)
Check the rules are sorted relative to cmp .
void add_rules(Presentation< Word > &p, Iterator first, Iterator last)
Add the rules stored in the range [first, last).
Definition presentation.hpp:1143
Iterator shortest_rule(Iterator first, Iterator last)
Return an iterator pointing at the left-hand side of the first rule of minimal length in the given ra...
void balance_no_checks(Presentation< Word1 > &p, Word2 const &letters, Word2 const &inverses)
Balance the length of the left-hand and right-hand sides.
Iterator::value_type::size_type shortest_rule_length(Iterator first, Iterator last)
Return the minimum length of a rule in the given range.
void add_commutator_rule(Presentation< Word > &p, Word const &x, Word const &y, Word const &alphabet, Word const &inverses, typename Presentation< Word >::letter_type id=UNDEFINED)
Add a commutator rule.
void balance(Presentation< Word1 > &p, Word2 const &letters, Word2 const &inverses)
Balance the length of the left-hand and right-hand sides.
Definition presentation.hpp:2832
void remove_trivial_rules(Presentation< Word > &p)
Remove rules consisting of identical words.
void throw_if_contains_duplicates(Word const &word, std::string_view where)
Throws an exception if a word contains duplicate letters.
void add_rules_no_checks(Presentation< Word > &p, Iterator first, Iterator last)
Add the rules stored in the range [first, last).
Definition presentation.hpp:1167
void replace_word(Presentation< Word > &p, Word const &existing, Word const &replacement)
Replace instances of a word on either side of a rule by another word.
void add_rule_no_checks(Presentation< Word > &p, Word const &lhop, Word const &rhop)
Add a rule to the presentation by reference.
Definition presentation.hpp:950
void throw_if_bad_rules(Presentation< Word > const &p, Iterator first, Iterator last)
Check rules against the alphabet of p.
Definition presentation.hpp:779
void try_detect_group_inverses(Presentation< Word > const &p, Word &letters, Word &inverses)
Try to detect group inverses.
void sort_rules(Presentation< Word > &p, Compare cmp)
Sort all of the rules by cmp.
void replace_subword(Presentation< Word > &p, Word const &existing, Word const &replacement)
Replace non-overlapping instances of a subword by another word.
void add_identity_rules(Presentation< Word > &p, typename Presentation< Word >::letter_type e)
Add rules for an identity element.
Presentation< Word >::letter_type make_semigroup(Presentation< Word > &p)
Convert a monoid presentation to a semigroup presentation.
void reduce_complements(Presentation< Word > &p)
If there are rules and where , then replace by .
void normalize_alphabet(Presentation< Word > &p)
Normalize the alphabet to .
bool strongly_compress(Presentation< Word > &p)
Strongly compress a -relation presentation.
bool is_rule_no_checks(Presentation< Word > const &p, Word const &lhs, Word const &rhs)
Check whether a rule belongs to a presentation.
Definition presentation.hpp:3177
Word commutator(Word const &x, Word const &y, Word const &alphabet, Word const &inverses)
Return the commutator of two words.
void add_cyclic_conjugates(Presentation< Word1 > &p, Word2 const &relator)
Add all cyclic permutations of a word as relators in a presentation.
void remove_redundant_generators(Presentation< Word > &p)
Remove any trivially redundant generators.
void throw_if_word_not_over_alphabet(Word const &alphabet, Word const &word)
Throws an exception if a word is not over an alphabet.
std::vector< Word >::iterator find_rule_no_checks(Presentation< Word > &p, Word const &lhs, Word const &rhs)
Find a rule.
void greedy_reduce_length(Presentation< Word > &p)
Greedily reduce the length of the presentation using longest_subword_reducing_length.
void change_alphabet(Presentation< Word > &, Word const &)
Change or re-order the alphabet.
void add_inverse_rules(Presentation< Word > &p, Word const &vals, typename Presentation< Word >::letter_type e=UNDEFINED)
Add rules for inverses.
bool is_strongly_compressible(Presentation< Word > const &p)
Return true if the -relation presentation can be strongly compressed.
void throw_if_bad_inverses(Word const &alphabet, Word const &inverses)
Throws an exception if the argument inverses does not define valid inverses for alphabet.
void remove_duplicate_rules(Presentation< Word > &p)
Remove duplicate rules.
size_t length(Iterator first, Iterator last)
Return the sum of the lengths of all values in the range [first, last).
std::string to_report_string(Presentation< Word > const &p)
Return a representation of a presentation to appear in the reporting output.
Presentation< Word >::letter_type first_unused_letter(Presentation< Word > const &p)
Return the first letter not in the alphabet of a presentation.
void add_cyclic_conjugates_no_checks(Presentation< Word1 > &p, Word2 const &relator)
Add all cyclic permutations of a word as relators in a presentation.
void try_detect_inverses(Presentation< Word > const &p, Word &letters, Word &inverses)
Try to detect group inverses.
Definition presentation.hpp:2179
bool is_normalized(Presentation< Word > const &p)
Check if the presentation is normalized.
void add_rule(Presentation< Word > &p, Word const &lhop, Word const &rhop)
Add a rule to the presentation by reference and check.
Definition presentation.hpp:970
void throw_if_not_normalized(Presentation< Word > const &p, std::string_view arg="1st")
Throws if the presentation isn't normalized.
size_t index_rule(Presentation< Word > const &p, Word const &lhs, Word const &rhs)
Returns the index of a rule or UNDEFINED.
Definition presentation.hpp:3152
void add_zero_rules(Presentation< Word > &p, typename Presentation< Word >::letter_type z)
Add rules for a zero element.
std::string to_gap_string(Presentation< word_type > const &p, std::string const &var_name)
Return the code that would create p in GAP.
Namespace containing some operators for creating words.
Definition word-range.hpp:2113
Word::value_type human_readable_letter(size_t i)
Returns a character by index in human readable order.
Definition word-range.hpp:2149
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
auto to(detail::KnuthBendixImpl< Rewriter, ReductionOrder > &kb) -> std::enable_if_t< std::is_same_v< Presentation< typename Result::word_type >, Result >, Result >
No doc.
T reverse(T... args)
T strlen(T... args)
Empty base for presentation-like classes.
Definition presentation.hpp:78
A stateless struct with binary call operator using shortlex_compare.
Definition order.hpp:380