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