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
00048 size_t neg(size_t var) const { return (var+numVars_)%(2*numVars_); }
00049
00050 const GraphicalModelType& gm_;
00051
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
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;
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
00181 size_t x_i = factor.variableIndex(0);
00182 size_t nx_i = neg(x_i);
00183
00184
00185
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
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
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
00217
00218
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
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
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
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
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
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
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 }
00311
00312 #endif // #ifndef OPENGM_EXTERNAL_QPBO_HXX