libsemigroups  v3.0.3
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-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 related to iterating through paths in an
20// WordGraph.
21
22// TODO(2) check code coverage
23
24#ifndef LIBSEMIGROUPS_PATHS_HPP_
25#define LIBSEMIGROUPS_PATHS_HPP_
26
27#include <algorithm> // for any_of, for_each, max_element
28#include <cstddef> // for size_t, ptrdiff_t
29#include <cstdint> // for uint64_t
30#include <iterator> // for distance, forward_iterator_tag
31#include <numeric> // for accumulate
32#include <string> // for std::string
33#include <type_traits> // for true_type
34#include <variant> // for visit, variant
35#include <vector> // for vector, allocator
36
37#include "config.hpp" // for LIBSEMIGROUPS_EIGEN_ENA...
38#include "constants.hpp" // for Max, UNDEFINED, Positive...
39#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
40#include "exception.hpp" // for LIBSEMIGROUPS_EXCEPTION
41#include "order.hpp" // for order
42#include "ranges.hpp" // for is_input_range
43#include "types.hpp" // for word_type
44#include "word-graph.hpp" // for WordGraph
45#include "word-range.hpp" // for number_of_words
46
47#include "detail/containers.hpp" // for DynamicArray2
48#include "detail/path-iterators.hpp" // for default_postfix_increment
49
50namespace libsemigroups {
56 namespace paths {
71 } // namespace paths
72
117 // not noexcept because constructors of const_pilo_iterator aren't
118 template <typename Node1, typename Node2>
119 [[nodiscard]] auto cbegin_pilo(WordGraph<Node1> const& wg,
120 Node2 source,
121 size_t min = 0,
122 size_t max = POSITIVE_INFINITY) {
123 word_graph::throw_if_node_out_of_bounds(wg, static_cast<Node1>(source));
124 return detail::const_pilo_iterator<Node1>(&wg, source, min, max);
125 }
126
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 return detail::const_pilo_iterator<Node>(&wg, 0, 0, 0);
141 }
142
187 // TODO(2) example and what is the complexity?
188 // not noexcept because detail::const_pislo_iterator constructors aren't
189 template <typename Node1, typename Node2>
190 [[nodiscard]] auto cbegin_pislo(WordGraph<Node1> const& wg,
191 Node2 source,
192 size_t min = 0,
193 size_t max = POSITIVE_INFINITY) {
194 word_graph::throw_if_node_out_of_bounds(wg, static_cast<Node1>(source));
195 return detail::const_pislo_iterator<Node1>(&wg, source, min, max);
196 }
197
208 // not noexcept because detail::const_pislo_iterator constructors aren't
209 template <typename Node>
210 [[nodiscard]] auto cend_pislo(WordGraph<Node> const& wg) {
211 return detail::const_pislo_iterator<Node>(&wg, UNDEFINED, 0, 0);
212 }
213
254 // not noexcept because detail::const_pstilo_iterator constructors aren't
255 template <typename Node1, typename Node2>
256 [[nodiscard]] auto cbegin_pstilo(WordGraph<Node1> const& wg,
257 Node2 source,
258 Node2 target,
259 size_t min = 0,
260 size_t max = POSITIVE_INFINITY) {
261 // source & target are validated in is_reachable.
263 return cend_pstilo(wg);
264 }
265 return detail::const_pstilo_iterator<Node1>(&wg, source, target, min, max);
266 }
267
278 // not noexcept because detail::const_pstilo_iterator constructors aren't
279 template <typename Node>
280 [[nodiscard]] auto cend_pstilo(WordGraph<Node> const& wg) {
281 return detail::const_pstilo_iterator<Node>(&wg, 0, 0, 0, 0);
282 }
283
326 // not noexcept because cbegin_pislo isn't
327 template <typename Node1, typename Node2>
328 [[nodiscard]] auto cbegin_pstislo(WordGraph<Node1> const& wg,
329 Node2 source,
330 Node2 target,
331 size_t min = 0,
332 size_t max = POSITIVE_INFINITY) {
333 // source & target are validated in is_reachable.
335 return cend_pstislo(wg);
336 }
337 return detail::const_pstislo_iterator<Node1>(&wg, source, target, min, max);
338 }
339
352 // not noexcept because cend_pislo isn't
353 template <typename Node>
354 [[nodiscard]] auto cend_pstislo(WordGraph<Node> const& wg) {
355 return detail::const_pstislo_iterator<Node>(
356 &wg, UNDEFINED, UNDEFINED, 0, 0);
357 }
358
372 template <typename Node1, typename Node2>
373 [[nodiscard]] paths::algorithm
375 (void) wg;
376 (void) source;
378 }
379
401 template <typename Node1, typename Node2>
402 [[nodiscard]] uint64_t number_of_paths(WordGraph<Node1> const& wg,
403 Node2 source);
404
425 // Not noexcept because word_graph::topological_sort is not.
426 template <typename Node1, typename Node2>
427 [[nodiscard]] paths::algorithm
429 Node2 source,
430 size_t min,
431 size_t max);
432
480 // not noexcept for example detail::number_of_paths_trivial can throw
481 template <typename Node1, typename Node2>
482 [[nodiscard]] uint64_t number_of_paths(WordGraph<Node1> const& wg,
483 Node2 source,
484 size_t min,
485 size_t max,
486 paths::algorithm lgrthm
488
511 // Not noexcept because word_graph::topological_sort isn't
512 template <typename Node1, typename Node2>
513 [[nodiscard]] paths::algorithm
515 Node2 source,
516 Node2 target,
517 size_t min,
518 size_t max);
519
564 // not noexcept because cbegin_pstilo isn't
565 template <typename Node1, typename Node2>
566 [[nodiscard]] uint64_t number_of_paths(WordGraph<Node1> const& wg,
567 Node2 source,
568 Node2 target,
569 size_t min,
570 size_t max,
571 paths::algorithm lgrthm
573
612 template <typename Node>
613 class Paths {
614 public:
620 using node_type = Node;
621
626
630 using output_type = word_type const&;
631
632 private:
633 using const_iterator = std::variant<detail::const_pstislo_iterator<Node>,
634 detail::const_pstilo_iterator<Node>,
635 detail::const_pislo_iterator<Node>,
636 detail::const_pilo_iterator<Node>>;
637
638 WordGraph<node_type> const* _word_graph;
639 Order _order;
640 size_type _max;
641 size_type _min;
642 mutable size_type _position;
643 node_type _source;
644 node_type _target;
645 mutable const_iterator _current;
646 mutable const_iterator _end;
647 mutable bool _current_valid;
648
649 bool set_iterator_no_checks() const;
650
651 // The following init function is private to avoid the case of constructing
652 // a Paths object without setting _word_graph. The subsequent default
653 // constructor is protected and still needed (instead of deleting it) to
654 // avoid problems with having uninitialised std::variants with copy
655 // constructors.
656
657 Paths& init();
658
659 protected:
660 Paths() = default;
661
662 public:
664 // Constructors + initialization
666
670 Paths(Paths const&);
671
675 Paths(Paths&&);
676
680 Paths& operator=(Paths const&);
681
685 Paths& operator=(Paths&&);
686
687 ~Paths();
688
701 explicit Paths(WordGraph<Node> const& wg) : Paths() {
702 init(wg);
703 }
704
721 Paths& init(WordGraph<Node> const& wg) {
722 init();
723 _word_graph = &wg;
724 return *this;
725 }
726
728 // Validation
730
737
739 // Functions + members required by rx::ranges
741
750 output_type get() const {
751 set_iterator_no_checks();
752 return std::visit(
753 [](auto& it) -> auto const& { return *it; }, _current);
754 }
755
763 void next() {
764 if (!at_end()) {
765 ++_position;
766 std::visit([](auto& it) { ++it; }, _current);
767 }
768 }
769
779 [[nodiscard]] bool at_end() const {
780 if (!set_iterator_no_checks()) {
781 return true;
782 }
783 return _current == _end;
784 }
785
798 [[nodiscard]] uint64_t size_hint() const;
799
812 [[nodiscard]] uint64_t count() const {
813 return size_hint();
814 }
815
816 static constexpr bool is_finite = true; // this isn't always true!
817 static constexpr bool is_idempotent = true;
818
820 // Settings
822
843 Paths& source_no_checks(node_type n) noexcept {
844 return source_no_checks(this, n);
845 }
846
868
878 [[nodiscard]] node_type source() const noexcept {
879 return _source;
880 }
881
902 Paths& target_no_checks(node_type n) noexcept {
903 return target_no_checks(this, n);
904 }
905
923 Paths& target(node_type n) {
924 if (n != UNDEFINED) {
926 }
927 return target_no_checks(n);
928 }
929
939 [[nodiscard]] node_type target() const noexcept {
940 return _target;
941 }
942
955 [[nodiscard]] node_type current_target() const;
956
969 Paths& min(size_type val) noexcept {
970 return min(this, val);
971 }
972
982 [[nodiscard]] size_type min() const noexcept {
983 return _min;
984 }
985
998 Paths& max(size_type val) noexcept {
999 return max(this, val);
1000 }
1001
1011 [[nodiscard]] size_type max() const noexcept {
1012 return _max;
1013 }
1014
1026 Paths& order(Order val) {
1027 return order(this, val);
1028 }
1029
1039 [[nodiscard]] Order order() const noexcept {
1040 return _order;
1041 }
1042
1052 [[nodiscard]] WordGraph<Node> const& word_graph() const noexcept {
1053 return *_word_graph;
1054 }
1055
1056 protected:
1057 template <typename Subclass>
1058 Subclass& source_no_checks(Subclass* obj, node_type src) {
1059 _current_valid &= (src == _source);
1060 _source = src;
1061 return *obj;
1062 }
1063
1064 template <typename Subclass>
1065 Subclass& target_no_checks(Subclass* obj, node_type trgt) noexcept {
1066 _current_valid &= (trgt == _target);
1067 _target = trgt;
1068 return *obj;
1069 }
1070
1071 template <typename Subclass>
1072 Subclass& min(Subclass* obj, size_type min) noexcept {
1073 _current_valid &= (min == _min);
1074 _min = min;
1075 return *obj;
1076 }
1077
1078 template <typename Subclass>
1079 Subclass& max(Subclass* obj, size_type max) noexcept {
1080 _current_valid &= (max == _max);
1081 _max = max;
1082 return *obj;
1083 }
1084
1085 template <typename Subclass>
1086 Subclass& order(Subclass* obj, Order val);
1087 }; // class Paths
1088
1093 template <typename Node>
1094 Paths(WordGraph<Node> const&) -> Paths<Node>;
1095
1100 template <typename Node>
1101 Paths(WordGraph<Node>&&) -> Paths<Node>;
1102
1115 template <typename Node>
1117
1118} // namespace libsemigroups
1119
1120#include "paths.tpp"
1121
1122#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:256
Paths(WordGraph< Node > &&) -> Paths< Node >
void next()
Advance to the next path in the range.
Definition paths.hpp:763
typename WordGraph< uint32_t >::size_type size_type
Definition paths.hpp:625
uint32_t node_type
Definition paths.hpp:620
size_type min() const noexcept
Get the minimum length of path in the range.
Definition paths.hpp:982
word_type const & output_type
Definition paths.hpp:630
Paths(WordGraph< Node > const &) -> Paths< Node >
auto cend_pstilo(WordGraph< Node > const &wg)
Definition paths.hpp:280
Paths(Paths const &)
Default copy constructor.
WordGraph< Node > const & word_graph() const noexcept
The underlying WordGraph.
Definition paths.hpp:1052
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:969
paths::algorithm number_of_paths_algorithm(WordGraph< Node1 > const &wg, Node2 source) noexcept
Definition paths.hpp:374
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:701
auto cbegin_pislo(WordGraph< Node1 > const &wg, Node2 source, size_t min=0, size_t max=POSITIVE_INFINITY)
Definition paths.hpp:190
auto cend_pstislo(WordGraph< Node > const &wg)
Definition paths.hpp:354
Paths & max(size_type val) noexcept
Definition paths.hpp:998
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:878
uint64_t number_of_paths(WordGraph< Node1 > const &wg, Node2 source)
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:1011
bool at_end() const
Check if the range is exhausted.
Definition paths.hpp:779
Paths & source(node_type n)
Definition paths.hpp:864
void throw_if_source_undefined() const
Throw an exception if the source node has not been defined (using source).
Paths & operator=(Paths &&)
Default move assignment operator.
uint64_t number_of_paths(WordGraph< Node1 > const &wg, Node2 source, size_t min, size_t max, paths::algorithm lgrthm=paths::algorithm::automatic)
output_type get() const
Get the current path in the range.
Definition paths.hpp:750
Paths & target_no_checks(node_type n) noexcept
Set the target node of every path in the range.
Definition paths.hpp:902
uint64_t count() const
Get the size of the range.
Definition paths.hpp:812
node_type target() const noexcept
Get the current target node of every path in the range.
Definition paths.hpp:939
paths::algorithm number_of_paths_algorithm(WordGraph< Node1 > const &wg, Node2 source, size_t min, size_t max)
Order order() const noexcept
Get the order of the paths in the range.
Definition paths.hpp:1039
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:119
Paths & target(node_type n)
Definition paths.hpp:923
paths::algorithm number_of_paths_algorithm(WordGraph< Node1 > const &wg, Node2 source, Node2 target, size_t min, size_t max)
auto cend_pislo(WordGraph< Node > const &wg)
Definition paths.hpp:210
auto cbegin_pstislo(WordGraph< Node1 > const &wg, Node2 source, Node2 target, size_t min=0, size_t max=POSITIVE_INFINITY)
Definition paths.hpp:328
uint64_t number_of_paths(WordGraph< Node1 > const &wg, Node2 source, Node2 target, size_t min, size_t max, paths::algorithm lgrthm=paths::algorithm::automatic)
Paths & order(Order val)
Set the order of the paths in the range.
Definition paths.hpp:1026
uint64_t size_hint() const
Get the size of the range.
Paths & init(WordGraph< Node > const &wg)
Reinitialize a Paths object.
Definition paths.hpp:721
Paths & source_no_checks(node_type n) noexcept
Set the source node of every path in the range.
Definition paths.hpp:843
Class for representing word graphs.
Definition word-graph.hpp:82
std::size_t size_type
Unsigned integer type.
Definition word-graph.hpp:104
Undefined const UNDEFINED
Value for something undefined.
PositiveInfinity const POSITIVE_INFINITY
Value for positive infinity.
Order
The possible orderings of words and strings.
Definition order.hpp:48
std::vector< letter_type > word_type
Type for a word over the generators of a semigroup.
Definition types.hpp:101
Namespace containing helper functions for the Paths class.
Definition paths.hpp:56
algorithm
An enum for specifying the algorithm to the functions number_of_paths().
Definition paths.hpp:58
@ trivial
Try to utilise some corner cases.
Definition paths.hpp:66
@ matrix
Use the adjacency matrix and matrix multiplication.
Definition paths.hpp:62
@ automatic
Definition paths.hpp:69
@ dfs
Use a depth-first-search.
Definition paths.hpp:60
@ acyclic
Use a dynamic programming approach for acyclic word graphs.
Definition paths.hpp:64
void throw_if_node_out_of_bounds(WordGraph< Node1 > const &wg, Node2 n)
Throws if a node is out of bounds.
bool is_reachable(WordGraph< Node1 > const &wg, Node2 source, Node2 target)
Check if there is a path from one node to another.
Namespace for everything in the libsemigroups library.
Definition action.hpp:44