OpenGM  2.3.x
Discrete Graphical Model Library
partition-move.hxx
Go to the documentation of this file.
1 #pragma once
2 #ifndef OPENGM_PARTITIONMOVE_HXX
3 #define OPENGM_PARTITIONMOVE_HXX
4 
5 #include <algorithm>
6 #include <vector>
7 #include <queue>
8 #include <utility>
9 #include <string>
10 #include <iostream>
11 #include <fstream>
12 #include <typeinfo>
13 #include <limits>
14 #ifdef WITH_BOOST
15 #include <boost/unordered_map.hpp>
16 #include <boost/unordered_set.hpp>
17 #else
18 #include <ext/hash_map>
19 #include <ext/hash_set>
20 #endif
21 
22 #include "opengm/opengm.hxx"
25 
26 namespace opengm {
27 
38 template<class GM, class ACC>
39 class PartitionMove : public Inference<GM, ACC>
40 {
41 public:
42  typedef ACC AccumulationType;
43  typedef GM GraphicalModelType;
45  typedef size_t LPIndexType;
49 #ifdef WITH_BOOST
50  typedef boost::unordered_map<IndexType, LPIndexType> EdgeMapType;
51  typedef boost::unordered_set<IndexType> VariableSetType;
52 #else
53  typedef __gnu_cxx::hash_map<IndexType, LPIndexType> EdgeMapType;
54  typedef __gnu_cxx::hash_set<IndexType> VariableSetType;
55 #endif
56 
57 
58  template<class _GM>
59  struct RebindGm{
61  };
62 
63  template<class _GM,class _ACC>
66  };
67 
68 
69  struct Parameter{
70  Parameter ( ) {};
71  template<class P>
72  Parameter (const P & p) {};
73  };
74 
76  PartitionMove(const GraphicalModelType&, Parameter para=Parameter());
77  virtual std::string name() const {return "PartitionMove";}
78  const GraphicalModelType& graphicalModel() const {return gm_;}
79  virtual InferenceTermination infer();
80  template<class VisitorType> InferenceTermination infer(VisitorType&);
81  virtual InferenceTermination arg(std::vector<LabelType>&, const size_t = 1) const;
82 
83 private:
84  enum ProblemType {INVALID, MC, MWC};
85 
86  const GraphicalModelType& gm_;
87  ProblemType problemType_;
88  Parameter parameter_;
89 
90  LabelType numberOfTerminals_;
91  LPIndexType numberOfInternalEdges_;
92 
93 
96  std::vector<EdgeMapType > neighbours_;
97  std::vector<double> edgeWeight_;
98  double constant_;
99  std::vector<LabelType> states_;
100 
101  template<class VisitorType> InferenceTermination inferKL(VisitorType&);
102  double solveBinaryKL(VariableSetType&, VariableSetType&);
103 
104 };
105 
106 
107 template<class GM, class ACC>
109  ;
110 }
111 
112 template<class GM, class ACC>
114 (
115  const GraphicalModelType& gm,
116  Parameter para
117  ) : gm_(gm), parameter_(para)
118 {
119  if(typeid(ACC) != typeid(opengm::Minimizer) || typeid(OperatorType) != typeid(opengm::Adder)) {
120  throw RuntimeError("This implementation does only supports Min-Plus-Semiring.");
121  }
122 
123 
124  //Set Problem Type
125  problemType_ = MC;
126  numberOfInternalEdges_ = 0;
127  numberOfTerminals_ = gm_.numberOfLabels(0);
128  for(size_t i=0; i<gm_.numberOfVariables(); ++i){
129  if(gm_.numberOfLabels(i)<gm_.numberOfVariables()) {
130  problemType_ = MWC;
131  numberOfTerminals_ = std::max(numberOfTerminals_ ,gm_.numberOfLabels(i));
132  }
133  }
134  for(size_t f=0; f<gm_.numberOfFactors();++f) {
135  if(gm_[f].numberOfVariables()==0) {
136  continue;
137  }
138  else if(gm_[f].numberOfVariables()==1) {
139  problemType_ = MWC;
140  }
141  else if(gm_[f].numberOfVariables()==2) {
142  ++numberOfInternalEdges_;
143  if(!gm_[f].isPotts()) {
144  problemType_ = INVALID;
145  break;
146  }
147  }
148  else{
149  problemType_ = INVALID;
150  break;
151  }
152  }
153 
154  if(problemType_ == INVALID)
155  throw RuntimeError("Invalid Model for Multicut-Solver! Solver requires a potts model!");
156  if(problemType_ == MWC)
157  throw RuntimeError("Invalid Model for Multicut-Solver! Solver currently do not support first order terms!");
158 
159 
160  //Calculate Neighbourhood
161  neighbours_.resize(gm_.numberOfVariables());
162  edgeWeight_.resize(numberOfInternalEdges_,0);
163  constant_=0;
164  LPIndexType numberOfInternalEdges=0;
165  // Add edges that have to be included
166  for(size_t f=0; f<gm_.numberOfFactors(); ++f) {
167  if(gm_[f].numberOfVariables()==0) {
168  const LabelType l=0;
169  constant_+=gm_[f](&l);
170  }
171  else if(gm_[f].numberOfVariables()==2) {
172  LabelType cc0[] = {0,0};
173  LabelType cc1[] = {0,1};
174  edgeWeight_[numberOfInternalEdges] += gm_[f](cc1) - gm_[f](cc0);
175  constant_ += gm_[f](cc0);
176  IndexType u = gm_[f].variableIndex(0);
177  IndexType v = gm_[f].variableIndex(1);
178  neighbours_[u][v] = numberOfInternalEdges;
179  neighbours_[v][u] = numberOfInternalEdges;
180  ++numberOfInternalEdges;
181  }
182  else{
183  throw RuntimeError("Only supports second order Potts functions!");
184  }
185  }
186  OPENGM_ASSERT(numberOfInternalEdges==numberOfInternalEdges_);
187 
188  states_.resize(gm_.numberOfVariables(),0);
189  size_t init = 2;
190 
191  if(init==1){
192  for(size_t i=0; i<states_.size();++i){
193  states_[i]=rand()%10;
194  }
195  }
196 
197  if(init==2){
198  LabelType p=0;
199  std::vector<bool> assigned(states_.size(),false);
200  for(IndexType node=0; node<states_.size(); ++node) {
201  if(assigned[node])
202  continue;
203  else{
204  std::list<IndexType> nodeList;
205  states_[node] = p;
206  assigned[node] = true;
207  nodeList.push_back(node);
208  while(!nodeList.empty()) {
209  size_t n=nodeList.front(); nodeList.pop_front();
210  for(typename EdgeMapType::const_iterator it=neighbours_[n].begin() ; it != neighbours_[n].end(); ++it) {
211  const IndexType node2 = (*it).first;
212  if(!assigned[node2] && edgeWeight_[(*it).second]>0) {
213  states_[node2] = p;
214  assigned[node2] = true;
215  nodeList.push_back(node2);
216  }
217  }
218  }
219  ++p;
220  }
221  }
222  }
223 
224  if(init==3){
225  for(size_t i=0; i<states_.size();++i){
226  states_[i]=i;
227  }
228  }
229 
230 
231 }
232 
233 
234 template <class GM, class ACC>
237 {
238  EmptyVisitorType visitor;
239  return infer(visitor);
240 }
241 
242 
243 template <class GM, class ACC>
244 template<class VisitorType>
246 PartitionMove<GM,ACC>::infer(VisitorType& visitor)
247 {
248  visitor.begin(*this);
249  inferKL(visitor);
250  visitor.end(*this);
251  return NORMAL;
252 }
253 
254 template <class GM, class ACC>
255 template<class VisitorType>
257 PartitionMove<GM,ACC>::inferKL(VisitorType& visitor)
258 {
259  // Current Partition-Sets
260  std::vector<VariableSetType> partitionSets;
261 
262  // Set-Up Partition-Sets from current/initial partitioning
263  LabelType numberOfPartitions =0;
264  for(size_t i=0; i<states_.size(); ++i)
265  if(states_[i]+1>numberOfPartitions) numberOfPartitions=states_[i]+1;
266  partitionSets.resize(numberOfPartitions);
267  for(IndexType i=0; i<states_.size(); ++i){
268  partitionSets[states_[i]].insert(i);
269  }
270 
271  bool change = true;
272  while(change){
273  // std::cout << numberOfPartitions << " conncted subsets."<<std::endl;
274  change = false;
275  std::vector<size_t> pruneSets;
276  // Check all pairs of partitions
277  for(size_t part0=0; part0<numberOfPartitions; ++part0){
278  //std::cout <<"*"<<std::flush;
279  // Find neighbord sets
280  std::set<size_t> neighbordSets;
281  for(typename VariableSetType::const_iterator it=partitionSets[part0].begin(); it!=partitionSets[part0].end(); ++it){
282  const IndexType node = (*it);
283  for(typename EdgeMapType::const_iterator nit=neighbours_[node].begin() ; nit != neighbours_[node].end(); ++nit) {
284  const IndexType node2 = (*nit).first;
285  if(states_[node2]>part0){
286  neighbordSets.insert(states_[node2]);
287  }
288  }
289  }
290  for(std::set<size_t>::const_iterator it=neighbordSets.begin(); it!=neighbordSets.end();++it){
291  size_t part1 = *it;
292  //for(size_t part1=part0+1; part1<numberOfPartitions; ++part1){
293  if(partitionSets[part0].size()==0 || partitionSets[part1].size()==0)
294  continue;
295  double improvement = solveBinaryKL(partitionSets[part0],partitionSets[part1]);
296  //std::cout <<part0<<" vs "<<part1<<" : " <<improvement<<std::endl;
297  OPENGM_ASSERT(improvement<1e-8);
298  if(-1e-8>improvement){
299  change = true; // Partition has been improved
300  }
301  }
302  }
303  // Check for each Partition ...
304  for(size_t part0=0; part0<numberOfPartitions; ++part0){
305  // ... if it is empty and can be pruned
306  if(partitionSets[part0].size()==0){
307  //std::cout <<"Remove "<<part0<<std::endl;
308  pruneSets.push_back(part0);
309  }
310  // ... or if it can be splited into two sets
311  else if(partitionSets[part0].size()>1){
312  // std::cout <<part0<<" vs "<<"NULL"<<std::endl;
313 
314  VariableSetType emptySet(partitionSets[part0].size());
315  double improvement = solveBinaryKL(partitionSets[part0], emptySet);
316  if(emptySet.size()>0){
317  OPENGM_ASSERT(improvement<0);
318  partitionSets.push_back(emptySet);
319  change = true;
320  }
321  }
322  }
323  // Remove sets marked as to prune
324  //std::cout << "Remove " <<pruneSets.size() << " subsets."<<std::endl;
325  for(size_t i=0; i<pruneSets.size(); ++i){
326  size_t part = pruneSets[pruneSets.size()-1-i];
327  partitionSets.erase( partitionSets.begin()+part);
328  }
329  // Update Labeling
330  numberOfPartitions = partitionSets.size();
331  for(size_t part=0; part<numberOfPartitions; ++part){
332  for(typename VariableSetType::const_iterator it=partitionSets[part].begin(); it!=partitionSets[part].end(); ++it){
333  states_[*it] = part;
334  }
335  }
336  if( visitor(*this) != visitors::VisitorReturnFlag::ContinueInf ){
337  change = false;
338  }
339  }
340  return NORMAL;
341 }
342 
343 template <class GM, class ACC>
345 (
346  VariableSetType& set0,
347  VariableSetType& set1
348 )
349 {
350  double improvement = 0.0;
351  //std::cout << "Set0: "<< set0.size() <<" Set1: "<< set1.size() << std::endl;
352 
353  for(size_t outerIt=0; outerIt<100;++outerIt){
354  // Compute D[n] = E_n - I_n
355  std::vector<double> D(gm_.numberOfVariables(),0);
356  for(typename VariableSetType::const_iterator it=set0.begin(); it!=set0.end(); ++it){
357  double E_a = 0.0;
358  double I_a = 0.0;
359  const IndexType node = *it;
360  for (typename EdgeMapType::const_iterator eit=neighbours_[node].begin(); eit!=neighbours_[node].end(); ++eit){
361  const IndexType node2 = (*eit).first;
362  const double weight = edgeWeight_[(*eit).second];
363 
364  if (set0.find(node2) != set0.end()) {
365  I_a += weight;
366  }
367  else if(set1.find(node2) != set1.end()){
368  E_a += weight;
369  }
370  }
371  D[node] = -(E_a - I_a);
372  }
373  for(typename VariableSetType::const_iterator it=set1.begin(); it!=set1.end(); ++it){
374  double E_a = 0.0;
375  double I_a = 0.0;
376  const IndexType node = *it;
377  for(typename EdgeMapType::const_iterator eit=neighbours_[node].begin(); eit!=neighbours_[node].end(); ++eit){
378  const IndexType node2 = (*eit).first;
379  const double weight = edgeWeight_[(*eit).second];
380 
381  if (set1.find(node2) != set1.end()) {
382  I_a += weight;
383  }
384  else if(set0.find(node2) != set0.end()){
385  E_a += weight;
386  }
387  }
388  D[node] = -(E_a - I_a);
389  }
390 
391  double d=0;
392  for(size_t i=0; i<D.size(); ++i){
393  if(D[i]<d)
394  d=D[i];
395  }
396 
397 
398  // Search a gready move sequence
399  std::vector<bool> isMovedNode(gm_.numberOfVariables(),false);
400  std::vector<IndexType> nodeSequence;
401  std::vector<double> improveSequence;
402  std::vector<double> improveSumSequence(1,0.0);
403  size_t bestMove=0;
404 
405  // Build sequence of greedy best moves
406  for(size_t innerIt=0; innerIt<1000; ++innerIt){
407  double improve = std::numeric_limits<double>::infinity();
408  IndexType node;
409  bool moved = false;
410  // Search over moves from set0
411  for(typename VariableSetType::const_iterator it=set0.begin(); it!=set0.end(); ++it){
412  if(isMovedNode[*it]){
413  continue;
414  }
415  else{
416  if(D[*it]<improve){
417  improve = D[*it];
418  node = *it;
419  moved = true;
420  }
421  }
422  }
423  // Search over moves from set1
424  for(typename VariableSetType::const_iterator it=set1.begin(); it!=set1.end(); ++it){
425  if(isMovedNode[*it]){
426  continue;
427  }
428  else{
429  if(D[*it]<improve){
430  improve = D[*it];
431  node = *it;
432  moved = true;
433  }
434  }
435  }
436 
437  // No more moves?
438  if(moved == false){
439  break;
440  }
441 
442  // Move node and recalculate D
443  //std::cout << " " <<improveSumSequence.back()+improve;
444  isMovedNode[node]=true;
445  nodeSequence.push_back(node);
446  improveSumSequence.push_back(improveSumSequence.back()+improve);
447  improveSequence.push_back(improve);
448  if (improveSumSequence[bestMove]>improveSumSequence.back()) {
449  bestMove = improveSumSequence.size()-1;
450  }
451 
452  VariableSetType& mySet = set0.find(node) != set0.end() ? set0 : set1;
453  for(typename EdgeMapType::const_iterator eit=neighbours_[node].begin(); eit!=neighbours_[node].end(); ++eit){
454  IndexType node2 = (*eit).first;
455  double weight = edgeWeight_[(*eit).second];
456  if(mySet.find(node2) != mySet.end()){
457  D[node2] -= 2.0 * weight;
458  }
459  else{
460  D[node2] += 2.0 * weight;
461  }
462 
463  }
464  }
465 
466  // Perform Move
467  if(improveSumSequence[bestMove]>-1e-10)
468  break;
469  else{
470  improvement += improveSumSequence[bestMove];
471  for (size_t i = 0; i < bestMove; ++i) {
472  int node = nodeSequence[i];
473  if (set0.find(node) != set0.end()) {
474  set0.erase(node);
475  set1.insert(node);
476  }
477  else{
478  set1.erase(node);
479  set0.insert(node);
480  }
481  }
482  }
483  // Search for the next move if this move has give improvement
484  }
485  return improvement;
486 }
487 
488 template <class GM, class ACC>
491 (
492  std::vector<typename PartitionMove<GM,ACC>::LabelType>& x,
493  const size_t N
494  ) const
495 {
496  if(N!=1) {
497  return UNKNOWN;
498  }
499  else{
500  x.resize(gm_.numberOfVariables());
501  for(size_t i=0; i<gm_.numberOfVariables(); ++i)
502  x[i] = states_[i];
503  return NORMAL;
504  }
505 }
506 
507 } // end namespace opengm
508 
509 #endif
PartitionMove(const GraphicalModelType &, Parameter para=Parameter())
PartitionMove< _GM, ACC > type
visitors::TimingVisitor< PartitionMove< GM, ACC > > TimingVisitorType
The OpenGM namespace.
Definition: config.hxx:43
Addition as a binary operation.
Definition: adder.hxx:10
PartitionMove< _GM, _ACC > type
#define OPENGM_ASSERT(expression)
Definition: opengm.hxx:77
virtual std::string name() const
GraphicalModelType::OperatorType OperatorType
Definition: inference.hxx:51
__gnu_cxx::hash_set< IndexType > VariableSetType
const GraphicalModelType & graphicalModel() const
visitors::EmptyVisitor< PartitionMove< GM, ACC > > EmptyVisitorType
GraphicalModelType::IndexType IndexType
Definition: inference.hxx:49
__gnu_cxx::hash_map< IndexType, LPIndexType > EdgeMapType
visitors::VerboseVisitor< PartitionMove< GM, ACC > > VerboseVisitorType
Inference algorithm interface.
Definition: inference.hxx:43
virtual InferenceTermination arg(std::vector< LabelType > &, const size_t=1) const
output a solution
virtual InferenceTermination infer()
GraphicalModelType::LabelType LabelType
Definition: inference.hxx:48
Minimization as a unary accumulation.
Definition: minimizer.hxx:12
Partition Move Currently Partition Move only implements the Kernighan-Lin-Algorithm.
OpenGM runtime error.
Definition: opengm.hxx:100
InferenceTermination
Definition: inference.hxx:24