2 #ifndef ANDRES_GRAPH_MULTICUT_LIFTED_KERNIGHAN_LIN_HXX
3 #define ANDRES_GRAPH_MULTICUT_LIFTED_KERNIGHAN_LIN_HXX
7 #include <unordered_set>
11 #include "andres/graph/components.hxx"
12 #include "andres/graph/twocut-lifted/kernighan-lin.hxx"
16 namespace multicut_lifted {
19 std::size_t numberOfInnerIterations { std::numeric_limits<std::size_t>::max() };
20 std::size_t numberOfOuterIterations { 100 };
21 double epsilon { 1e-7 };
22 bool verbose {
true };
25 template<
typename ORIGINAL_GRAPH,
typename LIFTED_GRAPH,
typename ECA,
typename ELA,
typename VIS>
28 const ORIGINAL_GRAPH& original_graph,
29 const LIFTED_GRAPH& lifted_graph,
31 const ELA& inputLabels,
36 struct SubgraphWithCut {
37 SubgraphWithCut(
const ELA& labels, std::vector<std::size_t>
const& edge_in_lifted_graph)
38 : labels_(labels), edge_in_lifted_graph_(edge_in_lifted_graph)
40 bool vertex(
const std::size_t v)
const
42 bool edge(
const std::size_t e)
const
43 {
return labels_[edge_in_lifted_graph_[e]] == 0; }
45 std::vector<std::size_t>
const& edge_in_lifted_graph_;
49 std::vector<std::size_t> edge_in_lifted_graph(original_graph.numberOfEdges());
50 for (std::size_t i = 0; i < original_graph.numberOfEdges(); ++i)
52 auto v0 = original_graph.vertexOfEdge(i, 0);
53 auto v1 = original_graph.vertexOfEdge(i, 1);
55 edge_in_lifted_graph[i] = lifted_graph.findEdge(v0, v1).second;
60 components.
build(original_graph, SubgraphWithCut(inputLabels, edge_in_lifted_graph));
62 double current_energy_value = .0;
65 for(std::size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge)
67 outputLabels[edge] = inputLabels[edge];
69 auto v0 = lifted_graph.vertexOfEdge(edge, 0);
70 auto v1 = lifted_graph.vertexOfEdge(edge, 1);
72 if (inputLabels[edge])
73 current_energy_value += edgeCosts[edge];
75 if (static_cast<bool>(inputLabels[edge]) != !components.
areConnected(v0, v1))
76 throw std::runtime_error(
"the input multicut labeling is invalid.");
79 auto numberOfComponents = *std::max_element(components.
labels_.begin(), components.
labels_.end()) + 1;
81 std::vector<std::vector<std::size_t>> partitions(numberOfComponents);
84 twocut_settings.numberOfIterations = settings.numberOfInnerIterations;
85 twocut_settings.epsilon = settings.epsilon;
90 for (std::size_t i = 0; i < components.
labels_.size(); ++i)
92 partitions[components.
labels_[i]].push_back(i);
100 std::cout <<
"Starting energy: " << current_energy_value << std::endl;
101 std::cout << std::setw(4) <<
"Iter" << std::setw(16) <<
"True decrease" << std::setw(15) <<
"Total decrease" << std::setw(15) <<
"Pair updates" << std::setw(15) <<
"New sets" << std::setw(15) <<
"Num. of sets\n";
106 std::vector<char> visited(original_graph.numberOfVertices());
109 std::vector<char> changed(numberOfComponents, 1);
112 for (std::size_t k = 0; k < settings.numberOfOuterIterations; ++k)
114 auto energy_decrease = .0;
116 std::vector<std::unordered_set<std::size_t>> edges(numberOfComponents);
117 for (std::size_t e = 0; e < original_graph.numberOfEdges(); ++e)
119 auto v0 = twocut_buffers.
vertex_labels[original_graph.vertexOfEdge(e, 0)];
120 auto v1 = twocut_buffers.
vertex_labels[original_graph.vertexOfEdge(e, 1)];
123 edges[std::min(v0, v1)].insert(std::max(v0, v1));
126 for (std::size_t i = 0; i < numberOfComponents && !visitor.time_limit_exceeded(); ++i)
127 if (!partitions[i].empty())
128 for (
auto j = edges[i].begin(); j != edges[i].end() && !visitor.time_limit_exceeded(); ++j)
129 if (!partitions[*j].empty() && (changed[*j] || changed[i]))
131 auto ret =
twocut_lifted::kernighanLin(original_graph, lifted_graph, edgeCosts, partitions[i], partitions[*j], twocut_buffers, twocut_settings);
133 if (ret > settings.epsilon)
134 changed[i] = changed[*j] = 1;
136 energy_decrease += ret;
138 if (partitions[i].size() == 0)
142 auto ee = energy_decrease;
145 auto new_end = std::partition(partitions.begin(), partitions.end(), [](
const std::vector<std::size_t>& s) {
return !s.empty(); });
146 partitions.resize(new_end - partitions.begin());
149 for (std::size_t i = 0, p_size = partitions.size(); i < p_size && !visitor.time_limit_exceeded(); ++i)
156 while (flag && !visitor.time_limit_exceeded())
158 std::vector<std::size_t> new_set;
159 energy_decrease +=
twocut_lifted::kernighanLin(original_graph, lifted_graph, edgeCosts, partitions[i], new_set, twocut_buffers, twocut_settings);
161 flag = !new_set.empty();
163 if (!new_set.empty())
164 partitions.emplace_back(std::move(new_set));
168 if (energy_decrease == .0)
171 std::stack<std::size_t> S;
173 std::fill(visited.begin(), visited.end(), 0);
176 numberOfComponents = 0;
177 for (std::size_t i = 0; i < original_graph.numberOfVertices(); ++i)
192 for (
auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it)
193 if (twocut_buffers.
vertex_labels[it->vertex()] == label && !visited[it->vertex()])
195 S.push(it->vertex());
196 visited[it->vertex()] = 1;
197 twocut_buffers.
referenced_by[it->vertex()] = numberOfComponents;
201 ++numberOfComponents;
205 double new_energy_value = .0;
206 for (std::size_t i = 0; i < lifted_graph.numberOfEdges(); ++i)
208 auto v0 = lifted_graph.vertexOfEdge(i, 0);
209 auto v1 = lifted_graph.vertexOfEdge(i, 1);
212 new_energy_value += edgeCosts[i];
216 if (new_energy_value >= current_energy_value - settings.epsilon)
218 for (std::size_t i = 0; i < lifted_graph.numberOfEdges(); ++i)
220 auto v0 = lifted_graph.vertexOfEdge(i, 0);
221 auto v1 = lifted_graph.vertexOfEdge(i, 1);
223 outputLabels[i] = last_good_vertex_labels[v0] == last_good_vertex_labels[v1] ? 0 : 1;
231 partitions.resize(numberOfComponents);
233 for (std::size_t i = 0; i < original_graph.numberOfVertices(); ++i)
242 bool didnt_change =
true;
243 for (std::size_t i = 0; i < lifted_graph.numberOfEdges(); ++i)
245 auto v0 = lifted_graph.vertexOfEdge(i, 0);
246 auto v1 = lifted_graph.vertexOfEdge(i, 1);
250 if (static_cast<bool>(outputLabels[i]) != (last_good_vertex_labels[v0] != last_good_vertex_labels[v1]))
251 didnt_change =
false;
259 changed.resize(numberOfComponents);
261 std::fill(visited.begin(), visited.end(), 0);
263 for (std::size_t i = 0; i < original_graph.numberOfVertices(); ++i)
270 auto label_old = last_good_vertex_labels[i];
277 for (
auto w = original_graph.verticesFromVertexBegin(v); w != original_graph.verticesFromVertexEnd(v); ++w)
279 if (last_good_vertex_labels[*w] == label_old && twocut_buffers.
vertex_labels[*w] != label_new)
280 changed[label_new] = 1;
290 if (last_good_vertex_labels[*w] != label_old)
291 changed[label_new] = 1;
299 if (!visitor(last_good_vertex_labels) || visitor.time_limit_exceeded())
302 if (settings.verbose)
303 std::cout << std::setw(4) << k+1 << std::setw(16) << current_energy_value - new_energy_value << std::setw(15) << energy_decrease << std::setw(15) << ee << std::setw(15) << (energy_decrease - ee) << std::setw(14) << partitions.size() << std::endl;
305 current_energy_value = new_energy_value;
309 template<
typename ORIGINAL_GRAPH,
typename LIFTED_GRAPH,
typename ECA,
typename ELA>
311 const ORIGINAL_GRAPH& original_graph,
312 const LIFTED_GRAPH& lifted_graph,
313 const ECA& edgeCosts,
314 const ELA& inputLabels,
319 constexpr
bool operator()(std::vector<std::size_t>& vertex_labels)
321 constexpr
bool time_limit_exceeded()
325 kernighanLin(original_graph, lifted_graph, edgeCosts, inputLabels, outputLabels, visitor, settings);