00001 #pragma once
00002 #ifndef OPENGM_DUALDDECOMPOSITION_BUNDLE_HXX
00003 #define OPENGM_DUALDDECOMPOSITION_BUNDLE_HXX
00004
00005 #include <vector>
00006 #include <list>
00007 #include <typeinfo>
00008 #include "opengm/inference/inference.hxx"
00009 #include "opengm/inference/visitors/visitor.hxx"
00010 #include "opengm/inference/dualdecomposition/dualdecomposition_base.hxx"
00011
00012 #ifdef WITH_OPENMP
00013 #include <omp.h>
00014 #endif
00015 #ifdef WITH_CONICBUNDLE
00016 #include <CBSolver.hxx>
00017
00018 namespace opengm {
00019
00021 template<class GM, class INF, class DUALBLOCK >
00022 class DualDecompositionBundle
00023 : public Inference<GM,typename INF::AccumulationType>,
00024 public DualDecompositionBase<GM, DUALBLOCK>,
00025 public ConicBundle::FunctionOracle
00026 {
00027 public:
00028 typedef GM GmType;
00029 typedef GM GraphicalModelType;
00030 typedef typename INF::AccumulationType AccumulationType;
00031 OPENGM_GM_TYPE_TYPEDEFS;
00032 typedef VerboseVisitor<DualDecompositionBundle<GM, INF,DUALBLOCK> > VerboseVisitorType;
00033 typedef TimingVisitor<DualDecompositionBundle<GM, INF,DUALBLOCK> > TimingVisitorType;
00034 typedef EmptyVisitor<DualDecompositionBundle<GM, INF,DUALBLOCK> > EmptyVisitorType;
00035 typedef INF InfType;
00036 typedef DUALBLOCK DualBlockType;
00037 typedef typename DualBlockType::DualVariableType DualVariableType;
00038 typedef DualDecompositionBase<GmType, DualBlockType> DDBaseType;
00039
00040 typedef typename DDBaseType::SubGmType SubGmType;
00041 typedef typename DualBlockType::SubFactorType SubFactorType;
00042 typedef typename DualBlockType::SubFactorListType SubFactorListType;
00043 typedef typename DDBaseType::SubVariableType SubVariableType;
00044 typedef typename DDBaseType::SubVariableListType SubVariableListType;
00045
00046 class Parameter : public DualDecompositionBaseParameter{
00047 public:
00049 double minimalRelAccuracy_;
00051 typename InfType::Parameter subPara_;
00053 double relativeDualBoundPrecision_;
00055 size_t maxBundlesize_;
00057 bool activeBoundFixing_;
00059 double minDualWeight_;
00061 double maxDualWeight_;
00063 bool noBundle_;
00065 bool useHeuristicStepsize_;
00066
00067 Parameter()
00068 : relativeDualBoundPrecision_(0.0),
00069 maxBundlesize_(100),
00070 activeBoundFixing_(false),
00071 minDualWeight_(-1),
00072 maxDualWeight_(-1),
00073 noBundle_(false),
00074 useHeuristicStepsize_(true)
00075 {};
00076 };
00077
00078 using DualDecompositionBase<GmType, DualBlockType >::gm_;
00079 using DualDecompositionBase<GmType, DualBlockType >::subGm_;
00080 using DualDecompositionBase<GmType, DualBlockType >::dualBlocks_;
00081 using DualDecompositionBase<GmType, DualBlockType >::numDualsOvercomplete_;
00082 using DualDecompositionBase<GmType, DualBlockType >::numDualsMinimal_;
00083
00084 ~DualDecompositionBundle();
00085 DualDecompositionBundle(const GmType&);
00086 DualDecompositionBundle(const GmType&, const Parameter&);
00087 virtual std::string name() const {return "DualDecompositionSubGradient";};
00088 virtual const GmType& graphicalModel() const {return gm_;};
00089 virtual InferenceTermination infer();
00090 template<class VisitorType>
00091 InferenceTermination infer(VisitorType&);
00092 virtual ValueType bound() const;
00093 virtual ValueType value() const;
00094 virtual InferenceTermination arg(std::vector<LabelType>&, const size_t = 1)const;
00095 virtual int evaluate(const ConicBundle::DVector&, double, double&, ConicBundle::DVector&, std::vector<ConicBundle::DVector>&,
00096 std::vector<ConicBundle::PrimalData*>&, ConicBundle::PrimalExtender*&);
00097
00098 private:
00099 virtual void allocate();
00100 virtual DualDecompositionBaseParameter& parameter();
00101 int dualStep(const size_t iteration);
00102 template <class T_IndexType, class T_LabelType>
00103 void getPartialSubGradient(const size_t, const std::vector<T_IndexType>&, std::vector<T_LabelType>&)const;
00104 double euclideanSubGradientNorm();
00105
00106
00107 std::vector<std::vector<LabelType> > subStates_;
00108 ConicBundle::CBSolver* solver;
00109 size_t nullStepCounter_;
00110
00111 Accumulation<ValueType,LabelType,AccumulationType> acUpperBound_;
00112 Accumulation<ValueType,LabelType,AccumulationType> acNegLowerBound_;
00113 ValueType upperBound_;
00114 ValueType lowerBound_;
00115
00116 Parameter para_;
00117 std::vector<ValueType> mem_;
00118 std::vector<ValueType> mem2_;
00119
00120 opengm::Timer primalTimer_;
00121 opengm::Timer dualTimer_;
00122 double primalTime_;
00123 double dualTime_;
00124
00125 };
00126
00127
00128 template<class GM, class INF, class DUALBLOCK>
00129 DualDecompositionBundle<GM,INF,DUALBLOCK>::~DualDecompositionBundle()
00130 {
00131 delete solver;
00132 }
00133
00134 template<class GM, class INF, class DUALBLOCK>
00135 DualDecompositionBundle<GM,INF,DUALBLOCK>::DualDecompositionBundle(const GmType& gm)
00136 : DualDecompositionBase<GmType, DualBlockType >(gm)
00137 {
00138 this->init(para_);
00139 subStates_.resize(subGm_.size());
00140 for(size_t i=0; i<subGm_.size(); ++i)
00141 subStates_[i].resize(subGm_[i].numberOfVariables());
00142
00143 solver = new ConicBundle::CBSolver(para_.noBundle_);
00144
00145 solver->init_problem(numDualsMinimal_);
00146 solver->add_function(*this);
00147 solver->set_out(&std::cout,0);
00148
00149 solver->set_max_bundlesize(*this,para_.maxBundlesize_);
00150
00151
00152 solver->set_active_bounds_fixing(para_.activeBoundFixing_);
00153 solver->set_term_relprec(para_.relativeDualBoundPrecision_);
00154 solver->set_min_weight(para_.minDualWeight_);
00155 solver->set_max_weight(para_.maxDualWeight_);
00156 nullStepCounter_ =0;
00157 }
00158
00159 template<class GM, class INF, class DUALBLOCK>
00160 DualDecompositionBundle<GM,INF,DUALBLOCK>::DualDecompositionBundle(const GmType& gm, const Parameter& para)
00161 : DualDecompositionBase<GmType, DualBlockType >(gm)
00162 {
00163 para_ = para;
00164 this->init(para_);
00165
00166 subStates_.resize(subGm_.size());
00167 for(size_t i=0; i<subGm_.size(); ++i)
00168 subStates_[i].resize(subGm_[i].numberOfVariables());
00169
00170 solver = new ConicBundle::CBSolver(para_.noBundle_);
00171
00172 solver->init_problem(numDualsMinimal_);
00173 solver->add_function(*this);
00174 solver->set_out(&std::cout,0);
00175 solver->set_max_bundlesize(*this,para_.maxBundlesize_);
00176
00177
00178 solver->set_active_bounds_fixing(para.activeBoundFixing_);
00179 solver->set_term_relprec(para_.relativeDualBoundPrecision_);
00180 solver->set_min_weight(para_.minDualWeight_);
00181 solver->set_max_weight(para_.maxDualWeight_);
00182 nullStepCounter_ =0;
00183 }
00184
00185
00187
00188 template <class GM, class INF, class DUALBLOCK>
00189 void DualDecompositionBundle<GM,INF,DUALBLOCK>::allocate()
00190 {
00191 mem_.resize(numDualsOvercomplete_,0);
00192 mem2_.resize(numDualsOvercomplete_,0);
00193 ValueType *data1Front = &mem_[0];
00194 ValueType *data1Back = &mem_[numDualsOvercomplete_];
00195 ValueType *data2Front = &mem2_[0];
00196 ValueType *data2Back = &mem2_[numDualsOvercomplete_];
00197 for(typename std::vector<DualBlockType>::iterator it=dualBlocks_.begin(); it!=dualBlocks_.end(); ++it){
00198 for(size_t i=0; i<(*it).duals_.size(); ++i){
00199 DualVariableType& dv1 = (*it).duals_[i];
00200 DualVariableType& dv2 = (*it).duals2_[i];
00201 if(i+1==(*it).duals_.size()){
00202 data1Back -= dv1.size();
00203 data2Back -= dv2.size();
00204 dv1.assign( dv1.shapeBegin(),dv1.shapeEnd(),data1Back);
00205 dv2.assign( dv2.shapeBegin(),dv2.shapeEnd(),data2Back);
00206 }
00207 else{
00208 dv1.assign( dv1.shapeBegin(),dv1.shapeEnd(),data1Front);
00209 dv2.assign( dv2.shapeBegin(),dv2.shapeEnd(),data2Front);
00210 data1Front += dv1.size();
00211 data2Front += dv2.size();
00212 }
00213 }
00214 }
00215 OPENGM_ASSERT(data1Front == data1Back );
00216 OPENGM_ASSERT(data2Front == data2Back );
00217 OPENGM_ASSERT(data1Front == &mem_[0]+numDualsMinimal_);
00218 OPENGM_ASSERT(data2Front == &mem2_[0]+numDualsMinimal_ );
00219 }
00220
00221 template <class GM, class INF, class DUALBLOCK>
00222 DualDecompositionBaseParameter& DualDecompositionBundle<GM,INF,DUALBLOCK>::parameter()
00223 {
00224 return para_;
00225 }
00226
00228
00229 template<class GM, class INF, class DUALBLOCK>
00230 InferenceTermination DualDecompositionBundle<GM,INF,DUALBLOCK>::
00231 infer()
00232 {
00233 EmptyVisitorType visitor;
00234 return infer(visitor);
00235 }
00236
00237 template<class GM, class INF, class DUALBLOCK>
00238 template<class VisitorType>
00239 InferenceTermination DualDecompositionBundle<GM,INF,DUALBLOCK>::
00240 infer(VisitorType& visitor)
00241 {
00242 std::cout.precision(15);
00243 visitor.begin(*this,this->value(),this->bound());
00244 for(size_t iteration=0; iteration<para_.maximalNumberOfIterations_; ++iteration){
00245
00246 dualTimer_.tic();
00247 int ret;
00248 if(dualBlocks_.size() == 0){
00249
00250 for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
00251 InfType inf(subGm_[subModelId],para_.subPara_);
00252 inf.infer();
00253 inf.arg(subStates_[subModelId]);
00254 }
00255
00256
00257 std::vector<LabelType> temp;
00258 std::vector<LabelType> temp2;
00259 const std::vector<SubVariableListType>& subVariableLists = para_.decomposition_.getVariableLists();
00260 (*this).template getBounds<AccumulationType>(subStates_, subVariableLists, lowerBound_, upperBound_, temp);
00261 acNegLowerBound_(-lowerBound_,temp2);
00262 acUpperBound_(upperBound_, temp);
00263 ret=128;
00264 }
00265 else{
00266 ret = dualStep(iteration);
00267 }
00268 dualTimer_.toc();
00269 dualTime_ = dualTimer_.elapsedTime() - primalTime_;
00270 std::cout.precision(15);
00271 visitor((*this), upperBound_, lowerBound_);
00272
00273
00274 dualTime_ = 0;
00275 primalTime_ = 0;
00276
00277
00278
00279 ValueType o;
00280 AccumulationType::iop(0.0001,-0.0001,o);
00281 OPENGM_ASSERT(AccumulationType::bop(lowerBound_, upperBound_+o));
00282 OPENGM_ASSERT(AccumulationType::bop(-acNegLowerBound_.value(), acUpperBound_.value()+o));
00283
00284 if( fabs(acUpperBound_.value() + acNegLowerBound_.value()) <= para_.minimalAbsAccuracy_
00285 || fabs((acUpperBound_.value()+ acNegLowerBound_.value())/acUpperBound_.value()) <= para_.minimalRelAccuracy_
00286 || ret ==1){
00287 visitor.end((*this), acUpperBound_.value(), -acNegLowerBound_.value());
00288 return NORMAL;
00289 }
00290 if(ret>0){
00291 break;
00292 }
00293 }
00294 visitor.end((*this), acUpperBound_.value(), -acNegLowerBound_.value());
00295 return NORMAL;
00296 }
00297
00298 template<class GM, class INF, class DUALBLOCK>
00299 InferenceTermination DualDecompositionBundle<GM,INF,DUALBLOCK>::
00300 arg(std::vector<LabelType>& conf, const size_t n)const
00301 {
00302 if(n!=1){
00303 return UNKNOWN;
00304 }
00305 else{
00306 acUpperBound_.state(conf);
00307 return NORMAL;
00308 }
00309 }
00310
00311 template<class GM, class INF, class DUALBLOCK>
00312 typename GM::ValueType DualDecompositionBundle<GM,INF,DUALBLOCK>::value() const
00313 {
00314 return acUpperBound_.value();
00315 }
00316
00317 template<class GM, class INF, class DUALBLOCK>
00318 typename GM::ValueType DualDecompositionBundle<GM,INF,DUALBLOCK>::bound() const
00319 {
00320 return -acNegLowerBound_.value();
00321 }
00322
00323
00325
00326 template <class GM, class INF, class DUALBLOCK>
00327 int DualDecompositionBundle<GM,INF,DUALBLOCK>::dualStep(const size_t iteration)
00328 {
00329 int retval;
00330 if(para_.useHeuristicStepsize_){
00331 solver->set_min_weight(para_.minDualWeight_);
00332 solver->set_max_weight(para_.maxDualWeight_);
00333 }
00334 else if(iteration == 0){
00335 solver->set_min_weight(100);
00336 solver->set_max_weight(100);
00337 }
00338 else{
00339 if(solver->get_objval() == solver->get_candidate_value() || iteration==1){
00340
00341 double primalDualGap = fabs(acUpperBound_.value() + acNegLowerBound_.value());
00342
00343 double subgradientNorm = (*this).euclideanSubGradientNorm();
00344 double stepsize = (primalDualGap)/subgradientNorm * para_.stepsizeStride_;
00345
00346 if(para_.minDualWeight_>=0)
00347 stepsize = std::min(1/para_.minDualWeight_, stepsize);
00348 if(para_.maxDualWeight_>=0)
00349 stepsize = std::max(1/para_.maxDualWeight_, stepsize);
00350
00351 double t = 1/stepsize;
00352 solver->set_next_weight(t);
00353 solver->set_min_weight(t);
00354 solver->set_max_weight(t);
00355 nullStepCounter_ =0;
00356 }
00357 else{
00358
00359 ++nullStepCounter_;
00360 }
00361 }
00362
00363 retval=solver->do_descent_step(1);
00364
00365 if (retval){
00366 std::cout<<"descent_step returned "<<retval<<std::endl;
00367 }
00368
00369 return solver->termination_code();
00370 }
00371
00372 template <class GM, class INF, class DUALBLOCK>
00373 int DualDecompositionBundle<GM,INF,DUALBLOCK>::evaluate
00374 (
00375 const ConicBundle::DVector& dual,
00376 double relprec,
00377 double& objective_value,
00378 ConicBundle::DVector& cut_vals,
00379 std::vector<ConicBundle::DVector>& subgradients,
00380 std::vector<ConicBundle::PrimalData*>& primal_solutions,
00381 ConicBundle::PrimalExtender*& primal_extender
00382 )
00383 {
00384 typename std::vector<DualBlockType>::iterator it;
00385 typename SubFactorListType::const_iterator lit;
00386
00387 for(size_t i=0; i<numDualsMinimal_; ++i){
00388 mem_[i] = dual[i];
00389 }
00390 for(it = dualBlocks_.begin(); it != dualBlocks_.end(); ++it){
00391 const size_t numDuals = (*it).duals_.size();
00392 (*it).duals_[numDuals-1] = -(*it).duals_[0];
00393 for(size_t i=1; i<numDuals-1;++i){
00394 (*it).duals_[numDuals-1] -= (*it).duals_[i];
00395 }
00396 }
00397
00398 objective_value=0;
00399 primalTimer_.tic();
00400
00401
00402
00403
00404
00405 for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
00406 InfType inf(subGm_[subModelId],para_.subPara_);
00407 inf.infer();
00408 inf.arg(subStates_[subModelId]);
00409 }
00410 primalTimer_.toc();
00411 primalTime_ += primalTimer_.elapsedTime();
00412
00413
00414 std::vector<LabelType> temp;
00415 std::vector<LabelType> temp2;
00416 const std::vector<SubVariableListType>& subVariableLists = para_.decomposition_.getVariableLists();
00417 (*this).template getBounds<AccumulationType>(subStates_, subVariableLists, lowerBound_, upperBound_, temp);
00418 acNegLowerBound_(-lowerBound_,temp2);
00419 acUpperBound_(upperBound_, temp);
00420 objective_value = -lowerBound_;
00421
00422
00423 std::vector<size_t> s;
00424 mem2_.assign(mem2_.size(),0);
00425 for(it = dualBlocks_.begin(); it != dualBlocks_.end(); ++it){
00426 const size_t numDuals = (*it).duals_.size();
00427 lit = (*((*it).subFactorList_)).begin();
00428 s.resize((*lit).subIndices_.size());
00429 for(size_t i=0; i<numDuals; ++i){
00430 getPartialSubGradient((*lit).subModelId_, (*lit).subIndices_, s);
00431 ++lit;
00432 (*it).duals2_[i](s.begin()) += -1.0;
00433 }
00434 for(size_t i=0; i<numDuals-1; ++i){
00435 (*it).duals2_[i] -= (*it).duals2_[numDuals-1] ;
00436 }
00437 }
00438
00439
00440 ConicBundle::PrimalDVector h(numDualsMinimal_,0);
00441 cut_vals.push_back(objective_value);
00442 for(size_t i=0; i<numDualsMinimal_; ++i){
00443 h[i] = mem2_[i];
00444 }
00445 subgradients.push_back(h);
00446
00447 return 0;
00448 }
00449
00450
00451
00452 template <class GM, class INF, class DUALBLOCK>
00453 template <class T_IndexType, class T_LabelType>
00454 inline void DualDecompositionBundle<GM,INF,DUALBLOCK>::getPartialSubGradient
00455 (
00456 const size_t subModelId,
00457 const std::vector<T_IndexType>& subIndices,
00458 std::vector<T_LabelType> & s
00459 )const
00460 {
00461 OPENGM_ASSERT(subIndices.size() == s.size());
00462 for(size_t n=0; n<s.size(); ++n){
00463 s[n] = subStates_[subModelId][subIndices[n]];
00464 }
00465 }
00466
00467 template <class GM, class INF, class DUALBLOCK>
00468 double DualDecompositionBundle<GM,INF,DUALBLOCK>::euclideanSubGradientNorm()
00469 {
00470 double norm = 0;
00471 std::vector<size_t> s,s2;
00472 typename std::vector<DUALBLOCK>::const_iterator it;
00473 typename SubFactorListType::const_iterator lit;
00474 for(it = dualBlocks_.begin(); it != dualBlocks_.end(); ++it){
00475 const size_t numDuals = (*it).duals_.size();
00476 const SubFactorType& sf = (*((*it).subFactorList_)).back();
00477 lit = (*((*it).subFactorList_)).begin();
00478 s.resize((*lit).subIndices_.size());
00479 s2.resize((*lit).subIndices_.size());
00480 getPartialSubGradient(sf.subModelId_, sf.subIndices_, s2);
00481 for(size_t i=0; i<numDuals-1; ++i){
00482 getPartialSubGradient((*lit).subModelId_, (*lit).subIndices_, s);
00483 ++lit;
00484 if(s!=s2)
00485 norm += 2;
00486 }
00487 }
00488 return sqrt(norm);
00489 }
00490
00491
00492
00493 }
00494 #endif // WITH_CONICBUNDLE
00495 #endif
00496