indigoX
base_graph_impl.hpp
Go to the documentation of this file.
1 #include "../algorithm/graph/connectivity.hpp"
2 #include "../algorithm/graph/cycles.hpp"
3 #include "../utils/serialise.hpp"
4 #include "../utils/triple.hpp"
5 
6 #include <EASTL/vector_map.h>
7 #include <EASTL/vector_set.h>
8 #include <vector>
9 
10 namespace indigox::graph {
11 
12 #define GRAPHTEMPLATE \
13  template <class V, class E, class S, class D, class VP, class EP>
14 #define BG BaseGraph<V, E, S, D, VP, EP>
15 #define BASEGRAPH(...) GRAPHTEMPLATE __VA_ARGS__ BG
16 #define tBG typename BG
17 
18  BASEGRAPH(struct)::BaseImpl {
19  graph_type boost_graph;
22  VertContain vertices;
23  EdgeContain edges;
24  NbrsContain predecessors;
25  NbrsContain successors;
27 
28  ComponentContain cached_connected_components;
30 
32  EdgeContain cached_cyclic_edges;
33  CycleEdgeContain cached_cycles;
35 
37  : boost_graph(), state(0), state_cached_components(0),
38  state_cached_cycles(0) {}
39 
40  V GetSourceVertex(const E &e) const {
41  EdgeType eboost = edge_descriptors.left.at(e);
42  VertType source = boost::source(eboost, boost_graph);
43  return vertex_descriptors.right.at(source);
44  }
45 
46  V GetTargetVertex(const E &e) const {
47  EdgeType eboost = edge_descriptors.left.at(e);
48  VertType target = boost::target(eboost, boost_graph);
49  return vertex_descriptors.right.at(target);
50  }
51 
52  void AddVertex(const V &v) {
53  VertType vboost = boost::add_vertex(VP(), boost_graph);
54  vertex_descriptors.insert(v, vboost);
55  vertices.emplace_back(v);
56  predecessors.emplace(v, VertContain());
57  if (D::is_directed) successors.emplace(v, VertContain());
58  }
59 
60  void AddEdge(const V &u, const V &v, const E &e) {
61  // assume has both the vertices already. Make the BaseGraph method do the
62  // real checking of this
63  VertType uboost = vertex_descriptors.left.at(u);
64  VertType vboost = vertex_descriptors.left.at(v);
65  EdgeType eboost =
66  boost::add_edge(uboost, vboost, EP(), boost_graph).first;
67  edge_descriptors.insert(e, eboost);
68  edges.emplace_back(e);
69  }
70 
71  template <typename Archive>
72  void save(Archive & archive, const uint32_t) const {
73  std::vector<std::pair<V, V>> vertex_edges;
74  vertex_edges.reserve(edges.size());
75  for (const E &e : edges) {
76  vertex_edges.emplace_back(GetSourceVertex(e), GetTargetVertex(e));
77  }
78 
79  archive(INDIGOX_SERIAL_NVP("vertices", vertices),
80  INDIGOX_SERIAL_NVP("vertex_edges", vertex_edges),
81  INDIGOX_SERIAL_NVP("edges", edges),
82  INDIGOX_SERIAL_NVP("state", state));
83  }
84 
85  template <typename Archive> void load(Archive & archive, const uint32_t) {
86  VertContain input_vertices;
87  std::vector<std::pair<V, V>> input_vertex_edges;
88  EdgeContain input_edges;
89  archive(INDIGOX_SERIAL_NVP("vertices", input_vertices),
90  INDIGOX_SERIAL_NVP("vertex_edges", input_vertex_edges),
91  INDIGOX_SERIAL_NVP("edges", input_edges));
92 
93  // Build the graph
94  for (V &v : input_vertices) AddVertex(v);
95  for (size_t pos = 0; pos < input_edges.size(); ++pos) {
96  AddEdge(input_vertex_edges[pos].first, input_vertex_edges[pos].second,
97  input_edges[pos]);
98  }
99 
100  // Reload state
101  archive(INDIGOX_SERIAL_NVP("state", state));
102  }
103  };
104 
105  BASEGRAPH(template <typename Archive> void)::serialise(Archive &archive,
106  const uint32_t) {
107  archive(INDIGOX_SERIAL_NVP("base_graph_data", m_basedata));
108  }
109 
110  // BASEGRAPH(void)::Clear() {
111  // _g.clear();
112  // _vm.clear();
113  // _em.clear();
114  // _v.clear();
115  // _e.clear();
116  // _pre.clear();
117  // _suc.clear();
118  // _comp_cache.clear();
119  // _vcyclic_cache.clear();
120  // _ecyclic_cache.clear();
121  // _cycles_cache.clear();
122  // }
123 
124  BASEGRAPH(void)::AddVertex(const V &v) {
125  ++m_basedata->state;
126  m_basedata->AddVertex(v);
127  }
128 
129  BASEGRAPH(void)::RemoveVertex(const V &v) {
130  ++m_basedata->state;
131  VertType vboost = GetDescriptor(v);
132  // Remove adjacent edges
133  PredIter vi, vi_end;
134  std::tie(vi, vi_end) =
135  boost::inv_adjacent_vertices(vboost, m_basedata->boost_graph);
136  for (; vi != vi_end; ++vi) {
137  V u = GetV(*vi);
138  E e = GetE(boost::edge(vboost, *vi, m_basedata->boost_graph).first);
139  m_basedata->edge_descriptors.erase(e);
140  m_basedata->edges.erase(
141  std::find(m_basedata->edges.begin(), m_basedata->edges.end(), e));
142  }
143  // Remove incident edges of directed graphs
144  if (D::is_directed) {
145  NbrsIter vp, vp_end;
146  std::tie(vp, vp_end) =
147  boost::adjacent_vertices(vboost, m_basedata->boost_graph);
148  for (; vp != vp_end; ++vp) {
149  V u = GetV(*vp);
150  E e = GetE(boost::edge(*vp, vboost, m_basedata->boost_graph).first);
151  m_basedata->edge_descriptors.erase(e);
152  m_basedata->edges.erase(
153  std::find(m_basedata->edges.begin(), m_basedata->edges.end(), e));
154  }
155  }
156  // Remove the vertex
157  m_basedata->vertex_descriptors.erase(v);
158  m_basedata->vertices.erase(
159  std::find(m_basedata->vertices.begin(), m_basedata->vertices.end(), v));
160  m_basedata->predecessors.erase(v);
161  if (D::is_directed) m_basedata->successors.erase(v);
162  boost::clear_vertex(vboost, m_basedata->boost_graph);
163  boost::remove_vertex(vboost, m_basedata->boost_graph);
164  }
165 
166  BASEGRAPH(void)::AddEdge(const V &u, const V &v, const E &e) {
167  ++m_basedata->state;
168  if (!HasVertex(u)) AddVertex(u);
169  if (!HasVertex(v)) AddVertex(v);
170  m_basedata->AddEdge(u, v, e);
171  }
172 
173  BASEGRAPH(void)::RemoveEdge(const E &e) {
174  ++m_basedata->state;
175  EdgeType eboost = GetDescriptor(e);
176  m_basedata->edge_descriptors.erase(eboost);
177  m_basedata->edges.erase(
178  std::find(m_basedata->edges.begin(), m_basedata->edges.end(), e));
179  boost::remove_edge(eboost, m_basedata->boost_graph);
180  }
181 
182  BASEGRAPH(void)::RemoveEdge(const V &u, const V &v) {
183  E e = GetEdge(u, v);
184  RemoveEdge(e);
185  }
186 
187  BASEGRAPH(bool)::HasVertex(const V &v) const {
188  return m_basedata->vertex_descriptors.left.find(v) !=
189  m_basedata->vertex_descriptors.left.end();
190  }
191 
192  BASEGRAPH(bool)::HasEdge(const E &e) const {
193  return m_basedata->edge_descriptors.left.find(e) !=
194  m_basedata->edge_descriptors.left.end();
195  }
196 
197  BASEGRAPH(bool)::HasEdge(const V &u, const V &v) const {
198  if (!HasVertex(u) || !HasVertex(v)) return false;
199  VertType u_ = GetDescriptor(u);
200  VertType v_ = GetDescriptor(v);
201  return boost::edge(u_, v_, m_basedata->boost_graph).second;
202  }
203 
204  BASEGRAPH(int64_t)::NumVertices() const {
205  return boost::num_vertices(m_basedata->boost_graph);
206  }
207 
208  BASEGRAPH(int64_t)::NumEdges() const {
209  return boost::num_edges(m_basedata->boost_graph);
210  }
211 
212  BASEGRAPH(int64_t)::Degree(const V &v) const {
213  return HasVertex(v) ? OutDegree(GetDescriptor(v)) : -1;
214  }
215 
216  BASEGRAPH(int64_t)::InDegree(const V &v) const {
217  if (!HasVertex(v)) return -1;
218  if (D::is_directed) return InDegree(GetDescriptor(v));
219  return OutDegree(GetDescriptor(v));
220  }
221 
222  BASEGRAPH(const tBG::VertContain &)::GetNeighbours(const V &v) {
223  static_assert(!D::is_directed, "Requires an undirected graph.");
224  VertType vboost = GetDescriptor(v);
225  auto adjis = boost::adjacent_vertices(vboost, m_basedata->boost_graph);
226  m_basedata->predecessors.at(v).clear();
227  for (; adjis.first != adjis.second; ++adjis.first)
228  m_basedata->predecessors.at(v).emplace_back(GetV(*adjis.first));
229  return m_basedata->predecessors.at(v);
230  }
231 
232  BASEGRAPH(const tBG::VertContain &)::GetPredecessors(const V &v) {
233  static_assert(D::is_directed, "Requires a directed graph.");
234  VertType vboost = GetDescriptor(v);
235  auto adjis = boost::inv_adjacent_vertices(vboost, m_basedata->boost_graph);
236  m_basedata->predecessors.at(v).clear();
237  for (; adjis.first != adjis.second; ++adjis.first)
238  m_basedata->predecessors.at(v).emplace_back(GetV(*adjis.first));
239  return m_basedata->predecessors.at(v);
240  }
241 
242  BASEGRAPH(const tBG::VertContain &)::GetSuccessors(const V &v) {
243  static_assert(D::is_directed, "Requires a directed graph.");
244  VertType vboost = GetDescriptor(v);
245  auto adjis = boost::adjacent_vertices(vboost, m_basedata->boost_graph);
246  m_basedata->successors.at(v).clear();
247  for (; adjis.first != adjis.second; ++adjis.first)
248  m_basedata->successors.at(v).emplace_back(GetV(*adjis.first));
249  return m_basedata->successors.at(v);
250  }
251 
252  BASEGRAPH(std::pair<V, V>)::GetVertices(const E &e) const {
253  EdgeType eboost = GetDescriptor(e);
254  VertType u = boost::source(eboost, m_basedata->boost_graph);
255  VertType v = boost::target(eboost, m_basedata->boost_graph);
256  return {GetV(u), GetV(v)};
257  }
258 
259  BASEGRAPH(const tBG::VertContain &)::GetVertices() const {
260  return m_basedata->vertices;
261  }
262 
263  BASEGRAPH(const tBG::EdgeContain &)::GetEdges() const {
264  return m_basedata->edges;
265  }
266 
267  BASEGRAPH(E)::GetEdge(const V &u, const V &v) const {
268  VertType uboost = GetDescriptor(u);
269  VertType vboost = GetDescriptor(v);
270  EdgeType eboost =
271  boost::edge(uboost, vboost, m_basedata->boost_graph).first;
272  return GetE(eboost);
273  }
274 
275  BASEGRAPH(V)::GetSourceVertex(const E &e) const {
276  return m_basedata->GetSourceVertex(e);
277  }
278 
279  BASEGRAPH(V)::GetTargetVertex(const E &e) const {
280  return m_basedata->GetTargetVertex(e);
281  }
282 
283  // =====================================================================
284  // == Private helper functions =========================================
285  // =====================================================================
286  BASEGRAPH(tBG::VertType)::GetDescriptor(const V &v) const {
287  return m_basedata->vertex_descriptors.left.at(v);
288  }
289 
290  BASEGRAPH(V)::GetV(BG::VertType v) const {
291  return m_basedata->vertex_descriptors.right.at(v);
292  }
293 
294  BASEGRAPH(tBG::EdgeType)::GetDescriptor(const E &e) const {
295  return m_basedata->edge_descriptors.left.at(e);
296  }
297 
298  BASEGRAPH(E)::GetE(BG::EdgeType e) const {
299  return m_basedata->edge_descriptors.right.at(e);
300  }
301 
302  BASEGRAPH(int64_t)::OutDegree(BG::VertType v) const {
303  return boost::out_degree(v, m_basedata->boost_graph);
304  }
305 
306  BASEGRAPH(int64_t)::InDegree(BG::VertType v) const {
307  return boost::in_degree(v, m_basedata->boost_graph);
308  }
309 
310  // ======================================================================
311  // == Algorithmic stuffs ================================================
312  // ======================================================================
313 
314  // Connectivity
315  BASEGRAPH(bool)::IsConnected() {
316  GetConnectedComponents();
317  return m_basedata->cached_connected_components.size() == 1;
318  }
319 
320  BASEGRAPH(int64_t)::NumConnectedComponents() {
321  GetConnectedComponents();
322  return m_basedata->cached_connected_components.size();
323  }
324 
325  BASEGRAPH(const tBG::ComponentContain &)::GetConnectedComponents() {
326  if (m_basedata->state_cached_components == m_basedata->state)
327  return m_basedata->cached_connected_components;
329  m_basedata->cached_connected_components);
330  m_basedata->state_cached_components = m_basedata->state;
331  return m_basedata->cached_connected_components;
332  }
333 
334  // Cycles
335  BASEGRAPH(bool)::IsCyclic(const V &v) {
336  GetCycles();
337  auto pos = std::find(m_basedata->cached_cyclic_vertices.begin(),
338  m_basedata->cached_cyclic_vertices.end(), v);
339  return pos != m_basedata->cached_cyclic_vertices.end();
340  }
341 
342  BASEGRAPH(bool)::IsCyclic(const V &v, uint32_t sz) {
343  if (!IsCyclic(v)) return false;
344  for (auto &cyc : m_basedata->cached_cycles) {
345  if (cyc.size() > sz) return false;
346  for (E &edge : cyc) {
347  V a = GetSourceVertex(edge);
348  V b = GetTargetVertex(edge);
349  if (a == v || b == v) return true;
350  }
351  }
352  return false;
353  }
354 
355  BASEGRAPH(bool)::IsCyclic(const E &e) {
356  GetCycles();
357  auto pos = std::find(m_basedata->cached_cyclic_edges.begin(),
358  m_basedata->cached_cyclic_edges.end(), e);
359  return pos != m_basedata->cached_cyclic_edges.end();
360  }
361 
362  BASEGRAPH(bool)::IsCyclic(const E &e, uint32_t sz) {
363  if (!IsCyclic(e)) return false;
364  for (auto &cyc : m_basedata->cached_cycles) {
365  if (cyc.size() > sz) return false;
366  for (E &edge : cyc) {
367  if (edge == e) return true;
368  }
369  }
370  return false;
371  }
372 
373  BASEGRAPH(const tBG::CycleEdgeContain &)::GetCycles() {
374  using VertSet = eastl::vector_set<V>;
375  using EdgeSet = eastl::vector_set<E>;
376 
377  if (m_basedata->state == m_basedata->state_cached_cycles)
378  return m_basedata->cached_cycles;
379  algorithm::AllCycles(*this, m_basedata->cached_cycles);
380  VertSet cyclic_v;
381  cyclic_v.reserve(NumVertices());
382  EdgeSet cyclic_e;
383  cyclic_e.reserve(NumEdges());
384 
385  for (EdgeContain &cycle : m_basedata->cached_cycles) {
386  for (E &edge : cycle) {
387  cyclic_e.emplace(edge);
388  cyclic_v.emplace(GetSourceVertex(edge));
389  cyclic_v.emplace(GetTargetVertex(edge));
390  }
391  }
392  m_basedata->cached_cyclic_vertices.clear();
393  m_basedata->cached_cyclic_vertices.assign(cyclic_v.begin(), cyclic_v.end());
394  m_basedata->cached_cyclic_edges.clear();
395  m_basedata->cached_cyclic_edges.assign(cyclic_e.begin(), cyclic_e.end());
396  std::sort(
397  m_basedata->cached_cycles.begin(), m_basedata->cached_cycles.end(),
398  [](EdgeContain &a, EdgeContain &b) { return a.size() < b.size(); });
399  m_basedata->state_cached_cycles = m_basedata->state;
400  return m_basedata->cached_cycles;
401  }
402 
403  BASEGRAPH(int64_t)::NumCycles() {
404  GetCycles();
405  return m_basedata->cached_cycles.size();
406  }
407 
408  // Isomorphism
409 
410 #undef GRAPHTEMPLATE
411 #undef BASEGRAPH
412 #undef BG
413 #undef tBG
414 } // namespace indigox::graph
V GetTargetVertex(const E &e) const
Definition: base_graph_impl.hpp:46
void load(Archive &archive, const uint32_t)
Definition: base_graph_impl.hpp:85
EdgeContain cached_cyclic_edges
Definition: base_graph_impl.hpp:32
std::vector< CMGEdge > EdgeContain
Type for storing edges.
Definition: base_graph.hpp:92
Definition: assignment.hpp:16
BaseImpl()
Definition: base_graph_impl.hpp:36
void RemoveEdge(const V &u, const V &v)
Remove an edge from the graph.
Definition: base_graph_impl.hpp:182
State state_cached_components
Definition: base_graph_impl.hpp:29
void AddVertex(const V &v)
Definition: base_graph_impl.hpp:52
#define BASEGRAPH(...)
Definition: base_graph_impl.hpp:15
void AddEdge(const V &u, const V &v, const E &e)
Definition: base_graph_impl.hpp:60
CycleEdgeContain cached_cycles
Definition: base_graph_impl.hpp:33
#define INDIGOX_SERIAL_NVP(name, value)
Definition: serialise.hpp:66
VertContain cached_cyclic_vertices
Definition: base_graph_impl.hpp:31
void save(Archive &archive, const uint32_t) const
Definition: base_graph_impl.hpp:72
EdgeMap edge_descriptors
Definition: base_graph_impl.hpp:21
typename graph_type::inv_adjacency_iterator PredIter
Type for iterator over predecessors of a vertex descriptor.
Definition: base_graph.hpp:79
typename graph_type::vertex_descriptor VertType
Type of the graph vertex descriptor.
Definition: base_graph.hpp:73
uint32_t State
Definition: fwd_declares.hpp:45
V GetSourceVertex(const E &e) const
Definition: base_graph_impl.hpp:40
EdgeContain edges
Definition: base_graph_impl.hpp:23
VertContain vertices
Definition: base_graph_impl.hpp:22
State state
Definition: base_graph_impl.hpp:26
#define BG
Definition: base_graph_impl.hpp:14
int64_t ConnectedComponents(graph::BaseGraph< V, E, S, D, VP, EP > &G, Container &bits)
NbrsContain successors
Definition: base_graph_impl.hpp:25
ComponentContain cached_connected_components
Definition: base_graph_impl.hpp:28
NbrsContain predecessors
Definition: base_graph_impl.hpp:24
graph_type boost_graph
Definition: base_graph_impl.hpp:19
VertMap vertex_descriptors
Definition: base_graph_impl.hpp:20
State state_cached_cycles
Definition: base_graph_impl.hpp:34
int64_t AllCycles(graph::BaseGraph< V, E, S, D, VP, EP > &G, Container &ecycles)
typename graph_type::edge_descriptor EdgeType
Type of the graph edge descriptor.
Definition: base_graph.hpp:81
typename graph_type::adjacency_iterator NbrsIter
Type for iterator over neighbours of vertex descriptor.
Definition: base_graph.hpp:77
Definition: base_graph_impl.hpp:18