00001 #pragma once
00002 #ifndef OPENGM_DUALDECOMPOSITION_BASE_HXX
00003 #define OPENGM_DUALDECOMPOSITION_BASE_HXX
00004
00005 #include <vector>
00006 #include <string>
00007 #include <iostream>
00008 #include <cmath>
00009 #include <limits>
00010
00011 #include "opengm/opengm.hxx"
00012 #include "opengm/graphicalmodel/decomposition/graphicalmodeldecomposition.hxx"
00013 #include "opengm/graphicalmodel/decomposition/graphicalmodeldecomposer.hxx"
00014 #include "opengm/functions/modelviewfunction.hxx"
00015 #include "opengm/datastructures/marray/marray.hxx"
00016 #include "opengm/utilities/tribool.hxx"
00017 #include "opengm/inference/dualdecomposition/dddualvariableblock.hxx"
00018 #include <opengm/utilities/timer.hxx>
00019
00020 namespace opengm {
00021
00022 class DualDecompositionBaseParameter{
00023 public:
00024 enum DecompositionId {MANUAL, TREE, SPANNINGTREES, BLOCKS};
00025 enum DualUpdateId {ADAPTIVE, STEPSIZE, STEPLENGTH, KIEWIL};
00026
00028 DecompositionId decompositionId_;
00030 GraphicalModelDecomposition decomposition_;
00032 size_t maximalDualOrder_;
00034 size_t numberOfBlocks_;
00036 size_t maximalNumberOfIterations_;
00038 double minimalAbsAccuracy_;
00040 double minimalRelAccuracy_;
00042 size_t numberOfThreads_;
00043
00044
00045 double stepsizeStride_;
00046 double stepsizeScale_;
00047 double stepsizeExponent_;
00048 double stepsizeMin_;
00049 double stepsizeMax_;
00050 bool stepsizePrimalDualGapStride_;
00051 bool stepsizeNormalizedSubgradient_;
00052
00053
00054 DualDecompositionBaseParameter() :
00055 decompositionId_(SPANNINGTREES),
00056 maximalDualOrder_(std::numeric_limits<size_t>::max()),
00057 numberOfBlocks_(2),
00058 maximalNumberOfIterations_(100),
00059 minimalAbsAccuracy_(0.0),
00060 minimalRelAccuracy_(0.0),
00061 numberOfThreads_(1),
00062 stepsizeStride_(1),
00063 stepsizeScale_(1),
00064 stepsizeExponent_(0.5),
00065 stepsizeMin_(0),
00066 stepsizeMax_(std::numeric_limits<double>::infinity()),
00067 stepsizePrimalDualGapStride_(false),
00068 stepsizeNormalizedSubgradient_(false)
00069
00070 {};
00071
00072 double getStepsize(size_t iteration, double primalDualGap, double subgradientNorm){
00073 OPENGM_ASSERT(iteration>=0);
00074 double stepsize = stepsizeStride_;
00075 if(stepsizePrimalDualGapStride_){
00076 stepsize *= fabs(primalDualGap) / subgradientNorm / subgradientNorm;
00077 }
00078 else{
00079 stepsize /= (1+std::pow( stepsizeScale_*(double)(iteration),stepsizeExponent_));
00080 if(stepsizeNormalizedSubgradient_)
00081 stepsize /= subgradientNorm;
00082 }
00083
00084
00085
00086
00087 return stepsize;
00088 }
00089 };
00090
00092 template<class DD>
00093 class DualDecompositionEmptyVisitor {
00094 public:
00095 typedef DD DDType;
00096 typedef typename DDType::ValueType ValueType;
00097
00098 void operator()(
00099 const DDType& dd,
00100 const ValueType bound, const ValueType bestBound,
00101 const ValueType value, const ValueType bestValue,
00102 double primalTime, double dualTime
00103 )
00104 {;}
00105 void startInference(){;}
00106 };
00107
00109 template<class DD>
00110 class DualDecompositionVisitor {
00111 public:
00112 typedef DD DDType;
00113 typedef typename DDType::ValueType ValueType;
00114
00115 void operator()(
00116 const DDType& dd,
00117 const ValueType bound, const ValueType bestBound,
00118 const ValueType value, const ValueType bestValue,
00119 const double primalTime, const double dualTime
00120 )
00121 {
00122 totalTimer_.toc();
00123 if(times_.size()==0)
00124 times_.push_back(totalTimer_.elapsedTime());
00125 else
00126 times_.push_back(times_.back() + totalTimer_.elapsedTime());
00127 values_.push_back(value);
00128 bounds_.push_back(bound);
00129 primalTimes_.push_back(primalTime);
00130 dualTimes_.push_back(dualTime);
00131
00132
00133
00134
00135
00136
00137
00138 totalTimer_.tic();
00139 }
00140 void startInference(){totalTimer_.tic();}
00141 const std::vector<ValueType>& values(){return values_;}
00142 const std::vector<ValueType>& bounds(){return bounds_;}
00143 const std::vector<double>& times(){return times_;}
00144 const std::vector<double>& primalTimes(){return primalTimes_;}
00145 const std::vector<double>& dualTimes(){return dualTimes_;}
00146
00147 private:
00148 std::vector<ValueType> values_;
00149 std::vector<ValueType> bounds_;
00150 std::vector<double> times_;
00151 std::vector<double> primalTimes_;
00152 std::vector<double> dualTimes_;
00153 opengm::Timer totalTimer_;
00154 };
00155
00157 template<class GM, class DUALBLOCK>
00158 class DualDecompositionBase
00159 {
00160 public:
00161 typedef GM GmType;
00162 typedef GM GraphicalModelType;
00163 typedef DUALBLOCK DualBlockType;
00164 typedef typename DualBlockType::DualVariableType DualVariableType;
00165 OPENGM_GM_TYPE_TYPEDEFS;
00166 typedef ModelViewFunction<GmType, DualVariableType> ViewFunctionType;
00167 typedef GraphicalModel<ValueType, OperatorType, typename meta::TypeListGenerator<ViewFunctionType>::type, opengm::DiscreteSpace<IndexType,LabelType> > SubGmType;
00168
00169
00170 typedef GraphicalModelDecomposition DecompositionType;
00171 typedef typename DecompositionType::SubVariable SubVariableType;
00172 typedef typename DecompositionType::SubVariableListType SubVariableListType;
00173 typedef typename DecompositionType::SubFactor SubFactorType;
00174 typedef typename DecompositionType::SubFactorListType SubFactorListType;
00175
00176
00177 DualDecompositionBase(const GmType&);
00178 void init(DualDecompositionBaseParameter&);
00179 const SubGmType& subModel(size_t subModelId) const {return subGm_[subModelId];};
00180
00181 protected:
00182 template<class ITERATOR> void addDualBlock(const SubFactorListType&,ITERATOR,ITERATOR);
00183 std::vector<DualVariableType*> getDualPointers(size_t);
00184 template<class ACC> void getBounds(const std::vector<std::vector<LabelType> >&, const std::vector<SubVariableListType>&, ValueType&, ValueType&, std::vector<LabelType>&);
00185 double subGradientNorm(double L=1) const;
00186 virtual DualDecompositionBaseParameter& parameter() = 0;
00187 virtual void allocate() = 0;
00188
00189 const GmType& gm_;
00190 std::vector<SubGmType> subGm_;
00191 std::vector<DualBlockType> dualBlocks_;
00192 size_t numDualsOvercomplete_;
00193 size_t numDualsMinimal_;
00194 std::vector<Tribool> modelWithSameVariables_;
00195 };
00196
00198 template<class DUALVAR> struct DDIsView {static bool isView(){return false;}};
00199 template<> struct DDIsView<marray::View<double,false> > {static bool isView(){return true;}};
00200 template<> struct DDIsView<marray::View<double,true> > {static bool isView(){return true;}};
00201 template<> struct DDIsView<marray::View<float,false> > {static bool isView(){return true;}};
00202 template<> struct DDIsView<marray::View<float,true> > {static bool isView(){return true;}};
00204
00206
00207 template<class DUALVAR, class T>
00208 void DualVarAssign(DUALVAR& dv,T* t)
00209 {
00210 }
00211
00212 template <class T>
00213 void DualVarAssign(marray::View<T,false>& dv, T* t)
00214 {
00215 dv.assign( dv.shapeBegin(),dv.shapeEnd(),t);
00216 }
00217
00218 template<class GM, class DUALBLOCK>
00219 DualDecompositionBase<GM, DUALBLOCK>::DualDecompositionBase(const GmType& gm):gm_(gm)
00220 {}
00221
00222 template<class GM, class DUALBLOCK>
00223 void DualDecompositionBase<GM, DUALBLOCK>::init(DualDecompositionBaseParameter& para)
00224 {
00225 if(para.decompositionId_ == DualDecompositionBaseParameter::TREE){
00226 opengm::GraphicalModelDecomposer<GmType> decomposer;
00227 para.decomposition_ = decomposer.decomposeIntoTree(gm_);
00228 para.decomposition_.reorder();
00229 para.decomposition_.complete();
00230 para.maximalDualOrder_ = 1;
00231 }
00232 if(para.decompositionId_ == DualDecompositionBaseParameter::SPANNINGTREES){
00233 opengm::GraphicalModelDecomposer<GmType> decomposer;
00234 para.decomposition_ = decomposer.decomposeIntoSpanningTrees(gm_);
00235 para.decomposition_.reorder();
00236 para.decomposition_.complete();
00237 para.maximalDualOrder_ = 1;
00238 }
00239 if(para.decompositionId_ == DualDecompositionBaseParameter::BLOCKS){
00240 opengm::GraphicalModelDecomposer<GmType> decomposer;
00241 para.decomposition_ = decomposer.decomposeIntoClosedBlocks(gm_,para.numberOfBlocks_);
00242 para.decomposition_.reorder();
00243 para.decomposition_.complete();
00244 para.maximalDualOrder_ = 1;
00245 }
00246
00247 OPENGM_ASSERT(para.decomposition_.isValid(gm_));
00248
00249
00250 const std::vector<SubVariableListType>& subVariableLists = para.decomposition_.getVariableLists();
00251 const std::vector<SubFactorListType>& subFactorLists = para.decomposition_.getFactorLists();
00252 const std::map<std::vector<size_t>,SubFactorListType>& emptySubFactorLists = para.decomposition_.getEmptyFactorLists();
00253 const size_t numberOfSubModels = para.decomposition_.numberOfSubModels();
00254
00255 modelWithSameVariables_.resize(numberOfSubModels,Tribool::Maybe);
00256
00257 typename SubVariableListType::const_iterator it;
00258 typename SubFactorListType::const_iterator it2;
00259 typename SubFactorListType::const_iterator it3;
00260 typename std::map<std::vector<size_t>,SubFactorListType>::const_iterator it4;
00261
00262
00263 std::vector<std::vector<size_t> > numStates(numberOfSubModels);
00264 for(size_t subModelId=0; subModelId<numberOfSubModels; ++subModelId){
00265 numStates[subModelId].resize(para.decomposition_.numberOfSubVariables(subModelId),0);
00266 }
00267
00268 for(size_t varId=0; varId<gm_.numberOfVariables(); ++varId){
00269 for(it = subVariableLists[varId].begin(); it!=subVariableLists[varId].end();++it){
00270 numStates[(*it).subModelId_][(*it).subVariableId_] = gm_.numberOfLabels(varId);
00271 }
00272 }
00273
00274 subGm_.resize(numberOfSubModels);
00275 for(size_t subModelId=0; subModelId<numberOfSubModels; ++subModelId){
00276 subGm_[subModelId] = SubGmType(opengm::DiscreteSpace<IndexType,LabelType>(numStates[subModelId].begin(),numStates[subModelId].end()));
00277 }
00278
00279
00280 numDualsOvercomplete_ = 0;
00281 numDualsMinimal_ = 0;
00282
00283 for(size_t factorId=0; factorId<gm_.numberOfFactors(); ++factorId){
00284 if(subFactorLists[factorId].size()>1 && (gm_[factorId].numberOfVariables() <= para.maximalDualOrder_)){
00285 addDualBlock(subFactorLists[factorId], gm_[factorId].shapeBegin(), gm_[factorId].shapeEnd());
00286 numDualsOvercomplete_ += subFactorLists[factorId].size() * gm_[factorId].size();
00287 numDualsMinimal_ += (subFactorLists[factorId].size()-1) * gm_[factorId].size();
00288 }
00289 }
00290
00291 for(it4=emptySubFactorLists.begin() ; it4 != emptySubFactorLists.end(); it4++ ){
00292 if((*it4).second.size()>1 && ((*it4).first.size() <= para.maximalDualOrder_)){
00293 std::vector<size_t> shape((*it4).first.size());
00294 size_t temp = 1;
00295 for(size_t i=0; i<(*it4).first.size(); ++i){
00296 shape[i] = gm_.numberOfLabels((*it4).first[i]);
00297 temp *= gm_.numberOfLabels((*it4).first[i]);
00298 }
00299 numDualsOvercomplete_ += (*it4).second.size() * temp;
00300 numDualsMinimal_ += ((*it4).second.size()-1) * temp;
00301 addDualBlock((*it4).second,shape.begin(),shape.end());
00302 }
00303 }
00304
00305
00306 this->allocate();
00307
00308
00309 size_t dualCounter = 0;
00310 for(size_t factorId=0; factorId<gm_.numberOfFactors(); ++factorId){
00311 if(subFactorLists[factorId].size()>1 && (gm_[factorId].numberOfVariables() <= para.maximalDualOrder_)){
00312 std::vector<DualVariableType*> offsets = getDualPointers(dualCounter++);
00313 size_t i=0;
00314 for(it2 = subFactorLists[factorId].begin(); it2!=subFactorLists[factorId].end();++it2){
00315 OPENGM_ASSERT(offsets[i]->dimension() == gm_[factorId].numberOfVariables());
00316 for(size_t j=0; j<offsets[i]->dimension();++j)
00317 OPENGM_ASSERT(offsets[i]->shape(j) == gm_[factorId].shape(j));
00318
00319 const size_t subModelId = (*it2).subModelId_;
00320 const ViewFunctionType function(gm_,factorId, 1.0/subFactorLists[factorId].size(),offsets[i++]);
00321 const typename SubGmType::FunctionIdentifier funcId = subGm_[subModelId].addFunction(function);
00322 subGm_[subModelId].addFactor(funcId,(*it2).subIndices_.begin(),(*it2).subIndices_.end());
00323 }
00324 }
00325 else{
00326 for(it2 = subFactorLists[factorId].begin(); it2!=subFactorLists[factorId].end();++it2){
00327 const size_t subModelId = (*it2).subModelId_;
00328 const ViewFunctionType function(gm_,factorId, 1.0/subFactorLists[factorId].size());
00329 const typename SubGmType::FunctionIdentifier funcId = subGm_[subModelId].addFunction(function);
00330 subGm_[subModelId].addFactor(funcId,(*it2).subIndices_.begin(),(*it2).subIndices_.end());
00331 }
00332 }
00333 }
00334
00335 for(it4=emptySubFactorLists.begin() ; it4 != emptySubFactorLists.end(); it4++ ){
00336 if((*it4).second.size()>1 && ((*it4).first.size() <= para.maximalDualOrder_)){
00337 size_t i=0;
00338 std::vector<DualVariableType*> offsets = getDualPointers(dualCounter++);
00339 for(it3 = (*it4).second.begin(); it3!=(*it4).second.end();++it3){
00340 const size_t subModelId = (*it3).subModelId_;
00341 const ViewFunctionType function(offsets[i++]);
00342 const typename SubGmType::FunctionIdentifier funcId = subGm_[subModelId].addFunction(function);
00343 subGm_[subModelId].addFactor(funcId,(*it3).subIndices_.begin(),(*it3).subIndices_.end());
00344 }
00345 }
00346 }
00347 }
00348
00349
00350
00351 template<class GM, class DUALBLOCK>
00352 template <class ITERATOR>
00353 inline void DualDecompositionBase<GM,DUALBLOCK>::addDualBlock(const SubFactorListType& c,ITERATOR shapeBegin, ITERATOR shapeEnd)
00354 {
00355 dualBlocks_.push_back(DualBlockType(c,shapeBegin,shapeEnd));
00356 return;
00357 }
00358
00359
00360
00361 template<class GM, class DUALBLOCK>
00362 inline std::vector<typename DUALBLOCK::DualVariableType*> DualDecompositionBase<GM,DUALBLOCK>::getDualPointers(size_t dualBlockId)
00363 {
00364 return dualBlocks_[dualBlockId].getPointers();
00365 }
00366
00367 template<class GM, class DUALBLOCK>
00368 template <class ACC>
00369 void DualDecompositionBase<GM,DUALBLOCK>::getBounds
00370 (
00371 const std::vector<std::vector<LabelType> >& subStates,
00372 const std::vector<SubVariableListType>& subVariableLists,
00373 ValueType& lowerBound,
00374 ValueType& upperBound,
00375 std::vector<LabelType> & upperState
00376 )
00377 {
00378
00379 lowerBound=0;
00380 for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
00381 lowerBound += subGm_[subModelId].evaluate(subStates[subModelId]);
00382 }
00383
00384
00385 Accumulation<ValueType,LabelType,ACC> ac;
00386
00387
00388 if(modelWithSameVariables_[0] == Tribool::Maybe){
00389 for(size_t varId=0; varId<gm_.numberOfVariables(); ++varId){
00390 for(typename SubVariableListType::const_iterator its = subVariableLists[varId].begin();
00391 its!=subVariableLists[varId].end();++its){
00392 const size_t& subModelId = (*its).subModelId_;
00393 const size_t& subVariableId = (*its).subVariableId_;
00394 if(subVariableId != varId){
00395 modelWithSameVariables_[subModelId] = Tribool::False;
00396 }
00397 }
00398 }
00399 for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
00400 if(gm_.numberOfVariables() != subGm_[subModelId].numberOfVariables()){
00401 modelWithSameVariables_[subModelId] = Tribool::False;
00402 }
00403 if(modelWithSameVariables_[subModelId] == Tribool::Maybe){
00404 modelWithSameVariables_[subModelId] = Tribool::True;
00405 }
00406 }
00407 }
00408
00409
00410 std::vector<std::vector<LabelType> > args(subGm_.size());
00411 bool somethingToFill = false;
00412 for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
00413 if(modelWithSameVariables_[subModelId] == Tribool::False){
00414 args[subModelId].assign(gm_.numberOfVariables(),std::numeric_limits<LabelType>::max());
00415 somethingToFill = true;
00416 }
00417 else{
00418 ac(gm_.evaluate(subStates[subModelId]),subStates[subModelId]);
00419 }
00420 }
00421
00422 if(somethingToFill){
00423 for(size_t varId=0; varId<gm_.numberOfVariables(); ++varId){
00424 for(typename SubVariableListType::const_iterator its = subVariableLists[varId].begin();
00425 its!=subVariableLists[varId].end();++its){
00426 const size_t& subModelId = (*its).subModelId_;
00427 const size_t& subVariableId = (*its).subVariableId_;
00428 if(modelWithSameVariables_[subModelId] == Tribool::False){
00429 args[subModelId][varId] = subStates[subModelId][subVariableId];
00430 }
00431 }
00432 for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
00433 if(modelWithSameVariables_[subModelId] == Tribool::False &&
00434 args[subModelId][varId] == std::numeric_limits<LabelType>::max())
00435 {
00436 const size_t& aSubModelId = subVariableLists[varId].front().subModelId_;
00437 const size_t& aSubVariableId = subVariableLists[varId].front().subVariableId_;
00438 args[subModelId][varId] = subStates[aSubModelId][aSubVariableId];
00439 }
00440 }
00441 }
00442 for(size_t subModelId=0; subModelId<subGm_.size(); ++subModelId){
00443 if(modelWithSameVariables_[subModelId] == Tribool::False){
00444 ac(gm_.evaluate(args[subModelId]),args[subModelId]);
00445 }
00446 }
00447 }
00448
00449 upperBound = ac.value();
00450 ac.state(upperState);
00451 }
00452
00453 template <class GM, class DUALBLOCK>
00454 double DualDecompositionBase<GM,DUALBLOCK>::subGradientNorm(double L) const
00455 {
00456 double norm = 0;
00457 typename std::vector<DualBlockType>::const_iterator it;
00458 for(it = dualBlocks_.begin(); it != dualBlocks_.end(); ++it){
00459 norm += (*it).duals_.size();
00460 }
00461 norm = pow(norm,1.0/L);
00462 return norm;
00463 }
00464
00465 }
00466
00467 #endif