ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
graph_cut.cc
Go to the documentation of this file.
1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 // its contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #include "base/graph_cut.h"
33 
34 #include <unordered_map>
35 
36 #include <boost/graph/stoer_wagner_min_cut.hpp>
37 #include <boost/property_map/property_map.hpp>
38 #include <boost/typeof/typeof.hpp>
39 
40 extern "C" {
41 #include "Graclus/metisLib/metis.h"
42 }
43 
44 #include "util/logging.h"
45 
46 namespace colmap {
47 namespace {
48 
49 // Wrapper class for weighted, undirected Graclus graph.
50 class GraclusGraph {
51  public:
52  GraclusGraph(const std::vector<std::pair<int, int>>& edges,
53  const std::vector<int>& weights) {
54  CHECK_EQ(edges.size(), weights.size());
55 
56  std::unordered_map<int, std::vector<std::pair<int, int>>> adjacency_list;
57  for (size_t i = 0; i < edges.size(); ++i) {
58  const auto& edge = edges[i];
59  const auto weight = weights[i];
60  const int vertex_idx1 = GetVertexIdx(edge.first);
61  const int vertex_idx2 = GetVertexIdx(edge.second);
62  adjacency_list[vertex_idx1].emplace_back(vertex_idx2, weight);
63  adjacency_list[vertex_idx2].emplace_back(vertex_idx1, weight);
64  }
65 
66  xadj_.reserve(vertex_id_to_idx_.size() + 1);
67  adjncy_.reserve(2 * edges.size());
68  adjwgt_.reserve(2 * edges.size());
69 
70  idxtype edge_idx = 0;
71  for (size_t i = 0; i < vertex_id_to_idx_.size(); ++i) {
72  xadj_.push_back(edge_idx);
73 
74  if (adjacency_list.count(i) == 0) {
75  continue;
76  }
77 
78  for (const auto& edge : adjacency_list[i]) {
79  edge_idx += 1;
80  adjncy_.push_back(edge.first);
81  adjwgt_.push_back(edge.second);
82  }
83  }
84 
85  xadj_.push_back(edge_idx);
86 
87  CHECK_EQ(edge_idx, 2 * edges.size());
88  CHECK_EQ(xadj_.size(), vertex_id_to_idx_.size() + 1);
89  CHECK_EQ(adjncy_.size(), 2 * edges.size());
90  CHECK_EQ(adjwgt_.size(), 2 * edges.size());
91 
92  data.gdata = data.rdata = nullptr;
93 
94  data.nvtxs = vertex_id_to_idx_.size();
95  data.nedges = 2 * edges.size();
96  data.mincut = data.minvol = -1;
97 
98  data.xadj = xadj_.data();
99  data.adjncy = adjncy_.data();
100 
101  data.vwgt = nullptr;
102  data.adjwgt = adjwgt_.data();
103 
104  data.adjwgtsum = nullptr;
105  data.label = nullptr;
106  data.cmap = nullptr;
107 
108  data.where = data.pwgts = nullptr;
109  data.id = data.ed = nullptr;
110  data.bndptr = data.bndind = nullptr;
111  data.rinfo = nullptr;
112  data.vrinfo = nullptr;
113  data.nrinfo = nullptr;
114 
115  data.ncon = 1;
116  data.nvwgt = nullptr;
117  data.npwgts = nullptr;
118 
119  data.vsize = nullptr;
120 
121  data.coarser = data.finer = nullptr;
122  }
123 
124  int GetVertexIdx(const int id) {
125  const auto it = vertex_id_to_idx_.find(id);
126  if (it == vertex_id_to_idx_.end()) {
127  const int idx = vertex_id_to_idx_.size();
128  vertex_id_to_idx_.emplace(id, idx);
129  vertex_idx_to_id_.emplace(idx, id);
130  return idx;
131  } else {
132  return it->second;
133  }
134  }
135 
136  int GetVertexId(const int idx) { return vertex_idx_to_id_.at(idx); }
137 
138  GraphType data;
139 
140  private:
141  std::unordered_map<int, int> vertex_id_to_idx_;
142  std::unordered_map<int, int> vertex_idx_to_id_;
143  std::vector<idxtype> xadj_;
144  std::vector<idxtype> adjncy_;
145  std::vector<idxtype> adjwgt_;
146 };
147 
148 } // namespace
149 
151  const std::vector<std::pair<int, int>>& edges,
152  const std::vector<int>& weights, int* cut_weight,
153  std::vector<char>* cut_labels) {
154  CHECK_EQ(edges.size(), weights.size());
155  CHECK_GE(edges.size(), 2);
156 
157  typedef boost::property<boost::edge_weight_t, int> edge_weight_t;
158  typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
159  boost::no_property, edge_weight_t>
160  undirected_graph_t;
161 
162  int max_vertex_index = 0;
163  for (const auto& edge : edges) {
164  CHECK_GE(edge.first, 0);
165  CHECK_GE(edge.second, 0);
166  max_vertex_index = std::max(max_vertex_index, edge.first);
167  max_vertex_index = std::max(max_vertex_index, edge.second);
168  }
169 
170  const undirected_graph_t graph(edges.begin(), edges.end(), weights.begin(),
171  max_vertex_index + 1, edges.size());
172 
173  const auto parities = boost::make_one_bit_color_map(
174  boost::num_vertices(graph), boost::get(boost::vertex_index, graph));
175 
176  *cut_weight =
177  boost::stoer_wagner_min_cut(graph, boost::get(boost::edge_weight, graph),
178  boost::parity_map(parities));
179 
180  cut_labels->resize(boost::num_vertices(graph));
181  for (size_t i = 0; i < boost::num_vertices(graph); ++i) {
182  (*cut_labels)[i] = boost::get(parities, i);
183  }
184 }
185 
186 std::unordered_map<int, int> ComputeNormalizedMinGraphCut(
187  const std::vector<std::pair<int, int>>& edges,
188  const std::vector<int>& weights, const int num_parts) {
189  GraclusGraph graph(edges, weights);
190 
191  const int levels =
192  amax((graph.data.nvtxs) / (40 * log2_metis(num_parts)), 20 * (num_parts));
193 
194  std::vector<idxtype> cut_labels(graph.data.nvtxs);
195 
196  int options[11];
197  options[0] = 0;
198  int wgtflag = 1;
199  int numflag = 0;
200  int chain_length = 0;
201  int edgecut;
202  int var_num_parts = num_parts;
203 
204  MLKKM_PartGraphKway(&graph.data.nvtxs, graph.data.xadj, graph.data.adjncy,
205  graph.data.vwgt, graph.data.adjwgt, &wgtflag, &numflag,
206  &var_num_parts, &chain_length, options, &edgecut,
207  cut_labels.data(), levels);
208 
209  float lbvec[MAXNCON];
210  ComputePartitionBalance(&graph.data, num_parts, cut_labels.data(), lbvec);
211 
212  ComputeNCut(&graph.data, &cut_labels[0], num_parts);
213 
214  std::unordered_map<int, int> labels;
215  for (size_t idx = 0; idx < cut_labels.size(); ++idx) {
216  labels.emplace(graph.GetVertexId(idx), cut_labels[idx]);
217  }
218 
219  return labels;
220 }
221 
222 } // namespace colmap
long vertex_index
GraphType data
Definition: graph_cut.cc:138
std::unordered_map< int, int > ComputeNormalizedMinGraphCut(const std::vector< std::pair< int, int >> &edges, const std::vector< int > &weights, const int num_parts)
Definition: graph_cut.cc:186
void ComputeMinGraphCutStoerWagner(const std::vector< std::pair< int, int >> &edges, const std::vector< int > &weights, int *cut_weight, std::vector< char > *cut_labels)
Definition: graph_cut.cc:150