16#include <boost/tuple/tuple.hpp>
17#include <boost/shared_array.hpp>
21#include "FindSeparator.h"
31namespace gtsam {
namespace partition {
33 typedef boost::shared_array<idx_t> sharedInts;
42 std::pair<int, sharedInts> separatorMetis(idx_t n,
const sharedInts& xadj,
43 const sharedInts& adjncy,
const sharedInts& adjwgt,
bool verbose) {
46 std::vector<idx_t> vwgt;
47 idx_t options[METIS_NOPTIONS];
48 METIS_SetDefaultOptions(options);
50 sharedInts part_(
new idx_t[n]);
58 printf(
"**********************************************************************\n");
59 printf(
"Graph Information ---------------------------------------------------\n");
60 printf(
" #Vertices: %d, #Edges: %u\n", n, *(xadj.get()+n) / 2);
61 printf(
"\nND Partitioning... -------------------------------------------\n");
66 METIS_ComputeVertexSeparator(&n, xadj.get(), adjncy.get(),
67 &vwgt[0], options, &sepsize, part_.get());
73 printf(
" Sep size: \t\t %d\n", sepsize);
74 printf(
"**********************************************************************\n");
77 return std::make_pair(sepsize, part_);
81 void modefied_EdgeComputeSeparator(idx_t *nvtxs, idx_t *xadj, idx_t *adjncy, idx_t *vwgt,
82 idx_t *adjwgt, idx_t *options, idx_t *edgecut, idx_t *part)
88 ctrl = SetupCtrl(METIS_OP_OMETIS, options, 1, 3,
nullptr,
nullptr);
89 ctrl->iptype = METIS_IPTYPE_GROW;
93 InitRandom(ctrl->seed);
95 graph = SetupGraph(ctrl, *nvtxs, 1, xadj, adjncy, vwgt,
nullptr,
nullptr);
97 AllocateWorkSpace(ctrl, graph);
105 tpwgts2 = rwspacemalloc(ctrl, 2*ncon);
106 for (i=0; i<ncon; i++) {
107 tpwgts2[i] = rsum((2>>1), ctrl->tpwgts+i, ncon);
108 tpwgts2[ncon+i] = 1.0 - tpwgts2[i];
111 *edgecut = MultilevelBisect(ctrl, graph, tpwgts2);
116 icopy(*nvtxs, graph->where, part);
117 std::cout <<
"Finished bisection:" << *edgecut << std::endl;
129 std::pair<int, sharedInts> edgeMetis(idx_t n,
const sharedInts& xadj,
const sharedInts& adjncy,
130 const sharedInts& adjwgt,
bool verbose) {
133 std::vector<idx_t> vwgt;
134 idx_t options[METIS_NOPTIONS];
135 METIS_SetDefaultOptions(options);
137 sharedInts part_(
new idx_t[n]);
145 printf(
"**********************************************************************\n");
146 printf(
"Graph Information ---------------------------------------------------\n");
147 printf(
" #Vertices: %d, #Edges: %u\n", n, *(xadj.get()+n) / 2);
148 printf(
"\nND Partitioning... -------------------------------------------\n");
156 modefied_EdgeComputeSeparator(&n, xadj.get(), adjncy.get(), &vwgt[0], adjwgt.get(),
157 options, &edgecut, part_.get());
162 printf(
"\nTiming Information --------------------------------------------------\n");
164 printf(
" Edge cuts: \t\t %d\n", edgecut);
165 printf(
"**********************************************************************\n");
168 return std::make_pair(edgecut, part_);
177 template <
class GenericGraph>
178 void prepareMetisGraph(
const GenericGraph& graph,
const std::vector<size_t>& keys,
WorkSpace& workspace,
179 sharedInts* ptr_xadj, sharedInts* ptr_adjncy, sharedInts* ptr_adjwgt) {
181 typedef std::vector<int> Weights;
182 typedef std::vector<int> Neighbors;
183 typedef std::pair<Neighbors, Weights> NeighborsInfo;
186 std::vector<int>& dictionary = workspace.dictionary;
187 workspace.prepareDictionary(keys);
190 int numNodes = keys.size();
192 std::vector<NeighborsInfo> adjacencyMap;
193 adjacencyMap.resize(numNodes);
194 std::cout <<
"Number of nodes: " << adjacencyMap.size() << std::endl;
197 for(
const typename GenericGraph::value_type& factor: graph){
198 index1 = dictionary[factor->key1.index];
199 index2 = dictionary[factor->key2.index];
200 std::cout <<
"index1: " << index1 << std::endl;
201 std::cout <<
"index2: " << index2 << std::endl;
203 if (index1 >= 0 && index2 >= 0) {
204 std::pair<Neighbors, Weights>& adjacencyMap1 = adjacencyMap[index1];
205 std::pair<Neighbors, Weights>& adjacencyMap2 = adjacencyMap[index2];
207 adjacencyMap1.first.push_back(index2);
208 adjacencyMap1.second.push_back(factor->weight);
209 adjacencyMap2.first.push_back(index1);
210 adjacencyMap2.second.push_back(factor->weight);
211 }
catch(std::exception& e){
212 std::cout << e.what() << std::endl;
219 *ptr_xadj = sharedInts(
new idx_t[numNodes+1]);
220 *ptr_adjncy = sharedInts(
new idx_t[numEdges*2]);
221 *ptr_adjwgt = sharedInts(
new idx_t[numEdges*2]);
222 sharedInts& xadj = *ptr_xadj;
223 sharedInts& adjncy = *ptr_adjncy;
224 sharedInts& adjwgt = *ptr_adjwgt;
225 int ind_xadj = 0, ind_adjncy = 0;
226 for(
const NeighborsInfo& info: adjacencyMap) {
227 *(xadj.get() + ind_xadj) = ind_adjncy;
228 std::copy(info.first .begin(), info.first .end(), adjncy.get() + ind_adjncy);
229 std::copy(info.second.begin(), info.second.end(), adjwgt.get() + ind_adjncy);
230 assert(info.first.size() == info.second.size());
231 ind_adjncy += info.first.size();
234 if (ind_xadj != numNodes)
throw std::runtime_error(
"prepareMetisGraph_: ind_xadj != numNodes");
235 *(xadj.get() + ind_xadj) = ind_adjncy;
239 template<
class GenericGraph>
240 boost::optional<MetisResult> separatorPartitionByMetis(
const GenericGraph& graph,
241 const std::vector<size_t>& keys,
WorkSpace& workspace,
bool verbose) {
243 size_t numKeys = keys.size();
245 std::cout << graph.size() <<
" factors,\t" << numKeys <<
" nodes;\t" << std::endl;
247 sharedInts xadj, adjncy, adjwgt;
249 prepareMetisGraph<GenericGraph>(graph, keys, workspace, &xadj, &adjncy, &adjwgt);
254 boost::tie(sepsize, part) = separatorMetis(numKeys, xadj, adjncy, adjwgt, verbose);
255 if (!sepsize)
return boost::optional<MetisResult>();
260 result.C.reserve(sepsize);
261 result.A.reserve(numKeys - sepsize);
262 result.B.reserve(numKeys - sepsize);
263 int* ptr_part = part.get();
264 std::vector<size_t>::const_iterator itKey = keys.begin();
265 std::vector<size_t>::const_iterator itKeyLast = keys.end();
266 while(itKey != itKeyLast) {
267 switch(*(ptr_part++)) {
268 case 0: result.A.push_back(*(itKey++));
break;
269 case 1: result.B.push_back(*(itKey++));
break;
270 case 2: result.C.push_back(*(itKey++));
break;
271 default:
throw std::runtime_error(
"separatorPartitionByMetis: invalid results from Metis ND!");
276 std::cout <<
"total key: " << keys.size()
277 <<
" result(A,B,C) = " << result.A.size() <<
", " << result.B.size() <<
", "
278 << result.C.size() <<
"; sepsize from Metis = " << sepsize << std::endl;
282 if(result.C.size() != sepsize) {
283 std::cout <<
"total key: " << keys.size()
284 <<
" result(A,B,C) = " << result.A.size() <<
", " << result.B.size() <<
", " << result.C.size()
285 <<
"; sepsize from Metis = " << sepsize << std::endl;
286 throw std::runtime_error(
"separatorPartitionByMetis: invalid sepsize from Metis ND!");
293 template<
class GenericGraph>
294 boost::optional<MetisResult> edgePartitionByMetis(
const GenericGraph& graph,
295 const std::vector<size_t>& keys,
WorkSpace& workspace,
bool verbose) {
298 if (graph.size() == 1 && keys.size() == 2) {
300 result.A.push_back(keys.front());
301 result.B.push_back(keys.back());
306 size_t numKeys = keys.size();
307 if (verbose) std::cout << graph.size() <<
" factors,\t" << numKeys <<
" nodes;\t" << std::endl;
308 sharedInts xadj, adjncy, adjwgt;
309 prepareMetisGraph<GenericGraph>(graph, keys, workspace, &xadj, &adjncy, &adjwgt);
314 boost::tie(edgecut, part) = edgeMetis(numKeys, xadj, adjncy, adjwgt, verbose);
318 result.A.reserve(numKeys);
319 result.B.reserve(numKeys);
320 int* ptr_part = part.get();
321 std::vector<size_t>::const_iterator itKey = keys.begin();
322 std::vector<size_t>::const_iterator itKeyLast = keys.end();
323 while(itKey != itKeyLast) {
324 if (*ptr_part != 0 && *ptr_part != 1)
325 std::cout << *ptr_part <<
"!!!" << std::endl;
326 switch(*(ptr_part++)) {
327 case 0: result.A.push_back(*(itKey++));
break;
328 case 1: result.B.push_back(*(itKey++));
break;
329 default:
throw std::runtime_error(
"edgePartitionByMetis: invalid results from Metis ND!");
334 std::cout <<
"the size of two submaps in the reduced graph: " << result.A.size()
335 <<
" " << result.B.size() << std::endl;
338 for(
const typename GenericGraph::value_type& factor: graph){
339 int key1 = factor->key1.index;
340 int key2 = factor->key2.index;
343 if (std::find(result.A.begin(), result.A.end(), key1) != result.A.end()) std::cout <<
"A ";
344 if (std::find(result.B.begin(), result.B.end(), key1) != result.B.end()) std::cout <<
"B ";
347 if (std::find(result.A.begin(), result.A.end(), key2) != result.A.end()) std::cout <<
"A ";
348 if (std::find(result.B.begin(), result.B.end(), key2) != result.B.end()) std::cout <<
"B ";
349 std::cout <<
"weight " << factor->weight;;
352 if ((std::find(result.A.begin(), result.A.end(), key1) != result.A.end() &&
353 std::find(result.B.begin(), result.B.end(), key2) != result.B.end()) ||
354 (std::find(result.B.begin(), result.B.end(), key1) != result.B.end() &&
355 std::find(result.A.begin(), result.A.end(), key2) != result.A.end())){
357 std::cout <<
" CUT ";
359 std::cout << std::endl;
361 std::cout <<
"edgeCut: " << edgeCut << std::endl;
368 bool isLargerIsland(
const std::vector<size_t>& island1,
const std::vector<size_t>& island2) {
369 return island1.size() > island2.size();
374 void printIsland(
const std::vector<size_t>& island) {
375 std::cout <<
"island: ";
376 for(
const size_t key: island)
377 std::cout << key <<
" ";
378 std::cout << std::endl;
381 void printIslands(
const std::list<std::vector<size_t> >& islands) {
382 for(
const std::vector<std::size_t>& island: islands)
386 void printNumCamerasLandmarks(
const std::vector<size_t>& keys,
const std::vector<Symbol>& int2symbol) {
387 int numCamera = 0, numLandmark = 0;
388 for(
const size_t key: keys)
389 if (int2symbol[key].chr() ==
'x')
393 std::cout <<
"numCamera: " << numCamera <<
" numLandmark: " << numLandmark << std::endl;
397 template<
class GenericGraph>
398 void addLandmarkToPartitionResult(
const GenericGraph& graph,
const std::vector<size_t>& landmarkKeys,
402 std::vector<size_t>& A = partitionResult.A;
403 std::vector<size_t>& B = partitionResult.B;
404 std::vector<size_t>& C = partitionResult.C;
405 std::vector<int>& dictionary = workspace.dictionary;
406 std::fill(dictionary.begin(), dictionary.end(), -1);
407 for(
const size_t a: A)
409 for(
const size_t b: B)
412 throw std::runtime_error(
"addLandmarkToPartitionResult: C is not empty");
416 for(
const typename GenericGraph::value_type& factor: graph) {
417 i = factor->key1.index;
418 j = factor->key2.index;
419 if (dictionary[j] == 0)
421 else if (dictionary[j] == -1)
422 dictionary[j] = dictionary[i];
424 if (dictionary[j] != dictionary[i])
431 for(
const size_t j: landmarkKeys) {
432 switch(dictionary[j]) {
433 case 0: C.push_back(j);
break;
434 case 1: A.push_back(j);
break;
435 case 2: B.push_back(j);
break;
436 default: std::cout << j <<
": " << dictionary[j] << std::endl;
437 throw std::runtime_error(
"addLandmarkToPartitionResult: wrong status for landmark");
442#define REDUCE_CAMERA_GRAPH
445 template<
class GenericGraph>
446 boost::optional<MetisResult> findPartitoning(
const GenericGraph& graph,
const std::vector<size_t>& keys,
448 const boost::optional<std::vector<Symbol> >& int2symbol,
const bool reduceGraph) {
449 boost::optional<MetisResult> result;
450 GenericGraph reducedGraph;
451 std::vector<size_t> keyToPartition;
452 std::vector<size_t> cameraKeys, landmarkKeys;
454 if (!int2symbol.is_initialized())
455 throw std::invalid_argument(
"findSeparator: int2symbol must be valid!");
458 cameraKeys.reserve(keys.size());
459 landmarkKeys.reserve(keys.size());
460 for(
const size_t key: keys) {
461 if((*int2symbol)[key].chr() ==
'x')
462 cameraKeys.push_back(key);
464 landmarkKeys.push_back(key);
467 keyToPartition = cameraKeys;
468 workspace.prepareDictionary(keyToPartition);
469 const std::vector<int>& dictionary = workspace.dictionary;
470 reduceGenericGraph(graph, cameraKeys, landmarkKeys, dictionary, reducedGraph);
471 std::cout <<
"original graph: V" << keys.size() <<
", E" << graph.size()
472 <<
" --> reduced graph: V" << cameraKeys.size() <<
", E" << reducedGraph.size() << std::endl;
473 result = edgePartitionByMetis(reducedGraph, keyToPartition, workspace, verbose);
475 result = separatorPartitionByMetis(graph, keys, workspace, verbose);
477 if (!result.is_initialized()) {
478 std::cout <<
"metis failed!" << std::endl;
483 addLandmarkToPartitionResult(graph, landmarkKeys, *result, workspace);
484 std::cout <<
"the separator size: " << result->C.size() <<
" landmarks" << std::endl;
491 template<
class GenericGraph>
492 int findSeparator(
const GenericGraph& graph,
const std::vector<size_t>& keys,
493 const int minNodesPerMap,
WorkSpace& workspace,
bool verbose,
494 const boost::optional<std::vector<Symbol> >& int2symbol,
const bool reduceGraph,
495 const int minNrConstraintsPerCamera,
const int minNrConstraintsPerLandmark) {
497 boost::optional<MetisResult> result = findPartitoning(graph, keys, workspace,
498 verbose, int2symbol, reduceGraph);
501 typedef std::vector<size_t> Island;
502 std::list<Island> islands;
504 std::list<Island> islands_in_A = findIslands(graph, result->A, workspace,
505 minNrConstraintsPerCamera, minNrConstraintsPerLandmark);
507 std::list<Island> islands_in_B = findIslands(graph, result->B, workspace,
508 minNrConstraintsPerCamera, minNrConstraintsPerLandmark);
510 islands.insert(islands.end(), islands_in_A.begin(), islands_in_A.end());
511 islands.insert(islands.end(), islands_in_B.begin(), islands_in_B.end());
512 islands.sort(isLargerIsland);
513 size_t numIsland0 = islands.size();
532 size_t oldSize = islands.size();
534 if (islands.size() < 2) {
535 std::cout <<
"numIsland: " << numIsland0 << std::endl;
536 throw std::runtime_error(
"findSeparator: found fewer than 2 submaps!");
539 std::list<Island>::reference island = islands.back();
540 if ((
int)island.size() >= minNodesPerMap)
break;
541 result->C.insert(result->C.end(), island.begin(), island.end());
544 if (islands.size() != oldSize){
545 if (verbose) std::cout << oldSize <<
"-" << oldSize - islands.size() <<
" submap(s);\t" << std::endl;
548 if (verbose) std::cout << oldSize <<
" submap(s);\t" << std::endl;
552 std::vector<int>& partitionTable = workspace.partitionTable;
553 std::fill(partitionTable.begin(), partitionTable.end(), -1);
554 for(
const size_t key: result->C)
555 partitionTable[key] = 0;
557 for(
const Island& island: islands) {
559 for(
const size_t key: island) {
560 partitionTable[key] = idx;
564 return islands.size();
Global functions in a separate testing namespace.
Definition chartTesting.h:28
the metis Nest dissection result
Definition FindSeparator.h:24
Definition PartitionWorkSpace.h:19