andres::graph
lifted/greedy-additive.hxx
1 #pragma once
2 #ifndef ANDRES_GRAPH_MULTICUT_LIFTED_GREEDY_ADDITIVE_HXX
3 #define ANDRES_GRAPH_MULTICUT_LIFTED_GREEDY_ADDITIVE_HXX
4 
5 #include <cstddef>
6 #include <iterator>
7 #include <vector>
8 #include <algorithm>
9 #include <map>
10 #include <queue>
11 
12 #include "andres/partition.hxx"
13 
14 namespace andres {
15 namespace graph {
16 namespace multicut_lifted {
17 
19 template<typename ORIGGRAPH, typename LIFTGRAPH, typename EVA, typename ELA>
21  const ORIGGRAPH& original_graph,
22  const LIFTGRAPH& lifted_graph,
23  EVA const& edge_values,
24  ELA& edge_labels
25 ) {
26  class DynamicGraph {
27  public:
28  DynamicGraph(size_t n)
29  : vertices_(n)
30  {}
31  bool edgeExists(size_t a, size_t b) const
32  {
33  return !vertices_[a].empty() && vertices_[a].find(b) != vertices_[a].end();
34  }
35  std::map<size_t, typename EVA::value_type> const& getAdjacentVertices(size_t v) const
36  {
37  return vertices_[v];
38  }
39  typename EVA::value_type getEdgeWeight(size_t a, size_t b) const
40  {
41  return vertices_[a].at(b);
42  }
43  void removeVertex(size_t v)
44  {
45  for (auto& p : vertices_[v])
46  vertices_[p.first].erase(v);
47 
48  vertices_[v].clear();
49  }
50  void setEdgeWeight(size_t a, size_t b, typename EVA::value_type w)
51  {
52  vertices_[a][b] = w;
53  vertices_[b][a] = w;
54  }
55 
56  private:
57  std::vector<std::map<size_t, typename EVA::value_type>> vertices_;
58  };
59 
60  struct Edge {
61  Edge(size_t _a, size_t _b, typename EVA::value_type _w)
62  {
63  if (_a > _b)
64  std::swap(_a, _b);
65 
66  a = _a;
67  b = _b;
68 
69  w = _w;
70  }
71 
72  size_t a;
73  size_t b;
74  size_t edition;
75  typename EVA::value_type w;
76 
77  bool operator <(Edge const& other) const
78  { return w < other.w; }
79  };
80 
81  std::vector<std::map<size_t, size_t>> edge_editions(original_graph.numberOfVertices());
82  DynamicGraph original_graph_cp(original_graph.numberOfVertices());
83  DynamicGraph lifted_graph_cp(original_graph.numberOfVertices());
84  std::priority_queue<Edge> Q;
85 
86  for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) {
87  auto a = original_graph.vertexOfEdge(i, 0);
88  auto b = original_graph.vertexOfEdge(i, 1);
89 
90  original_graph_cp.setEdgeWeight(a, b, 1.);
91  }
92 
93  for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) {
94  auto a = lifted_graph.vertexOfEdge(i, 0);
95  auto b = lifted_graph.vertexOfEdge(i, 1);
96 
97  lifted_graph_cp.setEdgeWeight(a, b, edge_values[i]);
98 
99  if (original_graph_cp.edgeExists(a, b)) {
100  auto e = Edge(a, b, edge_values[i]);
101  e.edition = ++edge_editions[e.a][e.b];
102 
103  Q.push(e);
104  }
105  }
106 
107  andres::Partition<size_t> partition(original_graph.numberOfVertices());
108 
109  while (!Q.empty()) {
110  auto edge = Q.top();
111  Q.pop();
112 
113  if (!original_graph_cp.edgeExists(edge.a, edge.b) || edge.edition < edge_editions[edge.a][edge.b])
114  continue;
115 
116  if (edge.w < typename EVA::value_type())
117  break;
118 
119  auto stable_vertex = edge.a;
120  auto merge_vertex = edge.b;
121 
122  if (lifted_graph_cp.getAdjacentVertices(stable_vertex).size() < lifted_graph_cp.getAdjacentVertices(merge_vertex).size())
123  std::swap(stable_vertex, merge_vertex);
124 
125  partition.merge(stable_vertex, merge_vertex);
126 
127  for (auto& p : original_graph_cp.getAdjacentVertices(merge_vertex)) {
128  if (p.first == stable_vertex)
129  continue;
130 
131  original_graph_cp.setEdgeWeight(stable_vertex, p.first, 1.);
132  }
133 
134  original_graph_cp.removeVertex(merge_vertex);
135 
136  for (auto& p : lifted_graph_cp.getAdjacentVertices(merge_vertex)) {
137  if (p.first == stable_vertex)
138  continue;
139 
140  auto t = typename EVA::value_type();
141 
142  if (lifted_graph_cp.edgeExists(stable_vertex, p.first))
143  t = lifted_graph_cp.getEdgeWeight(stable_vertex, p.first);
144 
145  lifted_graph_cp.setEdgeWeight(stable_vertex, p.first, p.second + t);
146 
147  if (original_graph_cp.edgeExists(stable_vertex, p.first)) {
148  auto e = Edge(stable_vertex, p.first, p.second + t);
149  e.edition = ++edge_editions[e.a][e.b];
150 
151  Q.push(e);
152  }
153  }
154 
155  lifted_graph_cp.removeVertex(merge_vertex);
156  }
157 
158  for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i)
159  edge_labels[i] = partition.find(lifted_graph.vertexOfEdge(i, 0)) == partition.find(lifted_graph.vertexOfEdge(i, 1)) ? 0 : 1;
160 }
161 
162 } // namespace multicut_lifted
163 } // namespace graph
164 } // namespace andres
165 
166 #endif // #ifndef ANDRES_GRAPH_MULTICUT_LIFTED_GREEDY_ADDITIVE_HXX