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