qpbo.hxx

Go to the documentation of this file.
00001 #pragma once
00002 #ifndef OPENGM_QPBO_HXX
00003 #define OPENGM_QPBO_HXX
00004 
00005 #include "opengm/graphicalmodel/graphicalmodel_factor.hxx"
00006 #include "opengm/graphicalmodel/graphicalmodel.hxx"
00007 #include "opengm/operations/adder.hxx"
00008 #include "opengm/operations/minimizer.hxx"
00009 #include "opengm/inference/inference.hxx"
00010 #include "opengm/inference/visitors/visitor.hxx"
00011 
00012 namespace opengm {
00013    
00018 template<class GM, class MIN_ST_CUT>
00019 class QPBO : public Inference<GM, opengm::Minimizer>
00020 {
00021 public:
00022    typedef GM GraphicalModelType;
00023    typedef opengm::Minimizer AccumulationType;
00024    OPENGM_GM_TYPE_TYPEDEFS;
00025    typedef VerboseVisitor<QPBO<GM,MIN_ST_CUT> > VerboseVisitorType;
00026    typedef TimingVisitor<QPBO<GM,MIN_ST_CUT> > TimingVisitorType;
00027    typedef EmptyVisitor<QPBO<GM,MIN_ST_CUT> > EmptyVisitorType;
00028 
00029    struct Parameter {};
00030 
00031    QPBO(const GraphicalModelType&, Parameter = Parameter());
00032    std::string name() const;
00033    const GraphicalModelType& graphicalModel() const;
00034    InferenceTermination infer();
00035    template<class VISITOR>
00036       InferenceTermination infer(VISITOR &);
00037    InferenceTermination arg(std::vector<LabelType>&, const size_t& = 1) const;
00038    double partialOptimality(std::vector<bool>&) const;
00039 
00040 private:
00041    void addUnaryFactorType(const FactorType& factor);
00042    void addUnaryFactorType(size_t var, ValueType value0, ValueType value1);
00043    void addEdgeCapacity(size_t v,size_t w, ValueType val);
00044    void addPairwiseFactorType(const FactorType& factor);
00045    void addPairwiseFactorType(size_t var0,size_t var1,ValueType A,ValueType B,ValueType C,ValueType D);
00046 
00047    // get the index of the opposite literal in the graph_
00048    size_t neg(size_t var) const { return (var+numVars_)%(2*numVars_); }
00049 
00050    const GraphicalModelType& gm_;
00051    //std::vector<LabelType> state_;
00052    std::vector<bool> stateBool_;
00053    size_t numVars_;
00054    ValueType constTerm_;
00055    MIN_ST_CUT minStCut_;
00056    ValueType tolerance_;
00057    size_t source_;
00058    size_t sink_;
00059 };
00060 
00061 template<class GM,class MIN_ST_CUT>
00062 QPBO<GM,MIN_ST_CUT>::QPBO
00063 (
00064    const GM & gm,
00065    typename QPBO<GM,MIN_ST_CUT>::Parameter
00066 )
00067 :  gm_(gm),
00068    numVars_(gm_.numberOfVariables()),
00069    minStCut_(2*gm_.numberOfVariables()+2, 6*gm_.numberOfVariables()) 
00070 {
00071    constTerm_ = 0;
00072    source_ = 2*numVars_;
00073    sink_   = 2*numVars_ + 1;
00074 
00075    // add pairwise factors
00076    for(size_t j=0; j<gm_.numberOfFactors(); ++j) {
00077       switch (gm_[j].numberOfVariables()) {
00078       case 0:
00079       {
00080          size_t c[]={0};
00081          constTerm_ += gm_[j](c);
00082       }
00083       break;
00084       case 1:
00085          addUnaryFactorType(gm_[j]);
00086          break;
00087       case 2:
00088          addPairwiseFactorType(gm_[j]);
00089          break;
00090       default: throw std::runtime_error("This implementation of the QPBO optimizer does not support factors of order >2.");
00091       }
00092    }
00093 }
00094 
00095 template<class GM,class MIN_ST_CUT>
00096 inline std::string
00097 QPBO<GM,MIN_ST_CUT>::name() const
00098 {
00099    return "QPBO";
00100 }
00101 
00102 template<class GM,class MIN_ST_CUT>
00103 inline const typename QPBO<GM,MIN_ST_CUT>::GraphicalModelType&
00104 QPBO<GM,MIN_ST_CUT>::graphicalModel() const
00105 {
00106    return gm_;
00107 }
00108 
00109 template<class GM,class MIN_ST_CUT>
00110 inline InferenceTermination
00111 QPBO<GM,MIN_ST_CUT>::infer() {
00112    EmptyVisitorType v;
00113    return infer(v);
00114 }
00115 
00116 template<class GM,class MIN_ST_CUT>
00117 template<class VISITOR>
00118 inline InferenceTermination
00119 QPBO<GM,MIN_ST_CUT>::infer(VISITOR & visitor) 
00120 {
00121    minStCut_.calculateCut(stateBool_);
00122    return NORMAL;
00123 }
00124 
00125 template<class GM,class MIN_ST_CUT>
00126 inline InferenceTermination
00127 QPBO<GM,MIN_ST_CUT>::arg
00128 (
00129    std::vector<LabelType>& arg,
00130    const size_t& n
00131    ) const
00132 {
00133    if(n > 1) {
00134       return UNKNOWN;
00135    }
00136    else {
00137       arg.resize(numVars_);
00138       for(size_t j=0; j<arg.size(); ++j) {
00139          if (stateBool_[j+2] == true && stateBool_[neg(j)+2] == false)
00140             arg[j] = 1;
00141          else if (stateBool_[j+2] == false && stateBool_[neg(j)+2] == true)
00142             arg[j] = 0;
00143          else
00144             arg[j] = 0; // select 0 or 1
00145       }
00146       return NORMAL;
00147    }
00148 }
00149 
00150 template<class GM,class MIN_ST_CUT>
00151 double
00152 QPBO<GM,MIN_ST_CUT>::partialOptimality
00153 (
00154    std::vector<bool>& optVec
00155    ) const
00156 {
00157    double opt = 0;
00158    optVec.resize(numVars_);
00159    for(size_t j=0; j<optVec.size(); ++j)
00160       if (stateBool_[j+2] != stateBool_[neg(j)+2]) {
00161          arg[j] = true;
00162          opt++;
00163       } else
00164          arg[j] = false;
00165 
00166    return opt/gm_.numerOfVariables();
00167 }
00168 
00169 template<class GM,class MIN_ST_CUT>
00170 void inline
00171 QPBO<GM,MIN_ST_CUT>::addEdgeCapacity(size_t v, size_t w, ValueType val)
00172 {
00173    minStCut_.addEdge((v+2)%(2*numVars_+2),(w+2)%(2*numVars_+2),val);
00174 }
00175 
00176 template<class GM,class MIN_ST_CUT>
00177 void
00178 QPBO<GM,MIN_ST_CUT>::addUnaryFactorType(const FactorType& factor)
00179 {
00180    // indices of literal nodes in graph_
00181    size_t x_i  = factor.variableIndex(0);
00182    size_t nx_i = neg(x_i);
00183 
00184    // conversion to normal form on-the-fly: c_[n]x_i are the new
00185    // values of the unary factor.
00186    size_t c[]={0};
00187    ValueType c_nx_i = factor(c);
00188    c[0]=1;
00189    ValueType c_x_i  = factor(c);
00190 
00191    // has to be zero
00192    ValueType delta = std::min(c_nx_i, c_x_i);
00193    c_nx_i     -= delta;
00194    c_x_i      -= delta;
00195    constTerm_ += delta;
00196 
00197    addEdgeCapacity(x_i,    sink_, 0.5*c_nx_i);
00198    addEdgeCapacity(source_, nx_i, 0.5*c_nx_i);
00199 
00200    addEdgeCapacity(nx_i,   sink_, 0.5*c_x_i);
00201    addEdgeCapacity(source_,  x_i, 0.5*c_x_i);
00202 }
00203 
00204 template<class GM,class MIN_ST_CUT>
00205 void
00206 QPBO<GM,MIN_ST_CUT>::addPairwiseFactorType
00207 (
00208    const FactorType& factor
00209 ) {
00210    // indices of literal nodes in graph_
00211    size_t x_i  = factor.variableIndex(0);
00212    size_t x_j  = factor.variableIndex(1);
00213    size_t nx_i = neg(x_i);
00214    size_t nx_j = neg(x_j);
00215 
00216    // conversion to normal form on-the-fly: c_[n]x_i_[n]x_j are the new
00217    // values of the pairwise factors. delta_c_[n]x_{i,j} are changes that have
00218    // to be made to the unary factors.
00219 
00220    size_t c[]={0,0};
00221    ValueType c_nx_i_nx_j = factor(c);
00222    c[1]=1;
00223    ValueType c_nx_i_x_j  = factor(c);
00224    c[0]=1;
00225    c[1]=0;
00226    ValueType c_x_i_nx_j  = factor(c);
00227    c[1]=1;
00228    ValueType c_x_i_x_j   = factor(c);
00229 
00230    ValueType delta_c_nx_j = 0;
00231    ValueType delta_c_x_j  = 0;
00232    ValueType delta_c_nx_i = 0;
00233    ValueType delta_c_x_i  = 0;
00234 
00235    // hast to be zero
00236    ValueType delta = std::min(c_nx_i_nx_j, c_x_i_nx_j);
00237    if (delta != 0) {
00238 
00239       c_nx_i_nx_j  -= delta;
00240       c_x_i_nx_j   -= delta;
00241       delta_c_nx_j += delta;
00242    }
00243 
00244    // has to be zero
00245    delta = std::min(c_nx_i_x_j, c_x_i_x_j);
00246    if (delta != 0) {
00247 
00248       c_nx_i_x_j  -= delta;
00249       c_x_i_x_j   -= delta;
00250       delta_c_x_j += delta;
00251    }
00252 
00253    // has to be zero
00254    delta = std::min(c_nx_i_nx_j, c_nx_i_x_j);
00255    if (delta != 0) {
00256 
00257       c_nx_i_nx_j  -= delta;
00258       c_nx_i_x_j   -= delta;
00259       delta_c_nx_i += delta;
00260    }
00261 
00262    // has to be zero
00263    delta = std::min(c_x_i_nx_j, c_x_i_x_j);
00264    if (delta != 0) {
00265 
00266       c_x_i_nx_j  -= delta;
00267       c_x_i_x_j   -= delta;
00268       delta_c_x_i += delta;
00269    }
00270 
00271    // for every non-zero c_[n]x_i_[n]x_j add two edges to the flow network
00272 
00273    if (c_nx_i_nx_j != 0) {
00274       addEdgeCapacity(x_i,  nx_j, 0.5*c_nx_i_nx_j);
00275       addEdgeCapacity(x_j,  nx_i, 0.5*c_nx_i_nx_j);
00276    }
00277    if (c_nx_i_x_j != 0) {
00278       addEdgeCapacity(x_i,   x_j, 0.5*c_nx_i_x_j);
00279       addEdgeCapacity(nx_j, nx_i, 0.5*c_nx_i_x_j);
00280    }
00281    if (c_x_i_nx_j != 0) {
00282       addEdgeCapacity(nx_i, nx_j, 0.5*c_x_i_nx_j);
00283       addEdgeCapacity(x_j,   x_i, 0.5*c_x_i_nx_j);
00284    }
00285    if (c_x_i_x_j != 0) {
00286       addEdgeCapacity(nx_i,  x_j, 0.5*c_x_i_x_j);
00287       addEdgeCapacity(nx_j,  x_i, 0.5*c_x_i_x_j);
00288    }
00289 
00290    // for every non-zero c_[n]x_{i,j} add two edges to the flow network
00291 
00292    if (delta_c_nx_j != 0) {
00293       addEdgeCapacity(x_j,    sink_, 0.5*delta_c_nx_j);
00294       addEdgeCapacity(source_, nx_j, 0.5*delta_c_nx_j);
00295    }
00296    if (delta_c_x_j != 0) {
00297       addEdgeCapacity(nx_j,   sink_, 0.5*delta_c_x_j);
00298       addEdgeCapacity(source_,  x_j, 0.5*delta_c_x_j);
00299    }
00300    if (delta_c_nx_i != 0) {
00301       addEdgeCapacity(x_i,    sink_, 0.5*delta_c_nx_i);
00302       addEdgeCapacity(source_, nx_i, 0.5*delta_c_nx_i);
00303    }
00304    if (delta_c_x_i != 0) {
00305       addEdgeCapacity(nx_i,   sink_, 0.5*delta_c_x_i);
00306       addEdgeCapacity(source_,  x_i, 0.5*delta_c_x_i);
00307    }
00308 }
00309 
00310 } // namespace opengm
00311 
00312 #endif // #ifndef OPENGM_EXTERNAL_QPBO_HXX
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Mon Jun 17 16:31:05 2013 for OpenGM by  doxygen 1.6.3