OSSIA
Open Scenario System for Interactive Application
transitive_closure.hpp
1 // Copyright (C) 2001 Vladimir Prus <ghost@cs.msu.su>
2 // Copyright (C) 2001 Jeremy Siek <jsiek@cs.indiana.edu>
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 // NOTE: this final is generated by libs/graph/doc/transitive_closure.w
8 
9 #pragma once
10 #include <ossia/detail/config.hpp>
11 
12 #include <boost/concept/assert.hpp>
13 #include <boost/config.hpp>
14 #include <boost/graph/adjacency_list.hpp>
15 #include <boost/graph/graph_concepts.hpp>
16 #include <boost/graph/named_function_params.hpp>
17 #include <boost/graph/strong_components.hpp>
18 #include <boost/graph/topological_sort.hpp>
19 
20 #include <algorithm> // for std::min and std::max
21 #include <functional>
22 #include <vector>
23 
24 namespace ossia
25 {
26 namespace detail
27 {
28 inline void union_successor_sets(
29  const std::vector<std::size_t>& s1, const std::vector<std::size_t>& s2,
30  std::vector<std::size_t>& s3)
31 {
32  BOOST_USING_STD_MIN();
33  for(std::size_t k = 0; k < s1.size(); ++k)
34  s3[k] = min BOOST_PREVENT_MACRO_SUBSTITUTION(s1[k], s2[k]);
35 }
36 
37 template <
38  typename TheContainer, typename ST = std::size_t,
39  typename VT = typename TheContainer::value_type>
40 struct subscript_t
41 {
42  typedef VT& result_type;
43 
44  subscript_t(TheContainer& c)
45  : container(&c)
46  {
47  }
48  VT& operator()(const ST& i) const { return (*container)[i]; }
49 
50 protected:
51  TheContainer* container;
52 };
53 template <typename TheContainer>
54 subscript_t<TheContainer> subscript(TheContainer& c)
55 {
56  return subscript_t<TheContainer>(c);
57 }
58 } // namespace detail
59 
60 template <typename Graph, typename GraphTC>
61 struct TransitiveClosureState
62 {
63  using VertexIndexMap =
64  typename boost::property_map<Graph, boost::vertex_index_t>::const_type;
65 
66  using vertex = typename boost::graph_traits<Graph>::vertex_descriptor;
67  using size_type = typename boost::property_traits<VertexIndexMap>::value_type;
68  using tc_vertex = typename boost::graph_traits<GraphTC>::vertex_descriptor;
69  using cg_vertex = size_type;
70  using CG_t = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS>;
71 
72  std::vector<tc_vertex> to_tc_vec;
73 
74  std::vector<cg_vertex> component_number_vec;
75  std::vector<std::vector<vertex>> components;
76 
77  CG_t CG;
78 
79  std::vector<cg_vertex> adj;
80 
81  std::vector<cg_vertex> topo_order;
82  std::vector<cg_vertex> topo_number;
83 
84  std::vector<std::vector<cg_vertex>> CG_vec;
85  std::vector<std::vector<cg_vertex>> chains;
86  std::vector<cg_vertex> in_a_chain;
87 
88  std::vector<size_type> chain_number;
89  std::vector<size_type> pos_in_chain;
90 
91  std::vector<std::vector<cg_vertex>> successors;
92 };
93 
94 template <typename T>
95 void resize_and_fill(T& vec, const std::size_t N)
96 {
97  vec.clear();
98  vec.resize(N);
99 }
100 template <typename T>
101 void resize_and_fill(std::vector<std::vector<T>>& vec, const std::size_t N)
102 {
103  const auto cur = vec.size();
104  vec.resize(N);
105  for(std::size_t i = 0; i < std::min(cur, N); i++)
106  {
107  vec[i].clear();
108  }
109 }
110 
111 template <typename T>
112 void resize_and_fill(
113  std::vector<std::vector<T>>& vec, const std::size_t N, const std::size_t init_num,
114  T init_val)
115 {
116  vec.resize(N);
117  for(std::size_t i = 0; i < N; i++)
118  {
119  auto cur = vec[i].size();
120  vec[i].resize(init_num, init_val);
121  std::fill(vec[i].begin(), vec[i].begin() + std::min(cur, init_num), init_val);
122  }
123 }
124 
125 template <
126  typename Graph, typename GraphTC, typename G_to_TC_VertexMap,
127  typename VertexIndexMap>
128 void transitive_closure(
129  const Graph& g, GraphTC& tc, G_to_TC_VertexMap g_to_tc_map, VertexIndexMap index_map,
130  TransitiveClosureState<Graph, GraphTC>& state)
131 {
132  using namespace boost;
133  if(num_vertices(g) == 0)
134  return;
135  typedef typename graph_traits<Graph>::vertex_descriptor vertex;
136  typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
137  typedef typename property_traits<VertexIndexMap>::value_type size_type;
138 
139  BOOST_CONCEPT_ASSERT((VertexListGraphConcept<Graph>));
140  BOOST_CONCEPT_ASSERT((AdjacencyGraphConcept<Graph>));
141  BOOST_CONCEPT_ASSERT((VertexMutableGraphConcept<GraphTC>));
142  BOOST_CONCEPT_ASSERT((EdgeMutableGraphConcept<GraphTC>));
143  BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept<VertexIndexMap, vertex>));
144 
145  typedef size_type cg_vertex;
146  const auto n_vtx = num_vertices(g);
147  auto& component_number_vec = state.component_number_vec;
148  resize_and_fill(component_number_vec, n_vtx);
149  iterator_property_map<cg_vertex*, VertexIndexMap, cg_vertex, cg_vertex&>
150  component_number(&component_number_vec[0], index_map);
151 
152  const auto num_scc
153  = strong_components(g, component_number, vertex_index_map(index_map));
154 
155  auto& components = state.components;
156  resize_and_fill(components, num_scc);
157  build_component_lists(g, num_scc, component_number, components);
158 
159  typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> CG_t;
160  auto& CG = state.CG;
161  CG = CG_t{num_scc}; // todo reuse memory/
162 
163  for(cg_vertex s = 0; s < components.size(); ++s)
164  {
165  auto& adj = state.adj;
166  adj.clear();
167  for(size_type i = 0; i < components[s].size(); ++i)
168  {
169  const auto u = components[s][i];
170  for(auto [v, v_end] = adjacent_vertices(u, g); v != v_end; ++v)
171  {
172  const auto t = component_number[*v];
173  if(s != t) // Avoid loops in the condensation graph
174  adj.push_back(t);
175  }
176  }
177 
178  ossia::remove_duplicates(adj);
179  for(auto i = adj.begin(); i != adj.end(); ++i)
180  {
181  add_edge(s, *i, CG);
182  }
183  }
184 
185  assert(num_scc == num_vertices(CG));
186  auto& topo_order = state.topo_order;
187  topo_order.clear();
188  topo_order.reserve(num_scc);
189  auto& topo_number = state.topo_number;
190  topo_number.resize(num_scc);
191  topological_sort(
192  CG, std::back_inserter(topo_order), vertex_index_map(identity_property_map()));
193  std::reverse(topo_order.begin(), topo_order.end());
194  size_type n = 0;
195  for(auto iter = topo_order.begin(); iter != topo_order.end(); ++iter)
196  topo_number[*iter] = n++;
197 
198  auto& CG_vec = state.CG_vec;
199  CG_vec.resize(num_scc);
200  for(size_type i = 0; i < num_scc; ++i)
201  {
202  auto pr = adjacent_vertices(i, CG);
203  CG_vec[i].assign(pr.first, pr.second);
204  std::sort(CG_vec[i].begin(), CG_vec[i].end(), [&](cg_vertex lhs, cg_vertex rhs) {
205  return topo_number[lhs] < topo_number[rhs];
206  });
207  }
208 
209  auto& chains = state.chains;
210  chains.clear();
211  chains.reserve(std::log2(n_vtx));
212  {
213  auto& in_a_chain = state.in_a_chain;
214  resize_and_fill(in_a_chain, num_scc);
215  for(cg_vertex v : topo_order)
216  {
217  if(!in_a_chain[v])
218  {
219  chains.resize(chains.size() + 1);
220  auto& chain = chains.back();
221  for(;;)
222  {
223  chain.push_back(v);
224  in_a_chain[v] = true;
225  auto next = std::find_if(CG_vec[v].begin(), CG_vec[v].end(), [&](auto elt) {
226  return !in_a_chain[elt];
227  });
228  if(next != CG_vec[v].end())
229  v = *next;
230  else
231  break; // end of chain, dead-end
232  }
233  }
234  }
235  }
236  auto& chain_number = state.chain_number;
237  chain_number.resize(num_scc); // resize_and_fill(chain_number, num_scc);
238  auto& pos_in_chain = state.pos_in_chain;
239  pos_in_chain.resize(num_scc); // resize_and_fill(pos_in_chain, num_scc);
240  for(size_type i = 0; i < chains.size(); ++i)
241  for(size_type j = 0; j < chains[i].size(); ++j)
242  {
243  const cg_vertex v = chains[i][j];
244  chain_number[v] = i;
245  pos_in_chain[v] = j;
246  }
247 
248  static const constexpr cg_vertex inf = std::numeric_limits<cg_vertex>::max();
249  auto& successors = state.successors;
250  resize_and_fill(successors, num_scc, chains.size(), inf);
251  for(auto i = topo_order.rbegin(); i != topo_order.rend(); ++i)
252  {
253  const cg_vertex u = *i;
254  for(auto adj = CG_vec[u].begin(), adj_last = CG_vec[u].end(); adj != adj_last; ++adj)
255  {
256  const cg_vertex v = *adj;
257  auto& suc_u = successors[u];
258  auto& suc_v = successors[v];
259  auto& suc_u_v = suc_u[chain_number[v]];
260  auto& topo_v = topo_number[v];
261  if(topo_v < suc_u_v)
262  {
263  // Succ(u) = Succ(u) U Succ(v)
264  detail::union_successor_sets(suc_u, suc_v, suc_u);
265  // Succ(u) = Succ(u) U {v}
266  suc_u_v = topo_v;
267  }
268  }
269  }
270 
271  for(size_type i = 0; i < CG_vec.size(); ++i)
272  CG_vec[i].clear();
273  for(size_type i = 0; i < CG_vec.size(); ++i)
274  for(size_type j = 0; j < chains.size(); ++j)
275  {
276  const size_type topo_num = successors[i][j];
277  if(topo_num < inf)
278  {
279  cg_vertex v = topo_order[topo_num];
280  const auto chain_j_size = chains[j].size();
281  const auto pos_v = pos_in_chain[v];
282  if(chain_j_size > pos_v)
283  {
284  CG_vec[i].reserve(CG_vec[i].size() + chain_j_size - pos_v);
285  for(size_type k = pos_v; k < chain_j_size; ++k)
286  CG_vec[i].push_back(chains[j][k]);
287  }
288  }
289  }
290 
291  // Add vertices to the transitive closure graph
292  {
293  vertex_iterator i, i_end;
294  for(boost::tie(i, i_end) = vertices(g); i != i_end; ++i)
295  g_to_tc_map[*i] = add_vertex(tc);
296  }
297  // Add edges between all the vertices in two adjacent SCCs
298  for(auto si = CG_vec.begin(), si_end = CG_vec.end(); si != si_end; ++si)
299  {
300  cg_vertex s = si - CG_vec.begin();
301  for(auto i = CG_vec[s].begin(), i_end = CG_vec[s].end(); i != i_end; ++i)
302  {
303  cg_vertex t = *i;
304  for(size_type k = 0; k < components[s].size(); ++k)
305  for(size_type l = 0; l < components[t].size(); ++l)
306  add_edge(g_to_tc_map[components[s][k]], g_to_tc_map[components[t][l]], tc);
307  }
308  }
309  // Add edges connecting all vertices in a SCC
310  for(size_type i = 0; i < components.size(); ++i)
311  if(components[i].size() > 1)
312  for(size_type k = 0; k < components[i].size(); ++k)
313  for(size_type l = 0; l < components[i].size(); ++l)
314  {
315  vertex u = components[i][k], v = components[i][l];
316  add_edge(g_to_tc_map[u], g_to_tc_map[v], tc);
317  }
318 
319  // Find loopbacks in the original graph.
320  // Need to add it to transitive closure.
321  {
322  for(auto [i, i_end] = vertices(g); i != i_end; ++i)
323  {
324  for(auto [ab, ae] = adjacent_vertices(*i, g); ab != ae; ++ab)
325  {
326  if(*ab == *i)
327  if(components[component_number[*i]].size() == 1)
328  add_edge(g_to_tc_map[*i], g_to_tc_map[*i], tc);
329  }
330  }
331  }
332 }
333 
334 template <typename Graph, typename GraphTC>
335 void transitive_closure(
336  const Graph& g, GraphTC& tc, TransitiveClosureState<Graph, GraphTC>& tc_state)
337 {
338  using namespace boost;
339  if(num_vertices(g) == 0)
340  return;
341  typedef typename property_map<Graph, vertex_index_t>::const_type VertexIndexMap;
342  VertexIndexMap index_map = get(vertex_index, g);
343 
344  typedef typename graph_traits<GraphTC>::vertex_descriptor tc_vertex;
345 
346  resize_and_fill(tc_state.to_tc_vec, num_vertices(g));
347  iterator_property_map<tc_vertex*, VertexIndexMap, tc_vertex, tc_vertex&> g_to_tc_map(
348  &tc_state.to_tc_vec[0], index_map);
349 
350  transitive_closure(g, tc, g_to_tc_map, index_map, tc_state);
351 }
352 }
Definition: git_info.h:7
constexpr OSSIA_INLINE auto min(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
min function tailored for values
Definition: math.hpp:125
constexpr OSSIA_INLINE auto max(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
max function tailored for values
Definition: math.hpp:96