IndexedGraph.h
Go to the documentation of this file.
1 /*
2  * A graph templated on vertex type which is indexed by instances of
3  * that type. That is, unlike the underlying boost graph that it uses
4  * you can treat a vertex as if it was an instance instead of going
5  * through boost vertex descriptors (numbers) and vertex properties.
6  *
7  * To do this, a mapping is used so it will slow down operation. Any
8  * graph operations can still make use of boost implementations.
9  *
10  * See test_indexedgraph.cxx
11  */
12 
13 #ifndef WIRECELL_INDEXEDGRAPH
14 #define WIRECELL_INDEXEDGRAPH
15 
16 
17 #include <boost/graph/connected_components.hpp>
18 #include <boost/graph/graph_traits.hpp>
19 #include <boost/graph/adjacency_list.hpp>
20 #include <boost/graph/copy.hpp>
21 
22 #include <unordered_set>
23 #include <set>
24 #include <variant> // C++17
25 
26 
27 namespace WireCell {
28 
29  // VertexType must be hashable.
30  template <typename VertexType>
31  class IndexedGraph {
32  public:
33  typedef VertexType vertex_t;
34  // The underlying graph inherently does not allow parallel
35  // edges (setS). It technically allows duplicate vertices
36  // (vecS) but that is assured not to happen by IndexedGraph
37  // and vecS is faster. However, it also means that removing
38  // vertices must NOT be performed. At all. Don't try it. If
39  // you need a smaller graph, make it with the nodes you want
40  // to keep. Seriously, don't call remove(). I know you want
41  // to, just don't.
42  typedef boost::adjacency_list<boost::setS, boost::vecS,
43  boost::undirectedS,
44  vertex_t> graph_t;
45  typedef typename boost::graph_traits<graph_t>::vertex_descriptor vdesc_t;
46  typedef typename boost::graph_traits<graph_t>::edge_descriptor edesc_t;
47 
49 
50  IndexedGraph(const graph_t& g) {
51 
52  // can't do straight copy() with setS unless give vertex index map.
53  typedef std::unordered_map<vdesc_t, size_t> vertex_map_t;
54  vertex_map_t vmap;
55  boost::associative_property_map<vertex_map_t> pmapindx(vmap);
56  int count = 0;
57  for (auto v : boost::make_iterator_range(boost::vertices(g))) {
58  boost::put(pmapindx, v, count++);
59  }
60  boost::copy_graph(g, m_graph, boost::vertex_index_map( pmapindx ) );
61 
62  // make index
63  for (auto v : boost::make_iterator_range(boost::vertices(m_graph))) {
64  m_index[m_graph[v]] = v;
65  }
66  }
67 
68  // return vertex objects connected to the vertex of given object.
69  std::vector<vertex_t> neighbors(vertex_t obj) const {
70  std::vector<vertex_t> ret;
71  auto it = m_index.find(obj);
72  if (it == m_index.end()) {
73  return ret;
74  }
75  vdesc_t vd = it->second;
76  for (auto edge : boost::make_iterator_range(boost::out_edges(vd, m_graph))) {
77  vdesc_t neigh = boost::target(edge, m_graph);
78  ret.push_back(m_graph[neigh]);
79  }
80  return ret;
81  }
82 
83  // return true if graph has vertex object
84  bool has(vertex_t vobj) const {
85  auto it = m_index.find(vobj);
86  if (it == m_index.end()) {
87  return false;
88  }
89  return true;
90  }
91 
92  // Add edge between two objects, return underlying edge descriptor.
93  edesc_t edge(vertex_t vobj1, vertex_t vobj2) {
94  vdesc_t v1 = vertex(vobj1);
95  vdesc_t v2 = vertex(vobj2);
96  auto ret = boost::add_edge(v1, v2, m_graph);
97  return ret.first;
98  }
99 
100  // Add vertex object, return underlying vertex descriptor.
101  vdesc_t vertex(vertex_t vobj) {
102  auto it = m_index.find(vobj);
103  if (it != m_index.end()) {
104  return it->second;
105  }
106  vdesc_t vd = boost::add_vertex(vobj, m_graph);
107  m_index[vobj] = vd;
108  return vd;
109  }
110 
111  // Replace old vertex object with new one. It does not change
112  // the graph topology.
113  vdesc_t replace(vertex_t vold, vertex_t vnew) {
114  auto vd = vertex(vold);
115  m_graph[vd] = vnew;
116  m_index[vnew] = vd;
117  return vd;
118  }
119 
120  // clear index and graph.
121  void clear() {
122  m_index.clear();
123  m_graph.clear();
124  }
125 
126 
127  /// Return connected component subgraphs.
128  typedef std::unordered_map<int, std::vector<vertex_t> > vertex_grouping_t;
129  vertex_grouping_t groups() {
130  std::unordered_map<vdesc_t, int> stripes;
131  boost::connected_components(m_graph,
132  boost::make_assoc_property_map(stripes));
133  vertex_grouping_t ret;
134  for (auto& vg : stripes) { // invert
135  ret[vg.second].push_back(m_graph[vg.first]);
136  }
137  return ret;
138  }
139 
140  // Access underlying Boost graph, read-only.
141  const graph_t& graph() const { return m_graph; }
142 
143  // Mutable access. Any changes made will NOT be reflected in
144  // the index.
145  graph_t& graph() { return m_graph; }
146 
147 
148 
149  typedef std::unordered_map<vertex_t, vdesc_t> index_t;
150  index_t& index() { return m_index; }
151  const index_t& index() const { return m_index; }
152 
153  private:
154  graph_t m_graph;
155  index_t m_index;
156  };
157 
158 }
159 
160 #endif
std::unordered_map< int, std::vector< vertex_t > > vertex_grouping_t
Return connected component subgraphs.
Definition: IndexedGraph.h:128
std::vector< vertex_t > neighbors(vertex_t obj) const
Definition: IndexedGraph.h:69
const index_t & index() const
Definition: IndexedGraph.h:151
IndexedGraph(const graph_t &g)
Definition: IndexedGraph.h:50
const graph_t & graph() const
Definition: IndexedGraph.h:141
boost::graph_traits< graph_t >::vertex_descriptor vdesc_t
Definition: IndexedGraph.h:45
void put(Configuration &cfg, const std::string &dotpath, const T &val)
Put value in configuration at the dotted path.
static const double g
Definition: Units.h:145
vdesc_t vertex(vertex_t vobj)
Definition: IndexedGraph.h:101
boost::adjacency_list< boost::setS, boost::vecS, boost::undirectedS, vertex_t > graph_t
Definition: IndexedGraph.h:44
vertex_grouping_t groups()
Definition: IndexedGraph.h:129
Definition: Main.h:22
vdesc_t replace(vertex_t vold, vertex_t vnew)
Definition: IndexedGraph.h:113
boost::graph_traits< graph_t >::edge_descriptor edesc_t
Definition: IndexedGraph.h:46
edesc_t edge(vertex_t vobj1, vertex_t vobj2)
Definition: IndexedGraph.h:93
bool has(vertex_t vobj) const
Definition: IndexedGraph.h:84
std::unordered_map< vertex_t, vdesc_t > index_t
Definition: IndexedGraph.h:149