OpenGM  2.3.x
Discrete Graphical Model Library
dualdecomposition_bundle.hxx
Go to the documentation of this file.
1 #pragma once
2 #ifndef OPENGM_DUALDDECOMPOSITION_BUNDLE_HXX
3 #define OPENGM_DUALDDECOMPOSITION_BUNDLE_HXX
4 
5 #include <vector>
6 #include <list>
7 #include <typeinfo>
11 
12 #ifdef WITH_OPENMP
13 #include <omp.h>
14 #endif
15 #ifdef WITH_CONICBUNDLE
16 #include <CBSolver.hxx>
17 
18 namespace opengm {
19 
27  template<class GM, class INF, class DUALBLOCK >
28  class DualDecompositionBundle
29  : public Inference<GM,typename INF::AccumulationType>,
30  public DualDecompositionBase<GM, DUALBLOCK>,
31  public ConicBundle::FunctionOracle
32  {
33  public:
34  typedef GM GmType;
35  typedef GM GraphicalModelType;
36  typedef typename INF::AccumulationType AccumulationType;
38  typedef visitors::VerboseVisitor<DualDecompositionBundle<GM, INF,DUALBLOCK> > VerboseVisitorType;
39  typedef visitors::TimingVisitor<DualDecompositionBundle<GM, INF,DUALBLOCK> > TimingVisitorType;
40  typedef visitors::EmptyVisitor<DualDecompositionBundle<GM, INF,DUALBLOCK> > EmptyVisitorType;
41  typedef INF InfType;
42  typedef DUALBLOCK DualBlockType;
43  typedef typename DualBlockType::DualVariableType DualVariableType;
44  typedef DualDecompositionBase<GmType, DualBlockType> DDBaseType;
45 
46  typedef typename DDBaseType::SubGmType SubGmType;
47  typedef typename DualBlockType::SubFactorType SubFactorType;
48  typedef typename DualBlockType::SubFactorListType SubFactorListType;
49  typedef typename DDBaseType::SubVariableType SubVariableType;
50  typedef typename DDBaseType::SubVariableListType SubVariableListType;
51 
52 
53  template<class _GM>
54  struct RebindGm{
55  typedef typename INF:: template RebindGm<_GM>::type RebindedInf;
56  typedef DualDecompositionBundle<_GM, RebindedInf, DUALBLOCK> type;
57  };
58 
59  template<class _GM,class _ACC>
60  struct RebindGmAndAcc{
61  typedef typename INF:: template RebindGm<_GM,_ACC>::type RebindedInf;
62  typedef DualDecompositionBundle<_GM, RebindedInf, DUALBLOCK> type;
63  };
64 
65 
66  class Parameter : public DualDecompositionBaseParameter{
67  public:
69  double minimalRelAccuracy_;
71  typename InfType::Parameter subPara_;
73  double relativeDualBoundPrecision_;
75  size_t maxBundlesize_;
77  bool activeBoundFixing_;
79  double minDualWeight_;
81  double maxDualWeight_;
83  bool noBundle_;
85  bool useHeuristicStepsize_;
86 
87  Parameter()
88  : relativeDualBoundPrecision_(0.0),
89  maxBundlesize_(100),
90  activeBoundFixing_(false),
91  minDualWeight_(-1),
92  maxDualWeight_(-1),
93  noBundle_(false),
94  useHeuristicStepsize_(true)
95  {};
96 
97  template<class P>
98  Parameter(const P & p)
99  :
100  minimalRelAccuracy_(p.minimalRelAccuracy_),
101  subPara_(subPara_),
102  relativeDualBoundPrecision_(p.relativeDualBoundPrecision_),
103  maxBundlesize_(p.maxBundlesize_),
104  activeBoundFixing_(p.activeBoundFixing_),
105  minDualWeight_(p.minDualWeight_),
106  maxDualWeight_(p.maxDualWeight_),
107  noBundle_(p.noBundle_),
108  useHeuristicStepsize_(p.useHeuristicStepsize_){
109  }
110  };
111 
117 
118  ~DualDecompositionBundle();
119  DualDecompositionBundle(const GmType&);
120  DualDecompositionBundle(const GmType&, const Parameter&);
121  virtual std::string name() const {return "DualDecompositionSubGradient";};
122  virtual const GmType& graphicalModel() const {return gm_;};
123  virtual InferenceTermination infer();
124  template<class VisitorType>
125  InferenceTermination infer(VisitorType&);
126  virtual ValueType bound() const;
127  virtual ValueType value() const;
128  virtual InferenceTermination arg(std::vector<LabelType>&, const size_t = 1)const;
129  virtual int evaluate(const ConicBundle::DVector&, double, double&, ConicBundle::DVector&, std::vector<ConicBundle::DVector>&,
130  std::vector<ConicBundle::PrimalData*>&, ConicBundle::PrimalExtender*&);
131 
132  private:
133  virtual void allocate();
134  virtual DualDecompositionBaseParameter& parameter();
135  int dualStep(const size_t iteration);
136  template <class T_IndexType, class T_LabelType>
137  void getPartialSubGradient(const size_t, const std::vector<T_IndexType>&, std::vector<T_LabelType>&)const;
138  double euclideanSubGradientNorm();
139 
140  // Members
141  std::vector<std::vector<LabelType> > subStates_;
142  ConicBundle::CBSolver* solver;
143  size_t nullStepCounter_;
144 
145  Accumulation<ValueType,LabelType,AccumulationType> acUpperBound_;
146  Accumulation<ValueType,LabelType,AccumulationType> acNegLowerBound_;
147  ValueType upperBound_;
148  ValueType lowerBound_;
149 
150  Parameter para_;
151  std::vector<ValueType> mem_;
152  std::vector<ValueType> mem2_;
153 
154  opengm::Timer primalTimer_;
155  opengm::Timer dualTimer_;
156  double primalTime_;
157  double dualTime_;
158 
159  };
160 
161 //**********************************************************************************
162  template<class GM, class INF, class DUALBLOCK>
163  DualDecompositionBundle<GM,INF,DUALBLOCK>::~DualDecompositionBundle()
164  {
165  delete solver;
166  }
167 
168  template<class GM, class INF, class DUALBLOCK>
169  DualDecompositionBundle<GM,INF,DUALBLOCK>::DualDecompositionBundle(const GmType& gm)
170  : DualDecompositionBase<GmType, DualBlockType >(gm)
171  {
172  this->init(para_);
173  subStates_.resize(subGm_.size());
174  for(size_t i=0; i<subGm_.size(); ++i)
175  subStates_[i].resize(subGm_[i].numberOfVariables());
176 
177  solver = new ConicBundle::CBSolver(para_.noBundle_);
178  // Setup bundle-solver
179  solver->init_problem(numDualsMinimal_);
180  solver->add_function(*this);
181  solver->set_out(&std::cout,0);//1=output
182 
183  solver->set_max_bundlesize(*this,para_.maxBundlesize_);
184  //solver->set_eval_limit(1000);
185  //solver->set_inner_update_limit(1);
186  solver->set_active_bounds_fixing(para_.activeBoundFixing_);
187  solver->set_term_relprec(para_.relativeDualBoundPrecision_);
188  solver->set_min_weight(para_.minDualWeight_);
189  solver->set_max_weight(para_.maxDualWeight_);
190  nullStepCounter_ =0;
191  }
192 
193  template<class GM, class INF, class DUALBLOCK>
194  DualDecompositionBundle<GM,INF,DUALBLOCK>::DualDecompositionBundle(const GmType& gm, const Parameter& para)
195  : DualDecompositionBase<GmType, DualBlockType >(gm)
196  {
197  para_ = para;
198  this->init(para_);
199 
200  subStates_.resize(subGm_.size());
201  for(size_t i=0; i<subGm_.size(); ++i)
202  subStates_[i].resize(subGm_[i].numberOfVariables());
203 
204  solver = new ConicBundle::CBSolver(para_.noBundle_);
205  // Setup bundle-solver
206  solver->init_problem(numDualsMinimal_);
207  solver->add_function(*this);
208  solver->set_out(&std::cout,0);//1=output
209  solver->set_max_bundlesize(*this,para_.maxBundlesize_);
210  //solver->set_eval_limit(1000);
211  //solver->set_inner_update_limit(1);
212  solver->set_active_bounds_fixing(para.activeBoundFixing_);
213  solver->set_term_relprec(para_.relativeDualBoundPrecision_);
214  solver->set_min_weight(para_.minDualWeight_);
215  solver->set_max_weight(para_.maxDualWeight_);
216  nullStepCounter_ =0;
217  }
218 
219 
221 
222  template <class GM, class INF, class DUALBLOCK>
223  void DualDecompositionBundle<GM,INF,DUALBLOCK>::allocate()
224  {
225  mem_.resize(numDualsOvercomplete_,0);
226  mem2_.resize(numDualsOvercomplete_,0);
227  ValueType *data1Front = &mem_[0];
228  ValueType *data1Back = &mem_[numDualsOvercomplete_];
229  ValueType *data2Front = &mem2_[0];
230  ValueType *data2Back = &mem2_[numDualsOvercomplete_];
231  for(typename std::vector<DualBlockType>::iterator it=dualBlocks_.begin(); it!=dualBlocks_.end(); ++it){
232  for(size_t i=0; i<(*it).duals_.size(); ++i){
233  DualVariableType& dv1 = (*it).duals_[i];
234  DualVariableType& dv2 = (*it).duals2_[i];
235  if(i+1==(*it).duals_.size()){
236  data1Back -= dv1.size();
237  data2Back -= dv2.size();
238  dv1.assign( dv1.shapeBegin(),dv1.shapeEnd(),data1Back);
239  dv2.assign( dv2.shapeBegin(),dv2.shapeEnd(),data2Back);
240  }
241  else{
242  dv1.assign( dv1.shapeBegin(),dv1.shapeEnd(),data1Front);
243  dv2.assign( dv2.shapeBegin(),dv2.shapeEnd(),data2Front);
244  data1Front += dv1.size();
245  data2Front += dv2.size();
246  }
247  }
248  }
249  OPENGM_ASSERT(data1Front == data1Back );
250  OPENGM_ASSERT(data2Front == data2Back );
251  OPENGM_ASSERT(data1Front == &mem_[0]+numDualsMinimal_);
252  OPENGM_ASSERT(data2Front == &mem2_[0]+numDualsMinimal_ );
253  }
254 
255  template <class GM, class INF, class DUALBLOCK>
256  DualDecompositionBaseParameter& DualDecompositionBundle<GM,INF,DUALBLOCK>::parameter()
257  {
258  return para_;
259  }
260 
262 
263  template<class GM, class INF, class DUALBLOCK>
265  infer()
266  {
267  EmptyVisitorType visitor;
268  return infer(visitor);
269  }
270 
271  template<class GM, class INF, class DUALBLOCK>
272  template<class VisitorType>
274  infer(VisitorType& visitor)
275  {
276  std::cout.precision(15);
277  visitor.begin(*this);
278  for(size_t iteration=0; iteration<para_.maximalNumberOfIterations_; ++iteration){
279  // Dual Step
281  int ret;
282  if(dualBlocks_.size() == 0){
283  // Solve subproblems
284  for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
285  InfType inf(subGm_[subModelId],para_.subPara_);
286  inf.infer();
287  inf.arg(subStates_[subModelId]);
288  }
289 
290  // Calculate lower-bound
291  std::vector<LabelType> temp;
292  std::vector<LabelType> temp2;
293  const std::vector<SubVariableListType>& subVariableLists = para_.decomposition_.getVariableLists();
294  (*this).template getBounds<AccumulationType>(subStates_, subVariableLists, lowerBound_, upperBound_, temp);
295  acNegLowerBound_(-lowerBound_,temp2);
296  acUpperBound_(upperBound_, temp);
297  ret=128;
298  }
299  else{
300  ret = dualStep(iteration);
301  }
304  std::cout.precision(15);
305  if(visitor(*this)!=0){
306  break;
307  }
308  //visitor((*this),lowerBound_,-acNegLowerBound_.value(), upperBound_, acUpperBound_.value(), primalTime_, dualTime_);
309 
312 
313 
314  // Test for Convergence
315  ValueType o;
316  AccumulationType::iop(0.0001,-0.0001,o);
317  OPENGM_ASSERT(AccumulationType::bop(lowerBound_, upperBound_+o));
318  OPENGM_ASSERT(AccumulationType::bop(-acNegLowerBound_.value(), acUpperBound_.value()+o));
319 
320  if( fabs(acUpperBound_.value() + acNegLowerBound_.value()) <= para_.minimalAbsAccuracy_
321  || fabs((acUpperBound_.value()+ acNegLowerBound_.value())/acUpperBound_.value()) <= para_.minimalRelAccuracy_
322  || ret ==1){
323  visitor.end(*this);
324  return NORMAL;
325  }
326  if(ret>0){
327  break;
328  }
329  }
330  visitor.end(*this);
331  return NORMAL;
332  }
333 
334  template<class GM, class INF, class DUALBLOCK>
335  InferenceTermination DualDecompositionBundle<GM,INF,DUALBLOCK>::
336  arg(std::vector<LabelType>& conf, const size_t n)const
337  {
338  if(n!=1){
339  return UNKNOWN;
340  }
341  else{
342  acUpperBound_.state(conf);
343  return NORMAL;
344  }
345  }
346 
347  template<class GM, class INF, class DUALBLOCK>
348  typename GM::ValueType DualDecompositionBundle<GM,INF,DUALBLOCK>::value() const
349  {
350  return acUpperBound_.value();
351  }
352 
353  template<class GM, class INF, class DUALBLOCK>
354  typename GM::ValueType DualDecompositionBundle<GM,INF,DUALBLOCK>::bound() const
355  {
356  return -acNegLowerBound_.value();
357  }
358 
359 
361 
362  template <class GM, class INF, class DUALBLOCK>
363  int DualDecompositionBundle<GM,INF,DUALBLOCK>::dualStep(const size_t iteration)
364  {
365  int retval;
366  if(para_.useHeuristicStepsize_){
367  solver->set_min_weight(para_.minDualWeight_);
368  solver->set_max_weight(para_.maxDualWeight_);
369  }
370  else if(iteration == 0){
371  solver->set_min_weight(100);
372  solver->set_max_weight(100);
373  }
374  else{
375  if(solver->get_objval() == solver->get_candidate_value() || iteration==1){
376  //Serious Step
377  double primalDualGap = fabs(acUpperBound_.value() + acNegLowerBound_.value());
378 
379  double subgradientNorm = (*this).euclideanSubGradientNorm();
380  double stepsize = (primalDualGap)/subgradientNorm * para_.stepsizeStride_;
381 
382  if(para_.minDualWeight_>=0)
383  stepsize = std::min(1/para_.minDualWeight_, stepsize);
384  if(para_.maxDualWeight_>=0)
385  stepsize = std::max(1/para_.maxDualWeight_, stepsize);
386 
387  double t = 1/stepsize;
388  solver->set_next_weight(t);
389  solver->set_min_weight(t);
390  solver->set_max_weight(t);
391  nullStepCounter_ =0;
392  }
393  else{
394  // Null Step
395  ++nullStepCounter_;
396  }
397  }
398 
399  retval=solver->do_descent_step(1);
400 
401  if (retval){
402  std::cout<<"descent_step returned "<<retval<<std::endl;
403  }
404  //std::cout << solver->get_last_weight() << std::endl;
405  return solver->termination_code();
406  }
407 
408  template <class GM, class INF, class DUALBLOCK>
409  int DualDecompositionBundle<GM,INF,DUALBLOCK>::evaluate
410  (
411  const ConicBundle::DVector& dual, // Argument/Lagrange multipliers
412  double relprec,
413  double& objective_value,
414  ConicBundle::DVector& cut_vals,
415  std::vector<ConicBundle::DVector>& subgradients,
416  std::vector<ConicBundle::PrimalData*>& primal_solutions,
417  ConicBundle::PrimalExtender*& primal_extender
418  )
419  {
420  typename std::vector<DualBlockType>::iterator it;
421  typename SubFactorListType::const_iterator lit;
422 
423  for(size_t i=0; i<numDualsMinimal_; ++i){
424  mem_[i] = dual[i];
425  }
426  for(it = dualBlocks_.begin(); it != dualBlocks_.end(); ++it){
427  const size_t numDuals = (*it).duals_.size();
428  (*it).duals_[numDuals-1] = -(*it).duals_[0];
429  for(size_t i=1; i<numDuals-1;++i){
430  (*it).duals_[numDuals-1] -= (*it).duals_[i];
431  }
432  }
433  // Solve Subproblems
434  objective_value=0;
435  primalTimer_.tic();
436 
437 //#ifdef WITH_OPENMP
438 // omp_set_num_threads(para_.numberOfThreads_);
439 //#pragma omp parallel for
440 //#endif
441  for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
442  InfType inf(subGm_[subModelId],para_.subPara_);
443  inf.infer();
444  inf.arg(subStates_[subModelId]);
445  }
446  primalTimer_.toc();
447  primalTime_ += primalTimer_.elapsedTime();
448 
449  // Calculate lower-bound
450  std::vector<LabelType> temp;
451  std::vector<LabelType> temp2;
452  const std::vector<SubVariableListType>& subVariableLists = para_.decomposition_.getVariableLists();
453  (*this).template getBounds<AccumulationType>(subStates_, subVariableLists, lowerBound_, upperBound_, temp);
454  acNegLowerBound_(-lowerBound_,temp2);
455  acUpperBound_(upperBound_, temp);
456  objective_value = -lowerBound_;
457 
458  // Store subgradient
459  std::vector<size_t> s;
460  mem2_.assign(mem2_.size(),0);
461  for(it = dualBlocks_.begin(); it != dualBlocks_.end(); ++it){
462  const size_t numDuals = (*it).duals_.size();
463  lit = (*((*it).subFactorList_)).begin();
464  s.resize((*lit).subIndices_.size());
465  for(size_t i=0; i<numDuals; ++i){
466  getPartialSubGradient((*lit).subModelId_, (*lit).subIndices_, s);
467  ++lit;
468  (*it).duals2_[i](s.begin()) += -1.0;
469  }
470  for(size_t i=0; i<numDuals-1; ++i){
471  (*it).duals2_[i] -= (*it).duals2_[numDuals-1] ;
472  }
473  }
474 
475  //construct first subgradient and objective value
476  ConicBundle::PrimalDVector h(numDualsMinimal_,0);
477  cut_vals.push_back(objective_value);
478  for(size_t i=0; i<numDualsMinimal_; ++i){
479  h[i] = mem2_[i];
480  }
481  subgradients.push_back(h);
482  // primal_solutions.push_back(h.clone_primal_data());
483  return 0;
484  }
485 
486 
487 
488  template <class GM, class INF, class DUALBLOCK>
489  template <class T_IndexType, class T_LabelType>
490  inline void DualDecompositionBundle<GM,INF,DUALBLOCK>::getPartialSubGradient
491  (
492  const size_t subModelId,
493  const std::vector<T_IndexType>& subIndices,
494  std::vector<T_LabelType> & s
495  )const
496  {
497  OPENGM_ASSERT(subIndices.size() == s.size());
498  for(size_t n=0; n<s.size(); ++n){
499  s[n] = subStates_[subModelId][subIndices[n]];
500  }
501  }
502 
503  template <class GM, class INF, class DUALBLOCK>
504  double DualDecompositionBundle<GM,INF,DUALBLOCK>::euclideanSubGradientNorm()
505  {
506  double norm = 0;
507  std::vector<size_t> s,s2;
508  typename std::vector<DUALBLOCK>::const_iterator it;
509  typename SubFactorListType::const_iterator lit;
510  for(it = dualBlocks_.begin(); it != dualBlocks_.end(); ++it){
511  const size_t numDuals = (*it).duals_.size();
512  const SubFactorType& sf = (*((*it).subFactorList_)).back();
513  lit = (*((*it).subFactorList_)).begin();
514  s.resize((*lit).subIndices_.size());
515  s2.resize((*lit).subIndices_.size());
516  getPartialSubGradient(sf.subModelId_, sf.subIndices_, s2);
517  for(size_t i=0; i<numDuals-1; ++i){
518  getPartialSubGradient((*lit).subModelId_, (*lit).subIndices_, s);
519  ++lit;
520  if(s!=s2)
521  norm += 2;
522  }
523  }
524  return sqrt(norm);
525  }
526 
527 
528 
529 }
530 #endif // WITH_CONICBUNDLE
531 #endif
532 
The OpenGM namespace.
Definition: config.hxx:43
std::vector< DualBlockType > dualBlocks_
void infer(const typename INF::GraphicalModelType &gm, const typename INF::Parameter &param, std::vector< typename INF::LabelType > &conf)
Definition: inference.hxx:34
Platform-independent runtime measurements.
Definition: timer.hxx:29
#define OPENGM_ASSERT(expression)
Definition: opengm.hxx:77
#define OPENGM_GM_TYPE_TYPEDEFS
Definition: inference.hxx:13
InferenceTermination
Definition: inference.hxx:24