2#include <ossia/dataflow/bench_map.hpp>
3#include <ossia/dataflow/graph/graph_interface.hpp>
4#include <ossia/dataflow/graph/graph_utils.hpp>
5#include <ossia/dataflow/graph/node_executors.hpp>
6#include <ossia/dataflow/graph/transitive_closure.hpp>
7#include <ossia/detail/flat_map.hpp>
8#include <ossia/editor/scenario/execution_log.hpp>
10#include <boost/circular_buffer.hpp>
11#include <boost/graph/transitive_closure.hpp>
13#include <ossia-config.hpp>
19using filtered_graph_t = std::decay_t<
decltype(boost::filtered_graph(
20 std::declval<graph_t>(), no_delay_edges{
nullptr}))>;
21template <
typename UpdateImpl,
typename TickImpl>
22struct graph_static final
27 UpdateImpl update_fun;
28 TickImpl tick_fun{*
this};
29 std::vector<boost::default_color_type> m_color_map_cache;
30 std::vector<boost::detail::DFSVertexInfo<graph_t, filtered_graph_t>> m_stack_cache;
31 explicit graph_static(
const ossia::graph_setup_options& opt = {})
32 : update_fun{*this, opt}
34#if !defined(OSSIA_FREESTANDING)
35 m_all_nodes.reserve(1024);
36 m_enabled_cache.reserve(1024);
37 m_topo_order_cache.reserve(1024);
38 m_color_map_cache.reserve(1024);
39 m_stack_cache.reserve(1024);
42 ~graph_static()
override { clear(); }
44 void sort_all_nodes(
const graph_t& gr)
50 m_all_nodes.reserve(m_nodes.size());
53 m_topo_order_cache.clear();
54 m_topo_order_cache.reserve(m_nodes.size());
55 auto view = boost::filtered_graph{gr, no_delay_edges{&gr}};
56 custom_topological_sort<graph_t>(
57 view, std::back_inserter(m_topo_order_cache), m_color_map_cache,
61 for(
auto vtx : m_topo_order_cache)
63 auto node = gr[vtx].get();
65 if(node->root_inputs().empty() && node->root_outputs().empty())
67 m_all_nodes.push_back(node);
71 for(
auto vtx : m_topo_order_cache)
73 auto node = gr[vtx].get();
76 if(!(node->root_inputs().empty() && node->root_outputs().empty()))
78 m_all_nodes.push_back(node);
85 std::cout <<
"Error: graph isn't a DAG: ";
86 print_graph(gr, std::cout);
87 std::cout << std::endl;
92 void state(execution_state& e)
override
98 update_fun(*
this, e.exec_devices());
99 m_enabled_cache.clear();
104 m_enabled_cache.reserve(m_nodes.size());
106 for(
auto node : m_all_nodes)
108 ossia::graph_node& ptr = *node;
111 m_enabled_cache.insert(&ptr);
115 auto it = m_enabled_cache.find(&ptr);
116 if(it != m_enabled_cache.end())
117 m_enabled_cache.erase(it);
121 disable_strict_nodes_rec(m_enabled_cache, m_disabled_cache);
123 tick_fun(*
this, update_fun, e, m_all_nodes);
125#if defined(OSSIA_EXECUTION_LOG)
126 auto log = g_exec_log.log_executed_nodes(m_graph, m_all_nodes);
129 finish_nodes(m_nodes);
131 catch(
const boost::not_a_dag&)
138 [[nodiscard]]
const graph_t& impl()
const {
return m_graph; }
139 graph_t& impl() {
return m_graph; }
140 std::vector<graph_node*> m_all_nodes;
143 void print(std::ostream& stream)
override { print_graph(m_graph, stream); }
146 node_flat_set m_enabled_cache;
147 node_flat_set m_disabled_cache;
148 std::vector<graph_vertex_t> m_topo_order_cache;
150 friend class ::DataflowTest;
155 ossia::graph_t& m_sub_graph;
156 template <
typename Graph_T>
157 simple_update(Graph_T& g,
const ossia::graph_setup_options& opt)
158 : m_sub_graph{g.m_graph}
162 template <
typename Graph_T,
typename DevicesT>
163 void operator()(Graph_T& g,
const DevicesT& devices)
165 g.sort_all_nodes(g.m_graph);
172 template <
typename Graph_T>
173 bfs_update(Graph_T& g,
const ossia::graph_setup_options& opt)
174 : m_color{boost::make_two_bit_color_map_fast(
175 0, boost::get(boost::vertex_index, g.m_graph))}
179 template <
typename Graph_T,
typename DevicesT>
180 void operator()(Graph_T& g,
const DevicesT& devices)
182 auto& m_graph = g.m_graph;
183 auto& m_nodes = g.m_nodes;
184 auto& m_all_nodes = g.m_all_nodes;
185 const auto N = boost::num_vertices(m_graph);
188 m_sub_graph = m_graph;
190 g.sort_all_nodes(m_graph);
193 for(std::size_t i = 0; i < N; i++)
195 ossia::graph_node* n1 = m_all_nodes[i];
196 for(std::size_t j = i + 1; j < N; j++)
198 ossia::graph_node* n2 = m_all_nodes[j];
200 auto source_vtx = m_nodes.find(n1)->second;
201 auto sink_vtx = m_nodes.find(n2)->second;
202 if(find_path(source_vtx, sink_vtx, m_sub_graph))
204 if(find_path(sink_vtx, source_vtx, m_sub_graph))
207 if(graph_util::find_address_connection(*n1, *n2, devices))
209 auto src_it = m_nodes.find(n1);
210 auto sink_it = m_nodes.find(n2);
211 assert(src_it != m_nodes.end());
212 assert(sink_it != m_nodes.end());
213 auto edge = g.allocate_edge(
214 ossia::dependency_connection{}, ossia::outlet_ptr{}, ossia::inlet_ptr{},
215 src_it->first, sink_it->first);
216 boost::add_edge(sink_it->second, src_it->second, edge, m_sub_graph);
218#if defined(OSSIA_GRAPH_DEBUG)
219 auto all_nodes_old = std::move(m_all_nodes);
221 sort_all_nodes(sub_graph);
222 m_all_nodes = std::move(all_nodes_old);
225 else if(graph_util::find_address_connection(*n2, *n1, devices))
227 auto src_it = m_nodes.find(n2);
228 auto sink_it = m_nodes.find(n1);
229 auto edge = g.allocate_edge(
230 ossia::dependency_connection{}, ossia::outlet_ptr{}, ossia::inlet_ptr{},
231 src_it->first, sink_it->first);
232 boost::add_edge(sink_it->second, src_it->second, edge, m_sub_graph);
234#if defined(OSSIA_GRAPH_DEBUG)
235 auto all_nodes_old = std::move(m_all_nodes);
237 sort_all_nodes(sub_graph);
238 m_all_nodes = std::move(all_nodes_old);
244 g.sort_all_nodes(m_sub_graph);
247 bool find_path(graph_vertex_t source, graph_vertex_t sink, graph_t& graph)
250 struct bfs_find_visitor
252 graph_vertex_t node_to_find{};
254 bool discover_vertex(graph_vertex_t u,
const graph_t&)
const noexcept
256 if(u == node_to_find)
264 const auto N = boost::num_vertices(graph);
265 if(m_queue.capacity() <= N)
266 m_queue.set_capacity(N);
270 ossia::bfs::breadth_first_search_simple(graph, source, to_find, m_queue, m_color);
276 boost::circular_buffer<graph_vertex_t> m_queue;
278 using pmap_type =
decltype(boost::make_two_bit_color_map_fast(
279 0, get(boost::vertex_index, graph_t{})));
284template <
typename Impl>
290 template <
typename Graph_T>
291 tc_update(Graph_T& g,
const ossia::graph_setup_options& opt)
294 template <
typename Graph_T,
typename DevicesT>
295 void operator()(Graph_T& g,
const DevicesT& devices)
297 m_sub_graph = g.m_graph;
299 g.sort_all_nodes(m_sub_graph);
301 impl.update(m_sub_graph);
303 tc_add_addresses(g, g.m_graph, m_sub_graph, g.m_nodes, g.m_all_nodes, impl, devices);
305 g.sort_all_nodes(m_sub_graph);
312 typename BaseGraph,
typename TCGraph,
typename NodeMap,
typename AllNodes,
313 typename TC,
typename Devices>
314 static void tc_add_addresses(
315 auto& impl, BaseGraph& m_graph, TCGraph& m_sub_graph, NodeMap& m_nodes,
316 AllNodes& m_all_nodes, TC& tc, Devices& devices)
340 for(std::size_t i = 0; i < m_all_nodes.size(); i++)
342 ossia::graph_node* n1 = m_all_nodes[i];
343 for(std::size_t j = i + 1; j < m_all_nodes.size(); j++)
345 ossia::graph_node* n2 = m_all_nodes[j];
347 auto source_vtx = m_nodes.find(n1)->second;
348 auto sink_vtx = m_nodes.find(n2)->second;
349 if(tc.has_edge(source_vtx, sink_vtx))
351 if(tc.has_edge(sink_vtx, source_vtx))
354 if(graph_util::find_address_connection(*n1, *n2, devices))
356 auto src_it = m_nodes.find(n1);
357 auto sink_it = m_nodes.find(n2);
358 auto edge = impl.allocate_edge(
359 ossia::dependency_connection{}, ossia::outlet_ptr{}, ossia::inlet_ptr{},
360 src_it->first, sink_it->first);
361 boost::add_edge(sink_it->second, src_it->second, edge, m_sub_graph);
362 tc.update(m_sub_graph);
364#if defined(OSSIA_GRAPH_DEBUG)
365 print_graph(transitive_closure, std::cout);
366 auto all_nodes_old = std::move(m_all_nodes);
368 sort_all_nodes(sub_graph);
369 m_all_nodes = std::move(all_nodes_old);
372 else if(graph_util::find_address_connection(*n2, *n1, devices))
374 auto src_it = m_nodes.find(n2);
375 auto sink_it = m_nodes.find(n1);
376 auto edge = impl.allocate_edge(
377 ossia::dependency_connection{}, ossia::outlet_ptr{}, ossia::inlet_ptr{},
378 src_it->first, sink_it->first);
379 boost::add_edge(sink_it->second, src_it->second, edge, m_sub_graph);
380 tc.update(m_sub_graph);
382#if defined(OSSIA_GRAPH_DEBUG)
383 auto all_nodes_old = std::move(m_all_nodes);
385 sort_all_nodes(sub_graph);
386 m_all_nodes = std::move(all_nodes_old);
397 using transitive_closure_t = boost::adjacency_list<
398 boost::vecS, boost::vecS, boost::directedS, ossia::graph_node*, int64_t>;
400 [[nodiscard]]
bool has_edge(
int source_vtx,
int sink_vtx)
const
402 return boost::edge(source_vtx, sink_vtx, m_transitive_closure).second;
404 void update(
const graph_t& sub_graph)
406 m_transitive_closure = transitive_closure_t{};
407 ossia::transitive_closure(sub_graph, m_transitive_closure, m_tcState);
409#if defined(OSSIA_GRAPH_DEBUG)
410 auto vertices = boost::vertices(sub_graph);
411 for(
auto i = vertices.first; i != vertices.second; i++)
413 tclos[*i] = sub_graph[*i].get();
416 print_graph(tclos, std::cout);
419 transitive_closure_t m_transitive_closure;
420 ossia::TransitiveClosureState<graph_t, transitive_closure_t> m_tcState;
426 using transitive_closure_t = boost::adjacency_list<
427 boost::vecS, boost::vecS, boost::directedS, ossia::graph_node*, int64_t>;
429 [[nodiscard]]
bool has_edge(
int source_vtx,
int sink_vtx)
const
431 return boost::edge(source_vtx, sink_vtx, m_transitive_closure).second;
434 void update(
const graph_t& sub_graph)
436 m_transitive_closure = transitive_closure_t{};
437 boost::transitive_closure(sub_graph, m_transitive_closure);
439#if defined(OSSIA_GRAPH_DEBUG)
440 auto vertices = boost::vertices(sub_graph);
441 for(
auto i = vertices.first; i != vertices.second; i++)
443 tclos[*i] = sub_graph[*i].get();
446 print_graph(tclos, std::cout);
451 transitive_closure_t m_transitive_closure;
454using tc_graph = graph_static<tc_update<fast_tc>, static_exec>;
455using bfs_graph = graph_static<bfs_update, static_exec>;
457using logged_tc_graph = graph_static<tc_update<fast_tc>, static_exec_logger>;
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition context.cpp:118
std::ostream & print(std::ostream &out, const state_element &e)
print Print a state_element
Definition state_element.cpp:23