Sequoia
Loading...
Searching...
No Matches
StateTransitionUtilities.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2021. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
18
19namespace sequoia::testing
20{
21 enum class check_ordering : bool {no, yes};
22
23 template<class T, invocable_r<T, const T&> TransitionFn>
25 {
26 std::string description;
27 TransitionFn fn;
28 };
29
30 template<class T, invocable_r<T, const T&> TransitionFn, check_ordering=check_ordering{std::totally_ordered<T>}>
31 struct transition_info : transition_info_base<T, TransitionFn>
32 {};
33
34 template<std::totally_ordered T, invocable_r<T, const T&> TransitionFn>
35 struct transition_info<T, TransitionFn, check_ordering::yes> : transition_info_base<T, TransitionFn>
36 {
37 std::weak_ordering ordering;
38 };
39
40 template<class T>
42 {
43 public:
44 template<std::invocable Fn>
45 requires std::convertible_to<std::invoke_result_t<Fn>, T>
46 object_generator(Fn f) : m_Fn{std::move(f)}
47 {}
48
50 requires std::movable<T>
51 : m_Fn{[t{std::move(t)}]() -> const T& { return t; }}
52 {}
53
54 template<class... Args>
55 requires (initializable_from<T, Args...> &&
56 ((sizeof...(Args) != 1) || (!std::is_same_v<T, std::remove_cvref_t<Args>> && ...)))
57 object_generator(Args&&... args)
58 : object_generator{T{std::forward<Args>(args)...}}
59 {}
60
61 template<class InitCheckFn, class... Args>
62 requires (initializable_from<T, Args...> && std::invocable<InitCheckFn, std::string, T, Args...>)
63 object_generator(std::string_view message, InitCheckFn initCheckFn, const Args&... args)
64 : object_generator{T{args...}}
65 {
66 initCheckFn(message, m_Fn(), args...);
67 }
68
69 [[nodiscard]]
70 decltype(auto) operator()() const { return m_Fn(); }
71 private:
72 std::function<T()> m_Fn;
73 };
74
75 template<class T, check_ordering CheckOrdering=check_ordering{std::totally_ordered<T>}>
77 {
78 public:
80 = maths::directed_graph<transition_info<T, std::function<T(const T&)>, CheckOrdering>, object_generator<T>>;
81
82 using size_type = typename transition_graph::size_type;
83
84 private:
85 using edge_iterator = typename transition_graph::const_edge_iterator;
86
87 template<class CheckFn, class... Args>
88 static void invoke_check_fn(const transition_graph& g, edge_iterator i, CheckFn fn, const std::string& message, object_generator<T> parentGenerator, size_type target, Args... args)
89 {
90 const auto& w{i->weight()};
91 fn(message,
92 w.fn(parentGenerator()),
93 g.cbegin_node_weights()[target](),
94 std::move(args)...);
95 }
96
97 template<class CheckFn, class... Args>
98 static void invoke_check_fn(std::string_view description, const transition_graph& g, edge_iterator i, CheckFn fn, Args... args)
99 {
100 const auto [message, parentGenerator, target] {make(description, g, i)};
101 const auto& w{i->weight()};
102 fn(message,
103 [&w,pg{parentGenerator}]() { return w.fn(pg()); },
104 g.cbegin_node_weights()[target],
105 parentGenerator,
106 std::move(args)...);
107 }
108 public:
109 using edge = typename transition_graph::edge_type;
110
111 template<std::invocable<std::string, T, T> CheckFn>
112 static void check(std::string_view description, const transition_graph& g, CheckFn checkFn)
113 {
114 auto edgeFn{
115 [description,&g,checkFn](edge_iterator i) {
116 const auto [message, parentGenerator, target] {make(description, g, i)};
117 invoke_check_fn(g, i, checkFn, message, parentGenerator, target);
118 }
119 };
120
121 check(g, edgeFn);
122 }
123
124 template<std::invocable<std::string, T, T, T> CheckFn>
125 static void check(std::string_view description, const transition_graph& g, CheckFn checkFn)
126 {
127 auto edgeFn{
128 [description,&g,checkFn](edge_iterator i) {
129 const auto [message, parentGenerator, target] {make(description, g, i)};
130 invoke_check_fn(g, i, checkFn, message, parentGenerator, target, parentGenerator());
131 }
132 };
133
134 check(g, edgeFn);
135 }
136
137 template<std::invocable<std::string, T, T, T, size_type, size_type> CheckFn>
138 static void check(std::string_view description, const transition_graph& g, CheckFn checkFn)
139 {
140 auto edgeFn{
141 [description,&g,checkFn](edge_iterator i) {
142 const auto [message, parentGenerator, target] {make(description, g, i)};
143 invoke_check_fn(g, i, checkFn, message, parentGenerator, target, parentGenerator(), i.partition_index(), target);
144 }
145 };
146
147 check(g, edgeFn);
148 }
149
150 template<std::invocable<std::string, T, T, T, std::weak_ordering> CheckFn>
151 requires (std::totally_ordered<T>&& pseudoregular<T>)
152 static void check(std::string_view description, const transition_graph& g, CheckFn checkFn)
153 {
154 auto edgeFn{
155 [description,&g,checkFn](edge_iterator i) {
156 const auto [message, parentGenerator, target] {make(description, g, i)};
157 invoke_check_fn(g, i, checkFn, message, parentGenerator, target, parentGenerator(), i->weight().ordering);
158 }
159 };
160
161 check(g, edgeFn);
162 }
163
164 template<std::invocable<std::string, std::function<T()>, std::function<T()>, std::function<T()>> CheckFn>
165 static void check(std::string_view description, const transition_graph& g, CheckFn checkFn)
166 {
167 auto edgeFn{
168 [description,&g,checkFn](edge_iterator i) { invoke_check_fn(description, g, i, checkFn); }
169 };
170
171 check(g, edgeFn);
172 }
173
174 template<std::invocable<std::string, std::function<T()>, std::function<T()>, std::function<T()>, std::weak_ordering> CheckFn>
175 requires std::totally_ordered<T>
176 static void check(std::string_view description, const transition_graph& g, CheckFn checkFn)
177 {
178 auto edgeFn{
179 [description,&g,checkFn](edge_iterator i) { invoke_check_fn(description, g, i, checkFn, i->weight().ordering); }
180 };
181
182 check(g, edgeFn);
183 }
184
185
186 private:
187 template<std::invocable<edge_iterator> EdgeFn>
188 static void check(const transition_graph& g, EdgeFn edgeFn)
189 {
190 using namespace maths;
191 traverse(breadth_first, g, find_disconnected_t{0}, null_func_obj{}, null_func_obj{}, edgeFn);
192 }
193
194 struct edge_fn_info
195 {
196 std::string message;
197 object_generator<T> parentGenerator;
198 size_type target;
199 };
200
201 [[nodiscard]]
202 static edge_fn_info make(std::string_view description, const transition_graph& g, edge_iterator i)
203 {
204 const auto& w{i->weight()};
205 const auto parent{i.partition_index()}, target{i->target_node()};
206 return {append_lines(description,
207 std::string{"Transition from node "}.append(std::to_string(parent)).append(" to ").append(std::to_string(target)),
208 w.description),
209 g.cbegin_node_weights()[parent],
210 target};
211 }
212 };
213}
Concepts which are sufficiently general to appear in the sequoia namespace.
Edge & Node storage traits, base class and final classes for dynamic graphs.
Breadth first, depth first and priority searches.
A collection of functions for formatting test output.
Definition: DynamicGraph.hpp:303
Definition: GraphTraversalDetails.hpp:72
Definition: StateTransitionUtilities.hpp:42
A concept similar to std::constructible_from, but which considers braced-init.
Definition: Concepts.hpp:75
Similar to std::regular but relaxes the requirement of default initializability.
Definition: Concepts.hpp:39
Definition: GraphTraversalDetails.hpp:24
Definition: StateTransitionUtilities.hpp:77
Definition: StateTransitionUtilities.hpp:25
Definition: StateTransitionUtilities.hpp:32