libsemigroups  v3.3.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
word-range.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2020-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 declarations for function related to words (counting, and
20// converting) in libsemigroups.
21
22// TODO:
23// * iwyu
24// * nodiscard
25// * tests for code coverage
26
27#ifndef LIBSEMIGROUPS_WORD_RANGE_HPP_
28#define LIBSEMIGROUPS_WORD_RANGE_HPP_
29
30#include <cstddef> // for size_t
31#include <cstdint> // for uint64_t, uint8_t
32#include <initializer_list> // for initializer_list
33#include <limits> // for numeric_limits
34#include <string> // for basic_string
35#include <string_view> // for string_view
36#include <type_traits> // for enable_if_t
37#include <unordered_map> // for vector, operator==
38#include <utility> // for forward
39#include <variant> // for visit, operator==
40#include <vector> // for vector, operator==
41
42#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
43#include "exception.hpp" // for LibsemigroupsException
44#include "ranges.hpp" // for begin, end
45#include "types.hpp" // for word_type
46
47#include "detail/print.hpp" // for isprint etc
48#include "detail/word-iterators.hpp" // for const_wilo_iterator
49
50namespace libsemigroups {
51
52 enum class Order : uint8_t; // forward decl
53
54 namespace detail {
55 std::string const& chars_in_human_readable_order();
56 }
57
69 template <typename Word>
70 Word& reverse(Word&& w) {
71 std::reverse(w.begin(), w.end());
72 return w;
73 }
74
76 // Words
78
104
124 [[nodiscard]] uint64_t number_of_words(size_t n, size_t min, size_t max);
125
140 [[nodiscard]] word_type random_word(size_t length, size_t nr_letters);
141
187 [[nodiscard]] detail::const_wilo_iterator cbegin_wilo(size_t n,
188 size_t upper_bound,
189 word_type&& first,
190 word_type&& last);
191
195 [[nodiscard]] detail::const_wilo_iterator cbegin_wilo(size_t n,
196 size_t upper_bound,
197 word_type const& first,
198 word_type const& last);
199
208 [[nodiscard]] detail::const_wilo_iterator
209 cend_wilo(size_t n, size_t upper_bound, word_type&& first, word_type&& last);
210
215 [[nodiscard]] detail::const_wilo_iterator cend_wilo(size_t n,
216 size_t upper_bound,
217 word_type const& first,
218 word_type const& last);
219
257 [[nodiscard]] detail::const_wislo_iterator cbegin_wislo(size_t n,
258 word_type&& first,
259 word_type&& last);
260
264 [[nodiscard]] detail::const_wislo_iterator
265 cbegin_wislo(size_t n, word_type const& first, word_type const& last);
266
275 [[nodiscard]] detail::const_wislo_iterator cend_wislo(size_t n,
276 word_type&& first,
277 word_type&& last);
278
283 [[nodiscard]] detail::const_wislo_iterator cend_wislo(size_t n,
284 word_type const& first,
285 word_type const& last);
286
319 class WordRange {
320 public:
323
325 using output_type = word_type const&;
326
327 private:
328 using const_iterator = std::variant<detail::const_wilo_iterator,
329 detail::const_wislo_iterator>;
330
331 size_type _alphabet_size;
332 mutable const_iterator _current;
333 mutable const_iterator _end;
334 mutable bool _current_valid;
335 word_type _first;
336 word_type _last;
337 Order _order;
338 size_type _upper_bound;
339 mutable size_type _visited;
340
341 void set_iterator() const;
342
343 public:
355 [[nodiscard]] output_type get() const noexcept {
356 set_iterator();
357 return std::visit(
358 [](auto& it) -> auto const& { return *it; }, _current);
359 }
360
369 void next() noexcept {
370 set_iterator();
371 if (!at_end()) {
372 ++_visited;
373 }
374 std::visit([](auto& it) { ++it; }, _current);
375 }
376
384 [[nodiscard]] bool at_end() const noexcept {
385 set_iterator();
386 return _current == _end;
387 }
388
399 [[nodiscard]] size_t size_hint() const noexcept {
400 return number_of_words(_alphabet_size, _first.size(), _last.size())
401 - _visited;
402 // This is only the actual size if _order is shortlex
403 }
404
416 [[nodiscard]] size_t count() const noexcept;
417
418 // For some reason, there needs to be two doxygen comment lines here for
419 // this to render.
421 static constexpr bool is_finite = true; // This may not always be true
422
426 static constexpr bool is_idempotent = true;
427
439 init();
440 }
441
452
457
462
467
472
476 ~WordRange();
477
489 _current_valid &= (n == _alphabet_size);
490 _alphabet_size = n;
491 return *this;
492 }
493
502 [[nodiscard]] size_type alphabet_size() const noexcept {
503 return _alphabet_size;
504 }
505
519 WordRange& first(word_type const& frst) {
520 _current_valid &= (frst == _first);
521 _first = frst;
522 return *this;
523 }
524
535 [[nodiscard]] word_type const& first() const noexcept {
536 return _first;
537 }
538
551 WordRange& last(word_type const& lst) {
552 _current_valid &= (lst == _last);
553 _last = lst;
554 return *this;
555 }
556
567 [[nodiscard]] word_type const& last() const noexcept {
568 return _last;
569 }
570
582
591 [[nodiscard]] Order order() const noexcept {
592 return _order;
593 }
594
607 _current_valid &= (n == _upper_bound);
608 _upper_bound = n;
609 return *this;
610 }
611
621 [[nodiscard]] size_type upper_bound() const noexcept {
622 return _upper_bound;
623 }
624
637 first(word_type(val, 0));
638 return *this;
639 }
640
641 // No corresponding getter for min, because what would it mean? Could be the
642 // length of first(), but that doesn't correspond well to what happens with
643 // the setter.
644
657 last(word_type(val, 0));
658 return *this;
659 }
660
676 // REQUIRED so that we can use StringRange in range based loops
677 auto begin() const noexcept {
678 return rx::begin(*this);
679 }
680
696 // REQUIRED so that we can use StringRange in range based loops
697 auto end() const noexcept {
698 return rx::end(*this);
699 }
700
701 // TODO(now) this doc doesn't feel nice, but JDE can't think of a good way
702 // to write it.
721 // Required so StringRange can accurately set _current_valid
722 bool valid() const noexcept {
723 return _current_valid;
724 }
725 };
726
740 size_t max_width = 72);
741
743 // Strings -> Words
745
746 namespace v4 {
768 // TODO (later) a version that takes a word_type, so that we can permute the
769 // letters in a word
770 // TODO(0) remove default template param
771 template <typename From>
772 class ToWord {
773 private:
775
776 public:
779 using from_type = From;
780
784 ToWord() : _alphabet_map() {
785 init();
786 }
787
791 ToWord(ToWord const&);
792
797
802
807
811 ~ToWord();
812
825 _alphabet_map.clear();
826 return *this;
827 }
828
837 explicit ToWord(From const& alphabet) : _alphabet_map() {
838 init(alphabet);
839 }
840
854 ToWord& init(From const& alphabet);
855
865 [[nodiscard]] bool empty() const noexcept {
866 return _alphabet_map.empty();
867 }
868
884 [[nodiscard]] from_type alphabet() const;
885
897 [[nodiscard]] bool
898 can_convert_letter(typename from_type::value_type const& c) const {
899 return _alphabet_map.count(c) == 1;
900 }
901
902 // TODO remove "string" from all the doc here
924 void call_no_checks(word_type& output, From const& input) const;
925
942 [[nodiscard]] word_type call_no_checks(From const& input) const {
943 word_type output;
944 call_no_checks(output, input);
945 return output;
946 }
947
968 void operator()(word_type& output, From const& input) const;
969
985 [[nodiscard]] word_type operator()(From const& input) const {
986 word_type output;
987 operator()(output, input);
988 return output;
989 }
990
991 // TODO remove reference to char in the doc
1007 [[nodiscard]] letter_type
1008 operator()(typename From::value_type input) const {
1009 // TODO improve this
1010 // FIXME(1) it also doesn't work for example to_word('a') returns 63 for
1011 // some reason
1012 word_type output;
1013 // operator()(output, std::string_view(&input, 1));
1014 operator()(output, std::string(input, 1));
1015 return output[0];
1016 }
1017
1034 [[nodiscard]] letter_type
1035 call_no_checks(typename From::value_type input) const {
1036 return _alphabet_map.find(input)->second;
1037 }
1038
1039 template <typename InputRange>
1040 struct Range;
1041
1061 template <typename InputRange,
1062 typename = std::enable_if_t<rx::is_input_or_sink_v<InputRange>>>
1063 [[nodiscard]] constexpr auto operator()(InputRange&& input) const {
1064 using Inner = rx::get_range_type_t<InputRange>;
1065 return Range<Inner>(std::forward<InputRange>(input), *this);
1066 }
1067 }; // class ToWord
1068
1069 template <size_t N>
1070 ToWord(const char (&)[N]) -> ToWord<std::string>;
1071
1072 template <typename From>
1073 template <typename InputRange>
1074 struct ToWord<From>::Range {
1075 using output_type = word_type;
1076
1077 static constexpr bool is_finite = rx::is_finite_v<InputRange>;
1078 static constexpr bool is_idempotent = rx::is_idempotent_v<InputRange>;
1079
1080 InputRange _input;
1081 ToWord<From> _to_word;
1082
1083 explicit Range(InputRange const& input, ToWord<From> const& t_wrd)
1084 : _input(input), _to_word(t_wrd) {}
1085
1086 explicit Range(InputRange&& input, ToWord<From> const& t_wrd)
1087 : _input(std::move(input)), _to_word(t_wrd) {}
1088
1089 explicit Range(InputRange const& input, ToWord<From>&& t_wrd)
1090 : _input(input), _to_word(std::move(t_wrd)) {}
1091
1092 explicit Range(InputRange&& input, ToWord<From>&& t_wrd)
1093 : _input(std::move(input)), _to_word(std::move(t_wrd)) {}
1094
1095 // Not noexcept because ToWord<From>()() isn't
1096 [[nodiscard]] output_type get() const {
1097 return _to_word.operator()(_input.get());
1098 }
1099
1100 constexpr void next() noexcept {
1101 _input.next();
1102 }
1103
1104 [[nodiscard]] constexpr bool at_end() const noexcept {
1105 return _input.at_end();
1106 }
1107
1108 [[nodiscard]] constexpr size_t size_hint() const noexcept {
1109 return _input.size_hint();
1110 }
1111 };
1112
1123 template <typename From>
1125 return fmt::format("<ToWord object with alphabet \"{}\">",
1126 twrd.alphabet());
1127 }
1128
1129 } // namespace v4
1130
1131 using ToWord [[deprecated]] = v4::ToWord<std::string>;
1132
1134 // Words -> Strings
1136
1158 class ToString {
1159 public:
1163 ToString() : _alphabet_map() {
1164 init();
1165 }
1166
1167 // TODO (later) noexcept?
1172
1177
1182
1187
1191 ~ToString();
1192
1204 ToString& init() noexcept {
1205 _alphabet_map.clear();
1206 return *this;
1207 }
1208
1217 explicit ToString(std::string const& alphabet) : _alphabet_map() {
1218 init(alphabet);
1219 }
1220
1235
1245 [[nodiscard]] bool empty() const noexcept {
1246 return _alphabet_map.empty();
1247 }
1248
1264 [[nodiscard]] std::string alphabet() const;
1265
1277 [[nodiscard]] bool can_convert_letter(letter_type const& l) const {
1278 return _alphabet_map.count(l) == 1;
1279 }
1280
1301 void call_no_checks(std::string& output, word_type const& input) const;
1302
1319 [[nodiscard]] std::string call_no_checks(word_type const& input) const {
1320 std::string output;
1321 call_no_checks(output, input);
1322 return output;
1323 }
1324
1344 void operator()(std::string& output, word_type const& input) const;
1345
1361 [[nodiscard]] std::string operator()(word_type const& input) const {
1362 std::string output;
1363 operator()(output, input);
1364 return output;
1365 }
1366
1383 template <typename Int>
1384 [[nodiscard]] std::string
1386 static_assert(std::is_integral_v<Int>);
1387 word_type copy(input.begin(), input.end());
1388 return operator()(copy);
1389 }
1390
1391 template <typename InputRange>
1392 struct Range;
1393
1411 template <typename InputRange,
1412 typename = std::enable_if_t<rx::is_input_or_sink_v<InputRange>>>
1413 [[nodiscard]] constexpr auto operator()(InputRange&& input) const {
1414 using Inner = rx::get_range_type_t<InputRange>;
1415 return Range<Inner>(std::forward<InputRange>(input), *this);
1416 }
1417
1418 private:
1419 // We could use std::vector<char> (or similar) here, but an
1420 // unordered_ordered hap has been used instead to allow for potential future
1421 // conversions between different types.
1423 };
1424
1425 template <typename InputRange>
1426 struct ToString::Range {
1427 using output_type = std::string;
1428
1429 static constexpr bool is_finite = rx::is_finite_v<InputRange>;
1430 static constexpr bool is_idempotent = rx::is_idempotent_v<InputRange>;
1431
1432 InputRange _input;
1433 ToString _to_string;
1434
1435 Range(InputRange const& input, ToString const& t_str)
1436 : _input(input), _to_string(t_str) {}
1437
1438 Range(InputRange&& input, ToString const& t_str)
1439 : _input(std::move(input)), _to_string(t_str) {}
1440
1441 Range(InputRange const& input, ToString&& t_str)
1442 : _input(input), _to_string(std::move(t_str)) {}
1443
1444 Range(InputRange&& input, ToString&& t_str)
1445 : _input(std::move(input)), _to_string(std::move(t_str)) {}
1446
1447 ~Range();
1448
1449 // Not noexcept because ToString()() isn't
1450 [[nodiscard]] output_type get() const {
1451 return _to_string(_input.get());
1452 }
1453
1454 constexpr void next() noexcept {
1455 _input.next();
1456 }
1457
1458 [[nodiscard]] constexpr bool at_end() const noexcept {
1459 return _input.at_end();
1460 }
1461
1462 [[nodiscard]] constexpr size_t size_hint() const noexcept {
1463 return _input.size_hint();
1464 }
1465
1466 [[nodiscard]] constexpr size_t count() const noexcept {
1467 return _input.count();
1468 }
1469 };
1470
1471 // NOTE: This is a terrible hack to avoid compiler warnings. Maybe remove in
1472 // the future?
1473#if defined(__clang__)
1474 template <typename InputRange>
1475 ToString::Range<InputRange>::~Range<InputRange>() = default;
1476#elif defined(__GNUC__)
1477 template <typename InputRange>
1478 ToString::Range<InputRange>::~Range() = default;
1479#endif
1480
1491 [[nodiscard]] inline std::string
1493 return fmt::format("<ToString object with alphabet \"{}\">",
1494 tstr.alphabet());
1495 }
1496
1498 // StringRange
1500
1501 namespace detail {
1502 void throw_if_random_string_should_throw(std::string const& alphabet,
1503 size_t min,
1504 size_t max);
1505 } // namespace detail
1506
1521 std::string random_string(std::string const& alphabet, size_t length);
1522
1541 size_t min,
1542 size_t max);
1543
1562 auto inline random_strings(std::string const& alphabet,
1563 size_t number,
1564 size_t min,
1565 size_t max) {
1566 detail::throw_if_random_string_should_throw(alphabet, min, max);
1567
1568 // Lambda must capture by copy, as the lambda will exist outside the scope
1569 // of this function once the range is returned.
1570 return rx::generate([alphabet, min, max] {
1571 return random_string(alphabet, min, max);
1572 })
1573 | rx::take(number);
1574 }
1575
1608 // This can in many places be replaced by "WordRange | ToString" but this
1609 // makes some things more awkward and so we retain this class for its
1610 // convenience.
1612 public:
1615
1617 using output_type = std::string const&;
1618
1619 private:
1620 mutable std::string _current;
1621 mutable bool _current_valid;
1622 std::string _letters;
1623 v4::ToWord<std::string> _to_word;
1624 ToString _to_string;
1625 WordRange _word_range;
1626
1627 void init_current() const {
1628 if (!_current_valid) {
1629 _current = _to_string(_word_range.get());
1630 _current_valid = true;
1631 }
1632 }
1633
1634 public:
1647 init_current();
1648 return _current;
1649 }
1650
1659 void next() noexcept {
1660 _word_range.next();
1661 _current_valid = false;
1662 }
1663
1673 bool at_end() const noexcept {
1674 return _word_range.at_end();
1675 }
1676
1687 size_t size_hint() const noexcept {
1688 return _word_range.size_hint();
1689 }
1690
1702 size_t count() const noexcept {
1703 return _word_range.count();
1704 }
1705
1707 static constexpr bool is_finite = true; // This may not always be true
1708
1712 static constexpr bool is_idempotent = true;
1713
1725 init();
1726 }
1727
1738
1741
1744
1747
1750
1752 ~StringRange();
1753
1764
1773 [[nodiscard]] std::string const& alphabet() const noexcept {
1774 return _letters;
1775 }
1776
1790 _word_range.first(_to_word(frst));
1791 _current_valid &= _word_range.valid();
1792 return *this;
1793 }
1794
1805 [[nodiscard]] std::string first() const noexcept {
1806 return _to_string(_word_range.first());
1807 }
1808
1826 _word_range.last(_to_word(lst));
1827 _current_valid &= _word_range.valid();
1828 return *this;
1829 }
1830
1841 [[nodiscard]] std::string last() const noexcept {
1842 return _to_string(_word_range.last());
1843 }
1844
1856 _word_range.order(val);
1857 _current_valid &= _word_range.valid();
1858 return *this;
1859 }
1860
1869 [[nodiscard]] Order order() const noexcept {
1870 return _word_range.order();
1871 }
1872
1885 _word_range.upper_bound(n);
1886 _current_valid &= _word_range.valid();
1887 return *this;
1888 }
1889
1899 [[nodiscard]] size_type upper_bound() const noexcept {
1900 return _word_range.upper_bound();
1901 }
1902
1915 _word_range.min(val);
1916 _current_valid &= _word_range.valid();
1917 return *this;
1918 }
1919
1920 // No corresponding getter for min, because what would it mean? Could be the
1921 // length of first(), but that doesn't correspond well to what happens with
1922 // the setter.
1923
1938 _word_range.max(val);
1939 _current_valid &= _word_range.valid();
1940 return *this;
1941 }
1942
1958 // REQUIRED so that we can use StringRange in range based loops
1959 auto begin() const noexcept {
1960 return rx::begin(*this);
1961 }
1962
1978 // REQUIRED so that we can use StringRange in range based loops
1979 auto end() const noexcept {
1980 return rx::end(*this);
1981 }
1982 };
1983
1997 size_t max_width = 72);
1998
2000 // Literals
2002
2017 namespace literals {
2045 word_type operator"" _w(const char* w, size_t n);
2046
2050 word_type operator"" _w(const char* w);
2051
2073 std::string operator"" _p(const char* w, size_t n);
2074
2079 std::string operator"" _p(const char* w);
2080 } // namespace literals
2081
2083
2100 namespace words {
2101
2117 [[nodiscard]] letter_type human_readable_index(char c);
2118
2135 template <typename Word = std::string>
2136 typename Word::value_type human_readable_letter(size_t i) {
2137 // This check ensures that i is not too large to be converted to a
2138 // Word::value_type. This is check is only needed if the number of
2139 // distinct Word::value objects is less than the number of distinct size_t
2140 // objects.
2141 if constexpr (sizeof(typename Word::value_type) < sizeof(size_t)) {
2145 "expected the argument to be in the range [0, {}), found {}",
2148 i);
2149 }
2150 }
2151 if constexpr (!std::is_same_v<Word, std::string>) {
2152 return static_cast<typename Word::value_type>(i);
2153 } else {
2154 // Choose visible characters a-zA-Z0-9 first before anything else
2155 // The ascii ranges for these characters are: [97, 123), [65, 91),
2156 // [48, 58) so the remaining range of chars that are appended to the end
2157 // after these chars are [0,48), [58, 65), [91, 97), [123, 255]
2158 return detail::chars_in_human_readable_order()[i];
2159 }
2160 }
2161
2163 // operator+
2165
2179
2184
2189
2191 // operator+=
2193
2206 static inline void operator+=(word_type& u, word_type const& v) {
2207 u.insert(u.end(), v.cbegin(), v.cend());
2208 }
2209
2213 inline void operator+=(word_type& u, letter_type a) {
2214 u.push_back(a);
2215 }
2216
2220 inline void operator+=(letter_type a, word_type& u) {
2221 u.insert(u.begin(), a);
2222 }
2223
2225 // pow
2227
2239 template <typename Word>
2240 void pow_inplace(Word& w, size_t n);
2241 // No pow_inplace for string_view or initializer_list because there's no
2242 // where to store the result.
2243
2257 template <typename Word>
2258 Word pow(Word const& x, size_t n) {
2259 Word y(x);
2260 pow_inplace(y, n);
2261 return y;
2262 }
2263
2268
2272 std::string pow(std::string_view w, size_t n);
2273
2275 // prod
2277
2316 template <typename Container, typename Word = Container>
2317 Word prod(Container const& elts, int first, int last, int step = 1);
2318
2323 int first,
2324 int last,
2325 int step = 1) {
2326 return prod<word_type>(word_type(ilist), first, last, step);
2327 }
2328
2332 static inline std::string
2333 prod(std::string_view sv, int first, int last, int step = 1) {
2334 return prod<std::string>(std::string(sv), first, last, step);
2335 }
2336
2341 int first,
2342 int last,
2343 int step = 1) {
2345 std::vector<word_type>(elts), first, last, step);
2346 }
2347
2351 static inline std::string
2353 int first,
2354 int last,
2355 int step = 1) {
2357 sv, first, last, step);
2358 }
2359
2365 template <typename Container, typename Word = Container>
2366 Word prod(Container const& elts, size_t last) {
2367 return prod(elts, 0, static_cast<int>(last), 1);
2368 }
2369
2376 size_t last) {
2377 return prod(elts, 0, static_cast<int>(last), 1);
2378 }
2379
2385 static inline std::string prod(std::string_view elts, size_t last) {
2387 elts, 0, static_cast<int>(last), 1);
2388 }
2389
2396 size_t last) {
2397 return prod(elts, 0, static_cast<int>(last), 1);
2398 }
2399
2405 static inline std::string
2408 std::vector<std::string_view>(elts), 0, static_cast<int>(last), 1);
2409 }
2410
2412 // pow - implementation
2414
2415 template <typename Word>
2416 void pow_inplace(Word& x, size_t n) {
2417 Word y(x);
2418 x.reserve(x.size() * n);
2419 if (n % 2 == 0) {
2420 x = Word({});
2421 }
2422
2423 while (n > 1) {
2424 y += y;
2425 n /= 2;
2426 if (n % 2 == 1) {
2427 x += y;
2428 }
2429 }
2430 }
2431
2433 // prod - implementation
2435
2436 // Note: we could do a version of the below using insert on words, where
2437 // the step is +/- 1.
2438 template <typename Container, typename Word>
2439 Word prod(Container const& elts, int first, int last, int step) {
2440 if (step == 0) {
2441 LIBSEMIGROUPS_EXCEPTION("the 4th argument must not be 0");
2442 } else if (((first < last && step > 0) || (first > last && step < 0))
2443 && elts.size() == 0) {
2444 LIBSEMIGROUPS_EXCEPTION("the 1st argument must not be empty if the "
2445 "given range is not empty");
2446 // TODO Is int signed? Should this also contain
2447 // std::numeric_limits<int>::min?
2448 } else if (elts.size() > std::numeric_limits<int>::max()) {
2450 "the 1st argument must have size less than or equal to {}",
2452 }
2453 Word result;
2454 int const s = elts.size();
2455
2456 if (first < last) {
2457 if (step < 0) {
2458 return result;
2459 }
2460 result.reserve((last - first) / step);
2461
2462 for (int i = first; i < last; i += step) {
2463 size_t const a = (i % s + s) % s;
2464 LIBSEMIGROUPS_ASSERT(static_cast<int>(a) < s);
2465 result += elts[a];
2466 }
2467 } else {
2468 if (step > 0) {
2469 return result;
2470 }
2471 size_t steppos = static_cast<size_t>(-step);
2472 result.reserve((first - last) / steppos);
2473 for (int i = first; i > last; i += step) {
2474 size_t const a = (i % s + s) % s;
2475 LIBSEMIGROUPS_ASSERT(static_cast<int>(a) < s);
2476 result += elts[a];
2477 }
2478 }
2479 return result;
2480 }
2481 } // namespace words
2482
2483 namespace v4 {
2485 // Out-of-line implementation of ToWord mem fns
2487
2488 template <typename From>
2489 ToWord<From>::ToWord(ToWord const&) = default;
2490
2491 template <typename From>
2492 ToWord<From>::ToWord(ToWord&&) = default;
2493
2494 template <typename From>
2495 ToWord<From>& ToWord<From>::operator=(ToWord const&) = default;
2496
2497 template <typename From>
2499
2500 template <typename From>
2501 ToWord<From>::~ToWord() = default;
2502
2503 template <typename From>
2505 if (alphabet.size() > 256) {
2506 // TODO replace 256 with numeric_limits::max - numeric_limits::min
2507 LIBSEMIGROUPS_EXCEPTION("The argument (alphabet) is too big, expected "
2508 "at most 256, found {}",
2509 alphabet.size());
2510 }
2511 auto _old_alphabet_map = _alphabet_map;
2512 init();
2513 LIBSEMIGROUPS_ASSERT(_alphabet_map.empty());
2514 for (letter_type l = 0; l < alphabet.size(); ++l) {
2515 auto it = _alphabet_map.emplace(alphabet[l], l);
2516 if (!it.second) {
2517 // Strong exception guarantee
2518 std::swap(_old_alphabet_map, _alphabet_map);
2519
2520 // TODO(v4) Remove the libsemigroups prefix
2522 "invalid alphabet {}, duplicate letter {}!",
2523 libsemigroups::detail::to_printable(alphabet),
2524 libsemigroups::detail::to_printable(alphabet[l]));
2525 }
2526 }
2527 return *this;
2528 }
2529
2530 template <typename From>
2531 [[nodiscard]] From ToWord<From>::alphabet() const {
2532 if (empty()) {
2533 return From();
2534 }
2535 From output(_alphabet_map.size(), typename From::value_type());
2536 for (auto it : _alphabet_map) {
2537 output[it.second] = it.first;
2538 }
2539 return output;
2540 }
2541
2542 template <typename From>
2544 From const& input) const {
2545 // Empty alphabet implies conversion should use human_readable_index
2546 if (empty()) {
2547 // TODO remove this behaviour
2548 output.resize(input.size(), 0);
2549 std::transform(input.cbegin(),
2550 input.cend(),
2551 output.begin(),
2552 [](char c) { return words::human_readable_index(c); });
2553 } else { // Non-empty alphabet implies conversion should use the
2554 // alphabet.
2555 output.clear();
2556 output.reserve(input.size());
2557 for (auto const& c : input) {
2558 output.push_back(_alphabet_map.at(c));
2559 }
2560 }
2561 }
2562
2563 template <typename From>
2564 void ToWord<From>::operator()(word_type& output, From const& input) const {
2565 if (!empty()) {
2566 for (auto const& c : input) {
2567 if (_alphabet_map.find(c) == _alphabet_map.cend()) {
2568 // TODO improve this like in presentation
2569 // TODO(v4) Remove the libsemigroups prefix
2571 "invalid letter {} in the 2nd argument (input word), "
2572 "expected letters in the alphabet {}!",
2573 libsemigroups::detail::to_printable(c),
2574 libsemigroups::detail::to_printable(alphabet()));
2575 }
2576 }
2577 }
2578 call_no_checks(output, input);
2579 }
2580 } // namespace v4
2581} // namespace libsemigroups
2582
2583#endif // LIBSEMIGROUPS_WORD_RANGE_HPP_
Class for generating strings in a given range and in a particular order.
Definition word-range.hpp:1611
static constexpr bool is_finite
Value indicating that the range is finite.
Definition word-range.hpp:1707
StringRange & operator=(StringRange const &)
Default copy assignment operator.
StringRange & min(size_type val)
Set the first string in the range by length.
Definition word-range.hpp:1914
auto end() const noexcept
Returns an input iterator pointing one beyond the last string in the range.
Definition word-range.hpp:1979
StringRange & upper_bound(size_type n)
Set an upper bound for the length of a string in the range.
Definition word-range.hpp:1884
std::string first() const noexcept
The current first string in the range.
Definition word-range.hpp:1805
StringRange & init()
Initialize an existing StringRange object.
StringRange & max(size_type val)
Set one past the last string in the range by length.
Definition word-range.hpp:1937
std::string last() const noexcept
The current one past the last string in the range.
Definition word-range.hpp:1841
StringRange & alphabet(std::string const &x)
Set the alphabet.
std::string const & alphabet() const noexcept
The current alphabet.
Definition word-range.hpp:1773
StringRange & order(Order val)
Set the order of the strings in the range.
Definition word-range.hpp:1855
StringRange()
Default constructor.
Definition word-range.hpp:1724
output_type get() const
Get the current value.
Definition word-range.hpp:1646
StringRange & first(std::string const &frst)
Set the first string in the range.
Definition word-range.hpp:1789
auto begin() const noexcept
Returns an input iterator pointing to the first string in the range.
Definition word-range.hpp:1959
size_type upper_bound() const noexcept
The current upper bound on the length of a string in the range.
Definition word-range.hpp:1899
StringRange(StringRange &&)
Default move constructor.
Order order() const noexcept
The current order of the strings in the range.
Definition word-range.hpp:1869
void next() noexcept
Advance to the next value.
Definition word-range.hpp:1659
static constexpr bool is_idempotent
Definition word-range.hpp:1712
size_t size_hint() const noexcept
The possible size of the range.
Definition word-range.hpp:1687
typename std::vector< std::string >::size_type size_type
Alias for the size type.
Definition word-range.hpp:1614
StringRange & operator=(StringRange &&)
Default move assignment operator.
std::string const & output_type
The type of the output of the range object.
Definition word-range.hpp:1617
size_t count() const noexcept
The actual size of the range.
Definition word-range.hpp:1702
bool at_end() const noexcept
Check if the range object is exhausted.
Definition word-range.hpp:1673
StringRange & last(std::string const &lst)
Set one past the last string in the range.
Definition word-range.hpp:1825
StringRange(StringRange const &)
Default copy constructor.
Class for converting word_type into std::string with specified alphabet.
Definition word-range.hpp:1158
ToString & init() noexcept
Initialize an existing ToString object.
Definition word-range.hpp:1204
bool can_convert_letter(letter_type const &l) const
Definition word-range.hpp:1277
ToString()
Default constructor.
Definition word-range.hpp:1163
constexpr auto operator()(InputRange &&input) const
Call operator for combining with other range objects.
Definition word-range.hpp:1413
bool empty() const noexcept
Check if the alphabet is defined.
Definition word-range.hpp:1245
ToString(ToString &&)
Default move constructor.
std::string operator()(std::initializer_list< Int > input) const
Convert a std::initializer_list to a std::string.
Definition word-range.hpp:1385
std::string call_no_checks(word_type const &input) const
Convert a word_type to a std::string.
Definition word-range.hpp:1319
ToString(ToString const &)
Default copy constructor.
std::string operator()(word_type const &input) const
Convert a word_type to a std::string.
Definition word-range.hpp:1361
ToString & init(std::string const &alphabet)
Initialize an existing Tostring object.
ToString & operator=(ToString &&)
Default move assignment.
void call_no_checks(std::string &output, word_type const &input) const
Convert a word_type to a std::string.
ToString(std::string const &alphabet)
Construct with given alphabet.
Definition word-range.hpp:1217
void operator()(std::string &output, word_type const &input) const
Convert a word_type to a std::string.
std::string alphabet() const
Return the alphabet used for conversion.
ToString & operator=(ToString const &)
Default copy assignment.
Class for converting strings to word_type with specified alphabet.
Definition word-range.hpp:772
void operator()(word_type &output, From const &input) const
Convert a string to a word_type.
Definition word-range.hpp:2564
ToWord & init(From const &alphabet)
Initialize an existing ToWord object.
Definition word-range.hpp:2504
std::string from_type
Definition word-range.hpp:779
from_type alphabet() const
Definition word-range.hpp:2531
ToWord()
Default constructor.
Definition word-range.hpp:784
void call_no_checks(word_type &output, From const &input) const
Convert a string to a word_type.
Definition word-range.hpp:2543
Class for generating words in a given range and in a particular order.
Definition word-range.hpp:319
static constexpr bool is_finite
Value indicating that the range is finite.
Definition word-range.hpp:421
output_type get() const noexcept
Get the current value.
Definition word-range.hpp:355
word_type const & output_type
The type of the output of a WordRange object.
Definition word-range.hpp:325
auto end() const noexcept
Returns an input iterator pointing one beyond the last word in the range.
Definition word-range.hpp:697
word_type const & last() const noexcept
The current one past the last word in the range.
Definition word-range.hpp:567
WordRange & last(word_type const &lst)
Set one past the last word in the range.
Definition word-range.hpp:551
WordRange(WordRange &&)
Default move constructor.
WordRange & min(size_type val)
Set the first word in the range by length.
Definition word-range.hpp:636
WordRange & max(size_type val)
Set one past the last word in the range by length.
Definition word-range.hpp:656
typename std::vector< word_type >::size_type size_type
Alias for the size type.
Definition word-range.hpp:322
WordRange(WordRange const &)
Default copy constructor.
WordRange & upper_bound(size_type n)
Set an upper bound for the length of a word in the range.
Definition word-range.hpp:606
word_type const & first() const noexcept
The current first word in the range.
Definition word-range.hpp:535
WordRange & order(Order val)
Set the order of the words in the range.
WordRange()
Default constructor.
Definition word-range.hpp:438
WordRange & operator=(WordRange const &)
Default copy assignment operator.
auto begin() const noexcept
Returns an input iterator pointing to the first word in the range.
Definition word-range.hpp:677
size_type upper_bound() const noexcept
The current upper bound on the length of a word in the range.
Definition word-range.hpp:621
bool valid() const noexcept
Returns whether or not the settings have been changed since the last time either next or get has been...
Definition word-range.hpp:722
Order order() const noexcept
The current order of the words in the range.
Definition word-range.hpp:591
void next() noexcept
Advance to the next value.
Definition word-range.hpp:369
static constexpr bool is_idempotent
Definition word-range.hpp:426
WordRange & alphabet_size(size_type n) noexcept
Set the number of letters in the alphabet.
Definition word-range.hpp:488
size_t size_hint() const noexcept
The possible size of the range.
Definition word-range.hpp:399
size_type alphabet_size() const noexcept
The current number of letters in the alphabet.
Definition word-range.hpp:502
size_t count() const noexcept
The actual size of the range.
bool at_end() const noexcept
Check if the range object is exhausted.
Definition word-range.hpp:384
WordRange & first(word_type const &frst)
Set the first word in the range.
Definition word-range.hpp:519
WordRange & init()
Initialize an existing WordRange object.
WordRange & operator=(WordRange &&)
Default move assignment operator.
Class for converting strings to word_type with specified alphabet.
Definition word-range.hpp:772
void operator()(word_type &output, From const &input) const
Convert a string to a word_type.
Definition word-range.hpp:2564
ToWord & init()
Initialize an existing ToWord object.
Definition word-range.hpp:824
bool can_convert_letter(typename from_type::value_type const &c) const
Definition word-range.hpp:898
From from_type
The type of values an instance of ToWord will convert into word_type.
Definition word-range.hpp:779
constexpr auto operator()(InputRange &&input) const
Call operator for combining with other range objects.
Definition word-range.hpp:1063
bool empty() const noexcept
Check if the alphabet is defined.
Definition word-range.hpp:865
word_type operator()(From const &input) const
Convert a string to a word_type.
Definition word-range.hpp:985
ToWord & operator=(ToWord const &)
Default copy assignment.
letter_type call_no_checks(typename From::value_type input) const
Convert a char to a letter_type.
Definition word-range.hpp:1035
ToWord & operator=(ToWord &&)
Default move assignment.
from_type alphabet() const
Return the alphabet used for conversion.
Definition word-range.hpp:2531
ToWord(ToWord &&)
Default move constructor.
ToWord(From const &alphabet)
Construct with given alphabet.
Definition word-range.hpp:837
ToWord()
Default constructor.
Definition word-range.hpp:784
letter_type operator()(typename From::value_type input) const
Convert a char to a letter_type.
Definition word-range.hpp:1008
word_type call_no_checks(From const &input) const
Convert a string to a word_type.
Definition word-range.hpp:942
void call_no_checks(word_type &output, From const &input) const
Convert a string to a word_type.
Definition word-range.hpp:2543
ToWord(ToWord const &)
Default copy constructor.
T clear(T... args)
T forward(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.
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:99
std::vector< letter_type > word_type
Type for a word over the generators of a semigroup.
Definition types.hpp:99
size_t letter_type
Type for the index of a generator of a semigroup.
Definition types.hpp:96
Order
The possible orderings of words and strings.
Definition order.hpp:54
std::string to_human_readable_repr(WordGraph< Node > const &wg)
Return a human readable representation of a WordGraph object.
detail::const_wislo_iterator cend_wislo(size_t n, word_type &&first, word_type &&last)
Returns a forward iterator pointing to one after the end of the range from first to last.
std::string random_string(std::string const &alphabet, size_t length)
Returns a random string.
detail::const_wilo_iterator cbegin_wilo(size_t n, size_t upper_bound, word_type &&first, word_type &&last)
Returns a forward iterator pointing to the 3rd parameter first.
Word & reverse(Word &&w)
Reverse an object.
Definition word-range.hpp:70
detail::const_wislo_iterator cbegin_wislo(size_t n, word_type &&first, word_type &&last)
Returns a forward iterator pointing to the 2nd parameter first.
auto random_strings(std::string const &alphabet, size_t number, size_t min, size_t max)
Returns a range object of random strings.
Definition word-range.hpp:1562
detail::const_wilo_iterator cend_wilo(size_t n, size_t upper_bound, word_type &&first, word_type &&last)
Returns a forward iterator pointing to one after the end of the range from first to last.
uint64_t number_of_words(size_t n, size_t min, size_t max)
Returns the number of words over an alphabet with a given number of letters with length in a specifie...
word_type random_word(size_t length, size_t nr_letters)
Returns a random word.
T insert(T... args)
T max(T... args)
T min(T... args)
T move(T... args)
Namespace containing some custom literals for creating words.
Definition word-range.hpp:2017
Namespace containing some operators for creating words.
Definition word-range.hpp:2100
static void operator+=(word_type &u, word_type const &v)
Concatenate a word with another word in-place.
Definition word-range.hpp:2206
Word pow(Word const &x, size_t n)
Returns the power of a word.
Definition word-range.hpp:2258
void pow_inplace(Word &w, size_t n)
Power a word in-place.
Definition word-range.hpp:2416
Word prod(Container const &elts, int first, int last, int step=1)
Returns a product of letters or words.
Definition word-range.hpp:2439
Word::value_type human_readable_letter(size_t i)
Returns a character by index in human readable order.
Definition word-range.hpp:2136
word_type operator+(word_type const &u, word_type const &w)
Concatenate two words.
letter_type human_readable_index(char c)
Returns the index of a character in human readable order.
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
T next(T... args)
T push_back(T... args)
T reserve(T... args)
T resize(T... args)
T reverse(T... args)
T swap(T... args)
T transform(T... args)