| 184 | } |
| 185 | |
| 186 | std::unordered_map<int, int> ComputeNormalizedMinGraphCut( |
| 187 | const std::vector<std::pair<int, int>>& edges, |
| 188 | const std::vector<int>& weights, |
| 189 | const int num_parts) { |
| 190 | THROW_CHECK(!edges.empty()); |
| 191 | THROW_CHECK_EQ(edges.size(), weights.size()); |
| 192 | THROW_CHECK_GT(num_parts, 0); |
| 193 | |
| 194 | MetisGraph graph(edges, weights); |
| 195 | |
| 196 | idx_t ncon = 1; |
| 197 | idx_t edgecut = -1; |
| 198 | idx_t nparts = num_parts; |
| 199 | |
| 200 | idx_t metisOptions[METIS_NOPTIONS]; |
| 201 | METIS_SetDefaultOptions(metisOptions); |
| 202 | |
| 203 | std::vector<idx_t> cut_labels(graph.nvtxs, -1); |
| 204 | const int metisResult = METIS_PartGraphKway(&graph.nvtxs, |
| 205 | /*ncon=*/&ncon, |
| 206 | graph.xadj, |
| 207 | graph.adjncy, |
| 208 | /*vwgt=*/nullptr, |
| 209 | /*vsize=*/nullptr, |
| 210 | graph.adjwgt, |
| 211 | &nparts, |
| 212 | /*tpwgts=*/nullptr, |
| 213 | /*ubvec=*/nullptr, |
| 214 | metisOptions, |
| 215 | &edgecut, |
| 216 | cut_labels.data()); |
| 217 | |
| 218 | if (metisResult == METIS_ERROR_INPUT) { |
| 219 | LOG(FATAL_THROW) << "INTERNAL: Metis input error"; |
| 220 | } else if (metisResult == METIS_ERROR_MEMORY) { |
| 221 | LOG(FATAL_THROW) << "INTERNAL: Metis memory error"; |
| 222 | } else if (metisResult == METIS_ERROR) { |
| 223 | LOG(FATAL_THROW) << "INTERNAL: Metis 'some other type of error'"; |
| 224 | } |
| 225 | |
| 226 | std::unordered_map<int, int> labels; |
| 227 | for (size_t idx = 0; idx < cut_labels.size(); ++idx) { |
| 228 | labels.emplace(graph.GetVertexId(idx), cut_labels[idx]); |
| 229 | } |
| 230 | |
| 231 | return labels; |
| 232 | } |
| 233 | |
| 234 | } // namespace colmap |