2 #ifndef ANDRES_GRAPH_MULTICUT_KERNIGHAN_LIN_HXX
3 #define ANDRES_GRAPH_MULTICUT_KERNIGHAN_LIN_HXX
8 #include <unordered_set>
11 #include "andres/graph/components.hxx"
12 #include "andres/graph/twocut/kernighan-lin.hxx"
22 size_t numberOfInnerIterations { std::numeric_limits<size_t>::max() };
23 size_t numberOfOuterIterations { 100 };
24 double epsilon { 1e-7 };
25 bool verbose {
true };
28 template<
typename GRAPH,
typename ECA,
typename ELA>
34 bool operator()(std::vector<size_t>& vertex_labels)
const
40 kernighanLin(graph, edgeCosts, inputLabels, outputLabels, visitor, settings);
43 template<
typename GRAPH,
typename ECA,
typename ELA,
typename VIS>
45 void kernighanLin(
const GRAPH& graph,
const ECA& edgeCosts,
const ELA& inputLabels, ELA& outputLabels, VIS& visitor,
const Settings settings =
Settings())
47 struct SubgraphWithCut {
48 SubgraphWithCut(
const ELA& labels)
50 bool vertex(
const size_t v)
const
52 bool edge(
const size_t e)
const
53 {
return labels_[e] == 0; }
60 components.
build(graph, SubgraphWithCut(inputLabels));
62 double starting_energy = .0;
65 for(
size_t edge = 0; edge < graph.numberOfEdges(); ++edge)
67 outputLabels[edge] = inputLabels[edge];
69 auto v0 = graph.vertexOfEdge(edge, 0);
70 auto v1 = graph.vertexOfEdge(edge, 1);
72 if (inputLabels[edge])
73 starting_energy += 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 auto twocut_buffers = twocut::makeTwoCutBuffers(graph);
83 twocut::TwoCutSettings twocut_settings;
84 twocut_settings.numberOfIterations = settings.numberOfInnerIterations;
85 twocut_settings.epsilon = settings.epsilon;
88 std::vector<std::vector<size_t>> partitions(numberOfComponents);
90 for (
size_t i = 0; i < components.
labels_.size(); ++i)
92 partitions[components.
labels_[i]].push_back(i);
93 twocut_buffers.vertex_labels[i] = components.
labels_[i];
96 twocut_buffers.max_not_used_label = partitions.size();
100 std::cout <<
"Starting energy: " << starting_energy << std::endl;
101 std::cout << std::setw(4) <<
"Iter" << std::setw(16) <<
"Total decrease" << std::setw(15) <<
"Pair updates" << std::setw(15) <<
"New sets" << std::setw(15) <<
"Num. of sets\n";
104 auto last_good_vertex_labels = twocut_buffers.vertex_labels;
107 std::vector<char> visited(graph.numberOfVertices());
110 std::vector<char> changed(numberOfComponents, 1);
113 for (
size_t k = 0; k < settings.numberOfOuterIterations; ++k)
115 auto energy_decrease = .0;
117 std::vector<std::unordered_set<size_t>> edges(numberOfComponents);
118 for (
size_t e = 0; e < graph.numberOfEdges(); ++e)
121 auto v0 = twocut_buffers.vertex_labels[graph.vertexOfEdge(e, 0)];
122 auto v1 = twocut_buffers.vertex_labels[graph.vertexOfEdge(e, 1)];
124 edges[std::min(v0, v1)].insert(std::max(v0, v1));
127 for (
size_t i = 0; i < numberOfComponents; ++i)
128 if (!partitions[i].empty())
129 for (
auto j : edges[i])
130 if (!partitions[j].empty() && (changed[j] || changed[i]))
132 auto ret =
twocut::kernighanLin(graph, edgeCosts, partitions[i], partitions[j], twocut_buffers, twocut_settings);
134 if (ret > settings.epsilon)
135 changed[i] = changed[j] = 1;
137 energy_decrease += ret;
139 if (partitions[i].size() == 0)
143 auto ee = energy_decrease;
146 auto new_end = std::partition(partitions.begin(), partitions.end(), [](
const std::vector<size_t>& s) {
return !s.empty(); });
147 partitions.resize(new_end - partitions.begin());
150 for (
size_t i = 0, p_size = partitions.size(); i < p_size; ++i)
159 std::vector<size_t> new_set;
160 energy_decrease +=
twocut::kernighanLin(graph, edgeCosts, partitions[i], new_set, twocut_buffers, twocut_settings);
162 flag = !new_set.empty();
164 if (!new_set.empty())
165 partitions.emplace_back(std::move(new_set));
169 if (!visitor(twocut_buffers.vertex_labels))
172 if (energy_decrease == .0)
175 std::stack<size_t> S;
177 std::fill(visited.begin(), visited.end(), 0);
180 numberOfComponents = 0;
183 for (
size_t i = 0; i < graph.numberOfVertices(); ++i)
189 auto label = twocut_buffers.vertex_labels[i];
191 twocut_buffers.referenced_by[i] = numberOfComponents;
193 partitions.emplace_back(std::vector<size_t>());
194 partitions.back().push_back(i);
201 for (
auto it = graph.adjacenciesFromVertexBegin(v); it != graph.adjacenciesFromVertexEnd(v); ++it)
202 if (twocut_buffers.vertex_labels[it->vertex()] == label && !visited[it->vertex()])
204 S.push(it->vertex());
205 visited[it->vertex()] = 1;
206 twocut_buffers.referenced_by[it->vertex()] = numberOfComponents;
207 partitions.back().push_back(it->vertex());
211 ++numberOfComponents;
214 twocut_buffers.vertex_labels = twocut_buffers.referenced_by;
216 twocut_buffers.max_not_used_label = numberOfComponents;
218 bool didnt_change =
true;
219 for (
size_t i = 0; i < graph.numberOfEdges(); ++i)
221 auto v0 = graph.vertexOfEdge(i, 0);
222 auto v1 = graph.vertexOfEdge(i, 1);
224 outputLabels[i] = twocut_buffers.vertex_labels[v0] == twocut_buffers.vertex_labels[v1] ? 0 : 1;
226 if (static_cast<bool>(outputLabels[i]) != (last_good_vertex_labels[v0] != last_good_vertex_labels[v1]))
227 didnt_change =
false;
234 changed.resize(numberOfComponents);
235 std::fill(changed.begin(), changed.end(), 0);
237 std::fill(visited.begin(), visited.end(), 0);
239 for (
size_t i = 0; i < graph.numberOfVertices(); ++i)
245 auto label_new = twocut_buffers.vertex_labels[i];
246 auto label_old = last_good_vertex_labels[i];
253 for (
auto w = graph.verticesFromVertexBegin(v); w != graph.verticesFromVertexEnd(v); ++w)
255 if (last_good_vertex_labels[*w] == label_old && twocut_buffers.vertex_labels[*w] != label_new)
256 changed[label_new] = 1;
261 if (twocut_buffers.vertex_labels[*w] == label_new)
266 if (last_good_vertex_labels[*w] != label_old)
267 changed[label_new] = 1;
273 last_good_vertex_labels = twocut_buffers.vertex_labels;
275 if (settings.verbose)
276 std::cout << std::setw(4) << k+1 << std::setw(16) << energy_decrease << std::setw(15) << ee << std::setw(15) << (energy_decrease - ee) << std::setw(14) << partitions.size() << std::endl;
280 template<
typename GraphVisitor,
typename ECA,
typename ELA>
286 bool operator()(ELA
const& edge_labels)
const
292 kernighanLin(graph, edgeCosts, inputLabels, outputLabels, visitor, settings);
295 template<
typename GraphVisitor,
typename ECA,
typename ELA,
typename VIS>
299 struct SubgraphWithCut {
300 SubgraphWithCut(
const ELA& labels)
302 bool vertex(
const size_t v)
const
304 bool edge(
const size_t e)
const
305 {
return labels_[e] == 0; }
312 components.
build(graph, SubgraphWithCut(inputLabels));
314 double starting_energy = .0;
322 if (inputLabels[edge])
323 starting_energy += edgeCosts[edge];
325 if (static_cast<bool>(inputLabels[edge]) != !components.
areConnected(v0, v1))
326 throw std::runtime_error(
"the input multicut labeling is invalid.");
329 auto numberOfComponents = *std::max_element(components.
labels_.begin(), components.
labels_.end()) + 1;
331 std::vector<std::vector<size_t>> partitions(numberOfComponents);
333 auto twocut_buffers = twocut::makeTwoCutBuffers(graph);
335 twocut::TwoCutSettings twocut_settings;
336 twocut_settings.numberOfIterations = settings.numberOfInnerIterations;
337 twocut_settings.epsilon = settings.epsilon;
340 for (
size_t i = 0; i < components.
labels_.size(); ++i)
341 partitions[components.
labels_[i]].push_back(i);
343 if (settings.verbose)
345 std::cout <<
"Starting energy: " << starting_energy << std::endl;
346 std::cout << std::setw(4) <<
"Iter" << std::setw(16) <<
"Total decrease" << std::setw(15) <<
"Pair updates" << std::setw(15) <<
"New sets" << std::setw(15) <<
"Num. of sets\n";
350 for (
size_t k = 0; k < settings.numberOfOuterIterations; ++k)
352 auto energy_decrease = .0;
355 for (
size_t i = 0; i < partitions.size() - 1; ++i)
356 for (
auto j = i + 1; j < partitions.size(); ++j)
357 if (!partitions[j].empty())
358 energy_decrease += twocut::kernighanLin(graph, edgeCosts, partitions[i], partitions[j], twocut_buffers, twocut_settings);
361 auto new_end = std::partition(partitions.begin(), partitions.end(), [](
const std::vector<size_t>& s) {
return !s.empty(); });
362 partitions.resize(new_end - partitions.begin());
364 auto ee = energy_decrease;
367 for (
size_t i = 0, p_size = partitions.size(); i < p_size; ++i)
370 std::vector<size_t> new_set;
371 energy_decrease +=
twocut::kernighanLin(graph, edgeCosts, partitions[i], new_set, twocut_buffers, twocut_settings);
373 if (!new_set.empty())
374 partitions.emplace_back(std::move(new_set));
379 if (energy_decrease == .0)
382 for (
size_t i = 0; i < partitions.size(); ++i)
383 for (
size_t a = 0; a < partitions[i].size(); ++a)
385 for (
size_t b = a + 1; b < partitions[i].size(); ++b)
386 outputLabels[graph.
findEdge(partitions[i][a], partitions[i][b]).second] = 0;
388 for (
size_t j = i + 1; j < partitions.size(); ++j)
389 for (
auto b : partitions[j])
390 outputLabels[graph.
findEdge(partitions[i][a], b).second] = 1;
393 if (!visitor(outputLabels))
396 if (settings.verbose)
397 std::cout << std::setw(4) << k+1 << std::setw(16) << energy_decrease << std::setw(15) << ee << std::setw(15) << (energy_decrease - ee) << std::setw(14) << partitions.size() << std::endl;