21namespace sequoia::maths
29 enum class disconnected_discovery_mode { on, off };
31 enum class traversal_flavour { breadth_first, depth_first, pseudo_depth_first, priority };
33 template<traversal_flavour F>
42 constexpr depth_first_search_type depth_first{};
43 constexpr pseudo_depth_first_search_type pseudo_depth_first{};
44 constexpr priority_first_search_type priority_first{};
52 : m_Index{startingIndex}
56 constexpr std::size_t starting_index()
const noexcept
67 std::size_t m_Index{};
70 template<disconnected_discovery_mode FindDisconnected>
74 constexpr static disconnected_discovery_mode mode{FindDisconnected};
76 using traversal_conditions_base::traversal_conditions_base;
81 template<
class Bitset>
83 constexpr std::size_t compute_restart_index(
const Bitset& b)
87 while(b.size() && b[m_Restart]) ++m_Restart;
92 return starting_index();
95 template<
class Bitset>
96 constexpr void register_discovered(Bitset& b,
const std::size_t index)
103 constexpr bool terminate(
const std::size_t order)
const noexcept
105 return m_NumDiscovered == order;
108 std::size_t m_NumDiscovered{}, m_Restart{};
115 constexpr static disconnected_discovery_mode mode{disconnected_discovery_mode::off};
117 using traversal_conditions_base::traversal_conditions_base;
122 template<
class Bitset>
123 constexpr std::size_t compute_restart_index(
const Bitset&)
const noexcept
125 return starting_index();
129 constexpr bool terminate(std::size_t)
const noexcept
134 template<
class Bitset>
135 constexpr void register_discovered(Bitset& b,
const std::size_t index)
145 template<
class ConcurrencyModel>
149 using model_type = ConcurrencyModel;
150 using return_type =
typename model_type::return_type;
156 template<
class Fn,
class... Args>
157 requires std::invocable<Fn, Args...>&& std::is_convertible_v<std::invoke_result_t<Fn, Args...>, return_type>
158 void push(Fn fn, Args&&... args)
160 m_Futures.emplace_back(m_Model->push(std::move(fn), std::forward<Args>(args)...));
164 std::vector<std::future<return_type>> extract_results()
noexcept(
noexcept(std::is_nothrow_move_constructible_v<return_type>)) {
return std::move(m_Futures); }
166 std::vector<std::future<return_type>> m_Futures;
167 ConcurrencyModel* m_Model;
174 using return_type = void;
178 template<
class Fn,
class... Args>
179 requires std::invocable<Fn, Args...>
180 constexpr void push(Fn&& fn, Args&&... args)
185 constexpr void extract_results()
const noexcept {}
192 using return_type = R;
196 template<
class Fn,
class... Args>
197 requires std::invocable<Fn, Args...>&& std::is_convertible_v<std::invoke_result_t<Fn, Args...>, R>
198 void push(Fn fn, Args&&... args)
204 std::vector<R> extract_results()
noexcept(
noexcept(std::is_nothrow_move_constructible_v<R>)) {
return std::move(m_Results); }
206 std::vector<R> m_Results;
210namespace sequoia::maths::graph_impl
216 constexpr static auto begin(
const G& graph,
const typename G::edge_index_type nodeIndex) {
return graph.cbegin_edges(nodeIndex); }
220 constexpr static auto end(
const G& graph,
const typename G::edge_index_type nodeIndex) {
return graph.cend_edges(nodeIndex); }
227 constexpr static auto begin(
const G& graph,
const typename G::edge_index_type nodeIndex) {
return graph.crbegin_edges(nodeIndex); }
231 constexpr static auto end(
const G& graph,
const typename G::edge_index_type nodeIndex) {
return graph.crend_edges(nodeIndex); }
235 template<
network G, traversal_flavour F,
class... QArgs>
238 template<
network G, traversal_flavour F,
class... QArgs>
242 using edge_index_type =
typename G::edge_index_type;
245 constexpr static queue_type make(QArgs... args)
247 return queue_type{std::forward<QArgs>(args)...};
251 constexpr static auto begin(
const G& graph,
const edge_index_type nodeIndex)
257 constexpr static auto end(
const G& graph,
const edge_index_type nodeIndex)
265 template<network G,
class Compare>
269 using compare_type = Compare;
275 constexpr bool operator()(
const std::size_t index1,
const std::size_t index2)
277 return Compare{}(*(m_Graph.cbegin_node_weights() + index1), *(m_Graph.cbegin_node_weights() + index2));
283 template<network G, graph_flavour GraphFlavour=G::flavour>
287 template<std::forward_iterator Iter>
289 constexpr static bool loop_matched(Iter begin, Iter current)
291 for(
auto i{begin}; i != current; ++i)
293 if(&(*i) == &(*current))
return true;
300 template<network G, graph_flavour GraphFlavour>
301 requires requires() {
302 std::declval<typename G::edge_type>().complementary_index();
307 template<std::forward_iterator Iter>
309 constexpr static bool loop_matched(Iter begin, Iter current)
311 using index_type =
typename G::edge_index_type;
312 const auto dist{
static_cast<index_type
>(std::ranges::distance(begin, current))};
313 return (current->complementary_index() < dist);
323 constexpr bool loop_matched(Iter, Iter)
noexcept
325 m_Matched = !m_Matched;
329 bool m_Matched{
true};
336 using edge_index_type =
typename G::edge_index_type;
337 using const_edge_iterator =
typename G::const_edge_iterator;
342 disconnected_discovery_mode FindDisconnected,
347 class TaskProcessingModel,
350 requires (std::invocable<NBEF, edge_index_type> )
351 && (std::invocable<NAEF, edge_index_type> )
352 && (std::invocable<EFTF, const_edge_iterator>)
353 && (std::invocable<ESTF, const_edge_iterator>)
357 NBEF&& nodeBeforeEdgesFn,
358 NAEF&& nodeAfterEdgesFn,
359 EFTF&& edgeFirstTraversalFn,
360 ESTF&& edgeSecondTraversalFn,
361 TaskProcessingModel&& taskProcessingModel,
368 constexpr bool hasEdgeSecondFn{!std::same_as<std::remove_cvref_t<ESTF>,
null_func_obj>};
369 static_assert(!is_directed(G::flavour) || !hasEdgeSecondFn,
370 "For a directed graph, edges are traversed only once: the edgeSecondTraversalFn is ignored and so should be the null_func_obj");
373 if(conditions.starting_index() < graph.order())
382 const auto restartNode{
static_cast<edge_index_type
>(conditions.compute_restart_index(discovered))};
384 nodeIndexQueue.push(restartNode);
385 conditions.register_discovered(discovered, restartNode);
387 while(!nodeIndexQueue.empty())
390 nodeIndexQueue.pop();
392 auto onDiscovery{[&nodeIndexQueue](
const edge_index_type nextNode) { nodeIndexQueue.push(nextNode); }};
404 edgeFirstTraversalFn,
405 edgeSecondTraversalFn,
408 }
while(!conditions.terminate(graph.order()));
411 return resultsAccumulator.extract_results();
416 disconnected_discovery_mode FindDisconnected,
420 class TaskProcessingModel
422 requires (std::invocable<NBEF, edge_index_type>)
423 && (std::invocable<NAEF, edge_index_type>)
424 && (std::invocable<ETUN, typename G::const_edge_iterator>)
428 NBEF&& nodeBeforeEdgesFn,
429 NAEF&& nodeAfterEdgesFn,
430 ETUN&& edgeToUndiscoveredNodeFn,
431 TaskProcessingModel&& taskProcessingModel)
438 if(conditions.starting_index() < graph.order())
445 const auto restartNode{
static_cast<edge_index_type
>(conditions.compute_restart_index(discovered))};
446 conditions.register_discovered(discovered, restartNode);
451 graph.cbegin_edges(restartNode),
452 graph.cend_edges(restartNode),
458 edgeToUndiscoveredNodeFn,
462 }
while(!conditions.terminate(graph.order()));
465 return resultsAccumulator.extract_results();
470 template<std::input_or_output_iterator Iter>
472 constexpr static bool is_loop(Iter iter, [[maybe_unused]]
const edge_index_type currentNodeIndex)
474 return iter->target_node() == currentNodeIndex;
479 disconnected_discovery_mode FindDisconnected,
487 class TaskProcessingModel
489 requires (std::invocable<NBEF, edge_index_type>)
490 && (std::invocable<NAEF, edge_index_type>)
491 && (std::invocable<EFTF, const_edge_iterator>)
492 && (std::invocable<ESTF, const_edge_iterator>)
493 && (std::invocable<OnDiscovery, edge_index_type> || std::same_as<OnDiscovery, recurse>)
494 constexpr void inner_loop([[maybe_unused]]
const G& graph,
495 const edge_index_type nodeIndex,
501 OnDiscovery onDiscovery,
502 NBEF&& nodeBeforeEdgesFn,
503 NAEF&& nodeAfterEdgesFn,
504 EFTF&& edgeFirstTraversalFn,
505 ESTF&& edgeSecondTraversalFn,
508 constexpr bool hasNodeBeforeFn{!std::same_as<std::remove_cvref_t<NBEF>,
null_func_obj>};
509 if constexpr(hasNodeBeforeFn)
511 resultsAccumulator.push(nodeBeforeEdgesFn, nodeIndex);
515 for(
auto iter{begin}; iter != end; ++iter)
517 const auto nextNode{iter->target_node()};
518 constexpr bool hasEdgeFirstFn{!std::same_as<std::remove_cvref_t<EFTF>,
null_func_obj>};
519 constexpr bool isDFS{std::same_as<OnDiscovery, recurse>};
523 if constexpr(hasEdgeFirstFn)
525 if(!discovered[nextNode]) resultsAccumulator.push(edgeFirstTraversalFn, iter);
528 else if constexpr(G::flavour != graph_flavour::directed)
530 constexpr bool hasEdgeSecondFn{!std::same_as<std::remove_cvref_t<ESTF>,
null_func_obj>};
531 if constexpr(hasEdgeFirstFn || hasEdgeSecondFn)
533 const bool loopMatched{is_loop(iter, nodeIndex) && loops.loop_matched(begin, iter)};
534 const bool secondTraversal{processed[nextNode] || loopMatched};
537 if constexpr(hasEdgeSecondFn)
539 resultsAccumulator.push(edgeSecondTraversalFn, iter);
544 if constexpr(hasEdgeFirstFn)
546 resultsAccumulator.push(edgeFirstTraversalFn, iter);
551 else if constexpr(hasEdgeFirstFn)
553 resultsAccumulator.push(edgeFirstTraversalFn, iter);
556 if(!discovered[nextNode])
558 conditions.register_discovered(discovered, nextNode);
559 if constexpr(std::same_as<OnDiscovery, recurse>)
564 graph.cbegin_edges(nextNode),
565 graph.cend_edges(nextNode),
571 edgeFirstTraversalFn,
572 edgeSecondTraversalFn,
577 onDiscovery(nextNode);
582 if constexpr(!std::same_as<std::remove_cvref_t<NAEF>,
null_func_obj>)
584 resultsAccumulator.push(nodeAfterEdgesFn, nodeIndex);
587 processed[nodeIndex] =
true;
Classes with a queue-like behaviour to which tasks can be pushed and results recovered,...
Meta-programming elements for graph implementation.
Traits and Concepts for graphs.
Tasks may be pushed, upon which they are immediately invoked.
Definition: ConcurrencyModels.hpp:150
Definition: GraphTraversalDetails.hpp:285
Definition: GraphTraversalDetails.hpp:267
Definition: GraphTraversalDetails.hpp:334
Definition: GraphTraversalDetails.hpp:147
Definition: GraphTraversalDetails.hpp:113
Definition: GraphTraversalDetails.hpp:47
Definition: GraphTraversalDetails.hpp:72
Definition: GraphTraits.hpp:18
Definition: GraphTraversalDetails.hpp:213
Definition: GraphTraversalDetails.hpp:263
Definition: GraphTraversalDetails.hpp:236
Definition: GraphTraversalDetails.hpp:240
Definition: GraphTraversalDetails.hpp:24
Definition: GraphTraversalDetails.hpp:34