libsemigroups  v3.6.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
paths.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2023-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 declarations related to iterating through paths in an
20// WordGraph.
21
22// TODO(2):
23// * check code coverage
24// * the function number_of_paths_algorithm and number_of_paths don't match
25// each other in terms of when they throw exceptions.
26
27#ifndef LIBSEMIGROUPS_PATHS_HPP_
28#define LIBSEMIGROUPS_PATHS_HPP_
29
30#include <algorithm> // for any_of, for_each, max_element
31#include <cstddef> // for size_t, ptrdiff_t
32#include <cstdint> // for uint64_t
33#include <iterator> // for distance, forward_iterator_tag
34#include <numeric> // for accumulate
35#include <string> // for std::string
36#include <type_traits> // for true_type
37#include <variant> // for visit, variant
38#include <vector> // for vector, allocator
39
40#include "config.hpp" // for LIBSEMIGROUPS_EIGEN_ENA...
41#include "constants.hpp" // for Max, UNDEFINED, Positive...
42#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
43#include "exception.hpp" // for LIBSEMIGROUPS_EXCEPTION
44#include "order.hpp" // for order
45#include "paths-count.hpp" // for algorithm
46#include "ranges.hpp" // for is_input_range
47#include "types.hpp" // for word_type
48#include "word-graph-helpers.hpp" // for word_graph
49#include "word-graph.hpp" // for WordGraph
50#include "word-range.hpp" // for number_of_words
51
52#include "detail/containers.hpp" // for DynamicArray2
53#include "detail/path-iterators.hpp" // for default_postfix_increment
54
55namespace libsemigroups {
56 // TODO(1): Remove this from the documentation?
62 namespace paths {
64 using algorithm [[deprecated]] = v4::paths::algorithm;
65 } // namespace paths
66
111 // not noexcept because constructors of const_pilo_iterator aren't
112 template <typename Node1, typename Node2>
113 [[nodiscard]] auto cbegin_pilo(WordGraph<Node1> const& wg,
114 Node2 source,
115 size_t min = 0,
116 size_t max = POSITIVE_INFINITY) {
117 word_graph::throw_if_node_out_of_bounds(wg, static_cast<Node1>(source));
118 return detail::const_pilo_iterator<Node1>(&wg, source, min, max);
119 }
120
137 // not noexcept because constructors of const_pilo_iterator aren't
138 template <typename Node>
139 [[nodiscard]] auto cend_pilo(WordGraph<Node> const& wg) {
140 (void) wg;
141 return detail::const_pilo_iterator<Node>();
142 }
143
188 // TODO(2) example and what is the complexity?
189 // not noexcept because detail::const_pislo_iterator constructors aren't
190 template <typename Node1, typename Node2>
191 [[nodiscard]] auto cbegin_pislo(WordGraph<Node1> const& wg,
192 Node2 source,
193 size_t min = 0,
194 size_t max = POSITIVE_INFINITY) {
195 word_graph::throw_if_node_out_of_bounds(wg, static_cast<Node1>(source));
196 return detail::const_pislo_iterator<Node1>(&wg, source, min, max);
197 }
198
216 // not noexcept because detail::const_pislo_iterator constructors aren't
217 template <typename Node>
218 [[nodiscard]] auto cend_pislo(WordGraph<Node> const& wg) {
219 (void) wg;
220 return detail::const_pislo_iterator<Node>();
221 }
222
263 // not noexcept because detail::const_pstilo_iterator constructors aren't
264 template <typename Node1, typename Node2>
265 [[nodiscard]] auto cbegin_pstilo(WordGraph<Node1> const& wg,
266 Node2 source,
267 Node2 target,
268 size_t min = 0,
269 size_t max = POSITIVE_INFINITY) {
270 // source & target are validated in is_reachable.
271 if (!v4::word_graph::is_reachable(wg, source, target)) {
272 return cend_pstilo(wg);
273 }
274 return detail::const_pstilo_iterator<Node1>(&wg, source, target, min, max);
275 }
276
293 // not noexcept because detail::const_pstilo_iterator constructors aren't
294 template <typename Node>
295 [[nodiscard]] auto cend_pstilo(WordGraph<Node> const& wg) {
296 (void) wg;
297 return detail::const_pstilo_iterator<Node>();
298 }
299
342 // not noexcept because cbegin_pislo isn't
343 template <typename Node1, typename Node2>
344 [[nodiscard]] auto cbegin_pstislo(WordGraph<Node1> const& wg,
345 Node2 source,
346 Node2 target,
347 size_t min = 0,
348 size_t max = POSITIVE_INFINITY) {
349 // source & target are validated in is_reachable.
350 if (!v4::word_graph::is_reachable(wg, source, target)) {
351 return cend_pstislo(wg);
352 }
353 return detail::const_pstislo_iterator<Node1>(&wg, source, target, min, max);
354 }
355
374 // not noexcept because cend_pislo isn't
375 template <typename Node>
376 [[nodiscard]] auto cend_pstislo(WordGraph<Node> const& wg) {
377 (void) wg;
378 return detail::const_pstislo_iterator<Node>();
379 }
380
397 template <typename Node1, typename Node2>
398 [[deprecated]] [[nodiscard]] paths::algorithm
400 return v4::paths::count_algorithm(wg, source);
401 }
402
428 template <typename Node1, typename Node2>
429 [[deprecated]] [[nodiscard]] uint64_t
431 return v4::paths::count(wg, source);
432 }
433
457 // Not noexcept because v4::word_graph::topological_sort is not.
458 template <typename Node1, typename Node2>
459 [[deprecated]] [[nodiscard]] paths::algorithm
461 Node2 source,
462 size_t min,
463 size_t max) {
464 return v4::paths::count_algorithm(wg, source, min, max);
465 }
466
513 // not noexcept for example detail::number_of_paths_trivial can throw
514 template <typename Node1, typename Node2>
515 [[deprecated]] [[nodiscard]] uint64_t number_of_paths(
516 WordGraph<Node1> const& wg,
517 Node2 source,
518 size_t min,
519 size_t max,
520 v4::paths::algorithm lgrthm = v4::paths::algorithm::automatic) {
521 return v4::paths::count(wg, source, min, max, lgrthm);
522 }
523
549 // Not noexcept because v4::word_graph::topological_sort isn't
550 template <typename Node1, typename Node2>
551 [[deprecated]] [[nodiscard]] paths::algorithm
553 Node2 source,
554 Node2 target,
555 size_t min,
556 size_t max) {
557 return v4::paths::count_algorithm(wg, source, target, min, max);
558 }
559
607 // not noexcept because cbegin_pstilo isn't
608 template <typename Node1, typename Node2>
609 [[deprecated]] [[nodiscard]] uint64_t number_of_paths(
610 WordGraph<Node1> const& wg,
611 Node2 source,
612 Node2 target,
613 size_t min,
614 size_t max,
615 v4::paths::algorithm lgrthm = v4::paths::algorithm::automatic) {
616 return v4::paths::count(wg, source, target, min, max, lgrthm);
617 }
618
657 template <typename Node>
658 class Paths {
659 public:
665 using node_type = Node;
666
671
675 using output_type = word_type const&;
676
677 private:
678 using const_iterator = std::variant<detail::const_pstislo_iterator<Node>,
679 detail::const_pstilo_iterator<Node>,
680 detail::const_pislo_iterator<Node>,
681 detail::const_pilo_iterator<Node>>;
682
683 WordGraph<node_type> const* _word_graph;
684 Order _order;
685 size_type _max;
686 size_type _min;
687 mutable size_type _position;
688 node_type _source;
689 node_type _target;
690 mutable const_iterator _current;
691 mutable const_iterator _end;
692 mutable bool _current_valid;
693
694 bool set_iterator_no_checks() const;
695
696 // The following init function is private to avoid the case of constructing
697 // a Paths object without setting _word_graph. The subsequent default
698 // constructor is protected and still needed (instead of deleting it) to
699 // avoid problems with having uninitialised std::variants with copy
700 // constructors.
701
702 Paths& init();
703
704 protected:
705 Paths() = default;
706
707 public:
709 // Constructors + initialization
711
715 Paths(Paths const&);
716
720 Paths(Paths&&);
721
725 Paths& operator=(Paths const&);
726
730 Paths& operator=(Paths&&);
731
732 ~Paths();
733
746 explicit Paths(WordGraph<Node> const& wg) : Paths() {
747 init(wg);
748 }
749
766 Paths& init(WordGraph<Node> const& wg) {
767 init();
768 _word_graph = &wg;
769 return *this;
770 }
771
773 // Validation
775
782
784 // Functions + members required by rx::ranges
786
795 output_type get() const {
796 set_iterator_no_checks();
797 return std::visit(
798 [](auto& it) -> auto const& { return *it; }, _current);
799 }
800
808 void next() {
809 if (!at_end()) {
810 ++_position;
811 std::visit([](auto& it) { ++it; }, _current);
812 }
813 }
814
824 [[nodiscard]] bool at_end() const {
825 if (!set_iterator_no_checks()) {
826 return true;
827 }
828 return _current == _end;
829 }
830
843 [[nodiscard]] uint64_t size_hint() const;
844
857 [[nodiscard]] uint64_t count() const {
858 return size_hint();
859 }
860
861 static constexpr bool is_finite = true; // this isn't always true!
862 static constexpr bool is_idempotent = true;
863
865 // Settings
867
888 Paths& source_no_checks(node_type n) noexcept {
889 return source_no_checks(this, n);
890 }
891
913
923 [[nodiscard]] node_type source() const noexcept {
924 return _source;
925 }
926
947 Paths& target_no_checks(node_type n) noexcept {
948 return target_no_checks(this, n);
949 }
950
968 Paths& target(node_type n) {
969 if (n != UNDEFINED) {
971 }
972 return target_no_checks(n);
973 }
974
984 [[nodiscard]] node_type target() const noexcept {
985 return _target;
986 }
987
1000 [[nodiscard]] node_type current_target() const;
1001
1014 Paths& min(size_type val) noexcept {
1015 return min(this, val);
1016 }
1017
1027 [[nodiscard]] size_type min() const noexcept {
1028 return _min;
1029 }
1030
1043 Paths& max(size_type val) noexcept {
1044 return max(this, val);
1045 }
1046
1056 [[nodiscard]] size_type max() const noexcept {
1057 return _max;
1058 }
1059
1071 Paths& order(Order val) {
1072 return order(this, val);
1073 }
1074
1084 [[nodiscard]] Order order() const noexcept {
1085 return _order;
1086 }
1087
1097 [[nodiscard]] WordGraph<Node> const& word_graph() const noexcept {
1098 return *_word_graph;
1099 }
1100
1101 protected:
1102 template <typename Subclass>
1103 Subclass& source_no_checks(Subclass* obj, node_type src) {
1104 _current_valid &= (src == _source);
1105 _source = src;
1106 return *obj;
1107 }
1108
1109 template <typename Subclass>
1110 Subclass& target_no_checks(Subclass* obj, node_type trgt) noexcept {
1111 _current_valid &= (trgt == _target);
1112 _target = trgt;
1113 return *obj;
1114 }
1115
1116 template <typename Subclass>
1117 Subclass& min(Subclass* obj, size_type min) noexcept {
1118 _current_valid &= (min == _min);
1119 _min = min;
1120 return *obj;
1121 }
1122
1123 template <typename Subclass>
1124 Subclass& max(Subclass* obj, size_type max) noexcept {
1125 _current_valid &= (max == _max);
1126 _max = max;
1127 return *obj;
1128 }
1129
1130 template <typename Subclass>
1131 Subclass& order(Subclass* obj, Order val);
1132 }; // class Paths
1133
1138 template <typename Node>
1139 Paths(WordGraph<Node> const&) -> Paths<Node>;
1140
1145 template <typename Node>
1146 Paths(WordGraph<Node>&&) -> Paths<Node>;
1147
1160 template <typename Node>
1162
1163} // namespace libsemigroups
1164
1165#include "paths.tpp"
1166
1167#endif // LIBSEMIGROUPS_PATHS_HPP_
auto cbegin_pstilo(WordGraph< Node1 > const &wg, Node2 source, Node2 target, size_t min=0, size_t max=POSITIVE_INFINITY)
Definition paths.hpp:265
Paths(WordGraph< Node > &&) -> Paths< Node >
void next()
Advance to the next path in the range.
Definition paths.hpp:808
typename WordGraph< uint32_t >::size_type size_type
Definition paths.hpp:670
uint32_t node_type
Definition paths.hpp:665
size_type min() const noexcept
Get the minimum length of path in the range.
Definition paths.hpp:1027
word_type const & output_type
Definition paths.hpp:675
Paths(WordGraph< Node > const &) -> Paths< Node >
auto cend_pstilo(WordGraph< Node > const &wg)
Definition paths.hpp:295
Paths(Paths const &)
Default copy constructor.
WordGraph< Node > const & word_graph() const noexcept
The underlying WordGraph.
Definition paths.hpp:1097
Paths(Paths &&)
Default move constructor.
auto cend_pilo(WordGraph< Node > const &wg)
Definition paths.hpp:139
Paths & min(size_type val) noexcept
Definition paths.hpp:1014
paths::algorithm number_of_paths_algorithm(WordGraph< Node1 > const &wg, Node2 source) noexcept
Definition paths.hpp:399
std::string to_human_readable_repr(Paths< Node > const &p)
Return a human readable representation of a Paths object.
Paths(WordGraph< Node > const &wg)
Construct from a WordGraph.
Definition paths.hpp:746
auto cbegin_pislo(WordGraph< Node1 > const &wg, Node2 source, size_t min=0, size_t max=POSITIVE_INFINITY)
Definition paths.hpp:191
auto cend_pstislo(WordGraph< Node > const &wg)
Definition paths.hpp:376
Paths & max(size_type val) noexcept
Definition paths.hpp:1043
Paths & operator=(Paths const &)
Default copy assignment operator.
node_type source() const noexcept
Get the current source node of every path in the range.
Definition paths.hpp:923
uint64_t number_of_paths(WordGraph< Node1 > const &wg, Node2 source)
Definition paths.hpp:430
node_type current_target() const
Get the current target node of the path labelled by get.
size_type max() const noexcept
Get the maximum length of path in the range.
Definition paths.hpp:1056
bool at_end() const
Check if the range is exhausted.
Definition paths.hpp:824
Paths & source(node_type n)
Definition paths.hpp:909
void throw_if_source_undefined() const
Throw an exception if the source node has not been defined (using source).
uint64_t number_of_paths(WordGraph< Node1 > const &wg, Node2 source, size_t min, size_t max, v4::paths::algorithm lgrthm=v4::paths::algorithm::automatic)
Definition paths.hpp:515
Paths & operator=(Paths &&)
Default move assignment operator.
output_type get() const
Get the current path in the range.
Definition paths.hpp:795
Paths & target_no_checks(node_type n) noexcept
Set the target node of every path in the range.
Definition paths.hpp:947
uint64_t count() const
Get the size of the range.
Definition paths.hpp:857
node_type target() const noexcept
Get the current target node of every path in the range.
Definition paths.hpp:984
paths::algorithm number_of_paths_algorithm(WordGraph< Node1 > const &wg, Node2 source, size_t min, size_t max)
Definition paths.hpp:460
Order order() const noexcept
Get the order of the paths in the range.
Definition paths.hpp:1084
uint64_t number_of_paths(WordGraph< Node1 > const &wg, Node2 source, Node2 target, size_t min, size_t max, v4::paths::algorithm lgrthm=v4::paths::algorithm::automatic)
Definition paths.hpp:609
auto cbegin_pilo(WordGraph< Node1 > const &wg, Node2 source, size_t min=0, size_t max=POSITIVE_INFINITY)
Returns an iterator for pilo (Path And Node In Lex Order).
Definition paths.hpp:113
Paths & target(node_type n)
Definition paths.hpp:968
paths::algorithm number_of_paths_algorithm(WordGraph< Node1 > const &wg, Node2 source, Node2 target, size_t min, size_t max)
Definition paths.hpp:552
auto cend_pislo(WordGraph< Node > const &wg)
Definition paths.hpp:218
auto cbegin_pstislo(WordGraph< Node1 > const &wg, Node2 source, Node2 target, size_t min=0, size_t max=POSITIVE_INFINITY)
Definition paths.hpp:344
Paths & order(Order val)
Set the order of the paths in the range.
Definition paths.hpp:1071
uint64_t size_hint() const
Get the size of the range.
Paths & init(WordGraph< Node > const &wg)
Reinitialize a Paths object.
Definition paths.hpp:766
Paths & source_no_checks(node_type n) noexcept
Set the source node of every path in the range.
Definition paths.hpp:888
Class for representing word graphs.
Definition word-graph.hpp:83
std::size_t size_type
Unsigned integer type.
Definition word-graph.hpp:105
Undefined const UNDEFINED
Value for something undefined.
PositiveInfinity const POSITIVE_INFINITY
Value for positive infinity.
std::vector< letter_type > word_type
Type for a word over the generators of a semigroup.
Definition types.hpp:99
Order
The possible orderings of words and strings.
Definition order.hpp:54
Namespace containing helper functions for the Paths class.
Definition paths.hpp:62
void throw_if_node_out_of_bounds(WordGraph< Node1 > const &wg, Node2 n)
Throws if a node is out of bounds.
Namespace for everything in the libsemigroups library.
Definition action.hpp:44