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