2 #ifndef OPENGM_MQPBO_HXX
3 #define OPENGM_MQPBO_HXX
18 #ifdef MQPBOHotFixOutPutPartialOPtimalityMap
36 template<
class GM,
class ACC>
54 std::vector<LabelType>
label_;
64 std::string
name()
const;
68 typename GM::ValueType
bound()
const;
69 typename GM::ValueType
value()
const;
70 template<
class VisitorType>
74 void setStartingPoint(
typename std::vector<typename GM::LabelType>::const_iterator);
90 kolmogorov::qpbo::QPBO<GraphValueType>* qpbo_;
96 std::vector<std::vector<LabelType> > permutation_;
97 std::vector<std::vector<LabelType> > inversePermutation_;
98 std::vector<std::vector<opengm::Tribool> > partialOptimality_;
99 std::vector<bool> optimal_;
100 std::vector<LabelType> label_;
101 std::vector<size_t> variableOffset_;
106 GraphValueType scale;
112 template<
class GM,
class ACC>
122 for(
size_t j = 0; j < gm_.numberOfFactors(); ++j) {
123 if(gm_[j].numberOfVariables() > 2) {
124 throw RuntimeError(
"This implementation of MQPBO supports only factors of order <= 2.");
129 permutation_.resize(gm_.numberOfVariables());
130 inversePermutation_.resize(gm_.numberOfVariables());
131 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
132 permutation_[var].resize(gm_.numberOfLabels(var));
133 inversePermutation_[var].resize(gm_.numberOfLabels(var));
137 partialOptimality_.resize(gm_.numberOfVariables());
138 optimal_.resize(gm_.numberOfVariables(),
false);
139 label_.resize(gm_.numberOfVariables());
140 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
148 variableOffset_.resize(gm_.numberOfVariables(),0);
149 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
150 variableOffset_[var] = numNodes_;
151 numNodes_ += gm_.numberOfLabels(var)-1;
153 for(
IndexType var=1; var<gm_.numberOfVariables(); ++var){
154 OPENGM_ASSERT( variableOffset_[var-1]< variableOffset_[var]);
157 for(
IndexType f=0; f<gm_.numberOfFactors(); ++f){
158 if(gm_[f].numberOfVariables()==1)
159 numEdges_ += gm_[f].numberOfLabels(0)-2;
160 if(gm_[f].numberOfVariables()==2){
161 numEdges_ += (gm_[f].numberOfLabels(0)-1);
166 if(param_.rounds_>0){
167 std::cout <<
"Large" <<std::endl;
168 qpbo_ =
new kolmogorov::qpbo::QPBO<GraphValueType > (numNodes_, numEdges_);
169 qpbo_->AddNode(numNodes_);
172 std::cout <<
"Small" <<std::endl;
173 qpbo_ =
new kolmogorov::qpbo::QPBO<GraphValueType > (gm_.numberOfVariables(), numSOF);
174 qpbo_->AddNode(gm_.numberOfVariables());
178 template<
class GM,
class ACC>
188 template<
class GM,
class ACC>
196 template<
class GM,
class ACC>
200 typename std::vector<typename GM::LabelType>::const_iterator begin
206 template<
class GM,
class ACC>
213 template<
class GM,
class ACC>
221 template<
class GM,
class ACC>
224 qpbo_->AddUnaryTerm(var, scale*v0, scale*v1);
227 template<
class GM,
class ACC>
229 MQPBO<GM,ACC>::AddPairwiseTerm(
int var0,
int var1,ValueType v00,ValueType v01,ValueType v10,ValueType v11){
230 qpbo_->AddPairwiseTerm(var0, var1,scale*v00,scale*v01,scale*v10,scale*v11);
233 template<
class GM,
class ACC>
238 qpbo_->AddNode(gm_.numberOfVariables());
239 for(
size_t f = 0; f < gm_.numberOfFactors(); ++f) {
240 if(gm_[f].numberOfVariables() == 0) {
243 else if(gm_[f].numberOfVariables() == 1) {
244 const LabelType numLabels = gm_[f].numberOfLabels(0);
245 const IndexType var = gm_[f].variableIndex(0);
247 ValueType v0 = gm_[f](&guess);
248 ValueType v1; ACC::neutral(v1);
250 ACC::op(gm_[f](&i),v1);
251 for(
LabelType i=guess+1; i<numLabels; ++i)
252 ACC::op(gm_[f](&i),v1);
253 AddUnaryTerm(var, v0, v1);
255 else if(gm_[f].numberOfVariables() == 2) {
256 const IndexType var0 = gm_[f].variableIndex(0);
257 const IndexType var1 = gm_[f].variableIndex(1);
262 ValueType v00 = gm_[f](c);
263 ValueType v01 = gm_[f](c2);
265 ValueType v11 = std::min(v00,v01);
266 AddPairwiseTerm(var0, var1,v00,v01,v10,v11);
269 qpbo_->MergeParallelEdges();
271 for(IndexType var=0; var<gm_.numberOfVariables();++var){
272 if(qpbo_->GetLabel(var)==0){
273 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
285 template<
class GM,
class ACC>
290 qpbo_->AddNode(gm_.numberOfVariables());
292 for(
size_t var=0; var<gm_.numberOfVariables(); ++var){
293 std::vector<ValueType> v(gm_.numberOfLabels(var),0);
294 for(
size_t i=0; i<gm_.numberOfFactors(var); ++i){
295 size_t f = gm_.factorOfVariable(var, i);
296 if(gm_[f].numberOfVariables()==1){
297 for(
size_t j=0; j<v.size(); ++j){
302 else if(gm_[f].numberOfVariables() == 2) {
303 LabelType c[] = {guess[gm_[f].variableIndex(0)],guess[gm_[f].variableIndex(1)]};
304 if(gm_[f].variableIndex(0)==var){
305 for(c[0]=0; c[0]<guess[var]; ++c[0]){
306 v[c[0]] += gm_[f](c);
308 for(c[0]=guess[var]+1; c[0]<v.size(); ++c[0]){
309 v[c[0]] += gm_[f](c);
312 else if(gm_[f].variableIndex(1)==var){
313 for(c[1]=0; c[1]<guess[var]; ++c[1]){
314 v[c[1]] += gm_[f](c);
316 for(c[1]=guess[var]+1; c[1]<v.size(); ++c[1]){
317 v[c[1]] += gm_[f](c);
327 for(
size_t j=0; j<guess[var]; ++j){
330 for(
size_t j=guess[var]+1; j<v.size(); ++j){
333 AddUnaryTerm(var, v0, v1);
337 for(
size_t f = 0; f < gm_.numberOfFactors(); ++f) {
338 if(gm_[f].numberOfVariables() < 2) {
341 else if(gm_[f].numberOfVariables() == 2) {
342 const IndexType var0 = gm_[f].variableIndex(0);
343 const IndexType var1 = gm_[f].variableIndex(1);
345 LabelType c[2] = {guess[var0],guess[var1]};
346 LabelType c0[2] = {guess[var0],guess[var1]};
347 LabelType c1[2] = {guess[var0],guess[var1]};
353 for(c[0]=0; c[0]<gm_[f].numberOfLabels(0); ++c[0]){
354 for(c[1]=0; c[1]<gm_[f].numberOfLabels(1); ++c[1]){
355 if(c[0]==guess[var0] || c[1]==guess[var1]){
361 ValueType v = gm_[f](c) - gm_[f](c0) - gm_[f](c1);
366 AddPairwiseTerm(var0, var1,v00,v01,v10,v11);
369 qpbo_->MergeParallelEdges();
371 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
372 if(qpbo_->GetLabel(var)==0){
373 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
378 label_[var]=guess[var];
384 template<
class GM,
class ACC>
389 std::vector<IndexType> var2VarR(gm_.numberOfVariables());
390 std::vector<IndexType> varR2Var;
391 std::vector<size_t> varROffset;
393 for(
size_t var = 0; var < gm_.numberOfVariables(); ++var) {
398 varROffset.push_back(numBVar);
399 numBVar = numBVar + gm_.numberOfLabels(var)-1;
400 var2VarR[var]=varR2Var.size();
401 varR2Var.push_back(var);
404 std::cout << varR2Var.size() <<
" / "<<gm_.numberOfVariables()<<std::endl;
407 if(permutationType==NONE){
408 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
409 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
410 permutation_[var][l]=l;
414 else if(permutationType==
RANDOM){
415 srand (
unsigned ( time (NULL) ) );
416 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
417 LabelType numStates = gm_.numberOfLabels(var);
420 permutation_[var][i]=i;
423 std::random_shuffle(permutation_[var].begin(),permutation_[var].end());
426 else if(permutationType==MINMARG){
432 std::vector<LabelType> numberOfLabels(varR2Var.size());
433 for(
size_t i=0; i<varR2Var.size(); ++i)
435 typename SUBGM::SpaceType subspace(numberOfLabels.begin(),numberOfLabels.end());
437 for(
IndexType f=0; f<gm_.numberOfFactors();++f){
438 std::vector<PositionAndLabel<IndexType, LabelType> > fixed;
439 std::vector<IndexType> vars;
440 for(
IndexType i=0; i<gm_[f].numberOfVariables();++i){
441 const IndexType var = gm_[f].variableIndex(i);
443 fixed.push_back(PositionAndLabel<IndexType, LabelType>(i,label_[var]));
446 vars.push_back(var2VarR[var]);
450 gm.addFactor(gm.addFunction(func),vars.begin(),vars.end());
454 typename LBP::Parameter para;
455 para.maximumNumberOfSteps_ = 100;
461 for(
IndexType varR=0; varR<gm.numberOfVariables(); ++varR){
463 LabelType numStates = gm_.numberOfLabels(var);
464 typename GM::IndependentFactorType marg;
465 bp.marginal(varR, marg);
468 std::vector<LabelType> list(numStates);
475 if(marg(&list[j])<marg(&list[i])){
483 permutation_[var][i] = list[i];
491 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
492 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
493 inversePermutation_[var][permutation_[var][l]]=l;
501 qpbo_->AddNode(numBVar);
504 for(
IndexType varR = 0; varR < varR2Var.size(); ++varR) {
506 for(
size_t l = 0; l+1<gm_.numberOfLabels(var); ++l){
507 AddUnaryTerm((
int) (varROffset[varR]+l), 0.0, 0.0);
509 for(
LabelType l=1; l+1<gm_.numberOfLabels(var); ++l){
510 AddPairwiseTerm((
int) (varROffset[varR]+l-1), (
int) (varROffset[varR]+l), 0.0, 1e30, 0.0, 0.0);
524 for(
size_t f = 0; f < gm_.numberOfFactors(); ++f) {
525 if(gm_[f].numberOfVariables() == 0) {
527 constValue += gm_[f](&l);
529 else if(gm_[f].numberOfVariables() == 1) {
530 const LabelType numLabels = gm_[f].numberOfLabels(0);
531 const IndexType var = gm_[f].variableIndex(0);
533 constValue += gm_[f](&(label_[var]));
536 LabelType l0 = inversePermutation_[var][0];
538 constValue += gm_[f](&l0);
541 l0 = inversePermutation_[var][i-1];
542 l1 = inversePermutation_[var][i];
543 AddUnaryTerm((
int) (varROffset[varR]+i-1), 0.0, gm_[f](&l1)-gm_[f](&l0));
548 else if(gm_[f].numberOfVariables() == 2) {
549 const IndexType var0 = gm_[f].variableIndex(0);
550 const IndexType var1 = gm_[f].variableIndex(1);
554 if(optimal_[var0]&&optimal_[var1]){
555 LabelType l[2] = { label_[var0], label_[var1]};
556 constValue += gm_[f](l);
558 else if(optimal_[var0]){
559 const LabelType numLabels = gm_[f].numberOfLabels(1);
560 LabelType l0[2] = { label_[var0], inversePermutation_[var1][0]};
562 constValue += gm_[f](l0);
564 l0[1] = inversePermutation_[var1][i-1];
565 l1[1] = inversePermutation_[var1][i];
567 AddUnaryTerm((
int) (varROffset[varR1]+i-1), 0.0, gm_[f](l1)-gm_[f](l0));
570 else if(optimal_[var1]){
571 const LabelType numLabels = gm_[f].numberOfLabels(0);
572 LabelType l0[2] = { inversePermutation_[var0][0], label_[var1]};
574 constValue += gm_[f](l0);
576 l0[0] = inversePermutation_[var0][i-1];
577 l1[0] = inversePermutation_[var0][i];
578 AddUnaryTerm((
int) (varROffset[varR0]+i-1), 0.0, gm_[f](l1)-gm_[f](l0));
584 const LabelType l[2]={inversePermutation_[var0][0],inversePermutation_[var1][0]};
585 constValue += gm_[f](l);
587 for(
size_t i=1; i<gm_[f].numberOfLabels(0);++i){
588 const LabelType l1[2]={inversePermutation_[var0][i] ,inversePermutation_[var1][0]};
589 const LabelType l2[2]={inversePermutation_[var0][i-1],inversePermutation_[var1][0]};
590 AddUnaryTerm((
int) (varROffset[varR0]+i-1), 0.0, gm_[f](l1)-gm_[f](l2));
593 for(
size_t i=1; i<gm_[f].numberOfLabels(1);++i){
594 const LabelType l1[2]={inversePermutation_[var0][0],inversePermutation_[var1][i]};
595 const LabelType l2[2]={inversePermutation_[var0][0],inversePermutation_[var1][i-1]};
596 AddUnaryTerm((
int) (varROffset[varR1]+i-1), 0.0, gm_[f](l1)-gm_[f](l2));
599 for(
size_t i=1; i<gm_[f].numberOfLabels(0);++i){
600 for(
size_t j=1; j<gm_[f].numberOfLabels(1);++j){
601 const int node0 = varROffset[varR0]+i-1;
602 const int node1 = varROffset[varR1]+j-1;
606 int l[2] = {(int)inversePermutation_[var0][i],(
int)inversePermutation_[var1][j]}; v += gm_[f](l);
607 l[0]=inversePermutation_[var0][i-1]; v -= gm_[f](l);
608 l[1]=inversePermutation_[var1][j-1]; v += gm_[f](l);
609 l[0]=inversePermutation_[var0][i]; v -= gm_[f](l);
611 AddPairwiseTerm(node0, node1,0.0,0.0,0.0,v);
617 qpbo_->MergeParallelEdges();
622 if(!param_.strongPersistency_)
623 qpbo_->ComputeWeakPersistencies();
628 bound_ = constValue + 0.5 * qpbo_->ComputeTwiceLowerBound();
631 if(param_.probing_) {
632 std::cout <<
"Start Probing ..."<<std::endl;
634 int *mapping =
new int[numBVar];
636 for(
int i = 0; i < static_cast<int>(numBVar); ++i) {
638 qpbo_->SetLabel(i, qpbo_->GetLabel(i));
641 typename kolmogorov::qpbo::QPBO<GraphValueType>::ProbeOptions options;
642 options.C = 1000000000;
643 if(!param_.strongPersistency_)
644 options.weak_persistencies = 1;
646 options.weak_persistencies = 0;
647 qpbo_->Probe(mapping, options);
648 if(!param_.strongPersistency_)
649 qpbo_->ComputeWeakPersistencies();
651 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
652 if(optimal_[var])
continue;
656 int l = qpbo_->GetLabel(mapping[varROffset[varR]]/2);
657 if(l>=0) l = (l + mapping[varROffset[varR]]) % 2;
666 int l = qpbo_->GetLabel(mapping[varROffset[varR]+gm_.numberOfLabels(var)-2]/2);
667 if(l>=0) l = (l + mapping[varROffset[varR]+gm_.numberOfLabels(var)-2]) % 2;
670 if(l==0) {partialOptimality_[var][inversePermutation_[var][gm_.numberOfLabels(var)-1]]&=
opengm::Tribool::False;}
671 else if(l==1){partialOptimality_[var][inversePermutation_[var][gm_.numberOfLabels(var)-1]]&=
opengm::Tribool::True;}
672 else {partialOptimality_[var][inversePermutation_[var][gm_.numberOfLabels(var)-1]]&=
opengm::Tribool::Maybe;}
676 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l)
678 int l1 = qpbo_->GetLabel(mapping[varROffset[varR]+l-1]/2);
679 int l2 = qpbo_->GetLabel(mapping[varROffset[varR]+l]/2);
680 if(l1>=0) l1 = (l1 + mapping[varROffset[varR]+l-1]) % 2;
681 if(l2>=0) l2 = (l2 + mapping[varROffset[varR]+l]) % 2;
697 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
698 if(optimal_[var])
continue;
702 int l = qpbo_->GetLabel(varROffset[varR]);
716 int l = qpbo_->GetLabel(varROffset[varR]+gm_.numberOfLabels(var)-2);
730 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l)
732 int l1 = qpbo_->GetLabel(varROffset[varR]+l-1);
733 int l2 = qpbo_->GetLabel(varROffset[varR]+l);
755 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
756 if(optimal_[var])
continue;
759 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l){
767 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l){
774 if(countFALSE+1==gm_.numberOfLabels(var)){
776 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l){
787 template<
class GM,
class ACC>
791 EmptyVisitorType visitor;
792 return infer(visitor);
795 template<
class GM,
class ACC>
796 template<
class VisitorType>
802 visitor.addLog(
"optimality");
803 visitor.addLog(
"optimalityV");
804 if(param_.rounds_>1 && param_.strongPersistency_==
false)
805 std::cout <<
"WARNING: Using weak persistency and several rounds may lead to wrong results if solution is not unique!"<<std::endl;
808 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
809 maxNumberOfLabels = std::max(maxNumberOfLabels, gm_.numberOfLabels(var));
813 for(
IndexType f=0; f< gm_.numberOfFactors(); ++f){
814 if(gm_[f].numberOfVariables()<2)
continue;
815 isPotts &= gm_[f].isPotts();
819 visitor.begin(*
this);
821 if(param_.useKovtunsMethod_){
823 std::cout <<
"Use Kovtuns method for potts"<<std::endl;
824 for(
LabelType l=0; l<maxNumberOfLabels; ++l) {
826 double xoptimality = optimality();
827 double xoptimalityV = optimalityV();
829 visitor.log(
"optimality",xoptimality);
830 visitor.log(
"optimalityV",xoptimalityV);
836 std::cout <<
"Use Kovtuns method for non-potts is not supported yet"<<std::endl;
854 if(param_.rounds_>0){
855 std::cout <<
"Start "<<param_.rounds_ <<
" of multilabel QPBO for different permutations" <<std::endl;
856 for(
size_t rr=0; rr<param_.rounds_;++rr){
857 testPermutation(param_.permutationType_);
858 double xoptimality = optimality();
859 double xoptimalityV = optimalityV();
861 visitor.log(
"optimality",xoptimality);
862 visitor.log(
"optimalityV",xoptimalityV);
868 #ifdef MQPBOHotFixOutPutPartialOPtimalityMap
870 std::vector<double> optimal;
871 for(
size_t i=0; i<optimal_.size();++i)
872 optimal.push_back((
double)(optimal_[i]));
882 template<
class GM,
class ACC>
888 size_t unlabeled = 0;
889 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
890 for(
LabelType l=0; l<gm_.numberOfLabels(var);++l){
897 return labeled*1.0/(labeled+unlabeled);
900 template<
class GM,
class ACC>
906 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
907 for(
LabelType l=0; l<gm_.numberOfLabels(var);++l){
914 return labeled*1.0/gm_.numberOfVariables();
917 template<
class GM,
class ACC>
918 typename GM::ValueType
925 template<
class GM,
class ACC>
927 std::vector<LabelType> states;
929 return gm_.evaluate(states);
932 template<
class GM,
class ACC>
936 std::vector<LabelType>& x,
941 x.resize(gm_.numberOfVariables(),0);
943 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
944 size_t countTrue = 0;
945 size_t countFalse = 0;
946 size_t countMaybe = 0;
948 for(
LabelType l=0; l<gm_.numberOfLabels(var);++l){
961 OPENGM_ASSERT(countTrue+countFalse+countMaybe == gm_.numberOfLabels(var));
973 #endif // #ifndef OPENGM_MQPBO_HXX
void setStartingPoint(typename std::vector< typename GM::LabelType >::const_iterator)
set starting point
hid_t createFile(const std::string &, HDF5Version=DEFAULT_HDF5_VERSION)
Create an HDF5 file.
Discrete space in which variables can have differently many labels.
GM::ValueType value() const
return the solution (value)
void reset()
reset assumes that the structure of the graphical model has not changed
A framework for message passing algorithms Cf. F. R. Kschischang, B. J. Frey and H...
InferenceTermination testPermutation(PermutationType permutationType)
[class mqpbo] Multilabel QPBO (MQPBO) Implements the algorithms described in i) Ivan Kovtun: Partial ...
#define OPENGM_ASSERT(expression)
GraphicalModelType::IndexType IndexType
MQPBO(const GmType &, const Parameter &=Parameter())
[class mqpbo]
virtual InferenceTermination arg(std::vector< LabelType > &, const size_t=1) const
output a solution
double optimality() const
GraphicalModelType::ValueType ValueType
Inference algorithm interface.
visitors::VerboseVisitor< MQPBO< GM, ACC > > VerboseVisitorType
void closeFile(const hid_t &)
Close an HDF5 file.
double optimalityV() const
void save(const hid_t &, const std::string &, const Marray< T > &)
Save an Marray as an HDF5 dataset.
InferenceTermination testQuess(std::vector< LabelType > &guess)
bool partialOptimality(IndexType var, LabelType &l) const
GM::ValueType bound() const
return a bound on the solution
Funcion that refers to a factor of another GraphicalModel in which some variables are fixed...
std::vector< LabelType > label_
LabelType numberOfLabels(const IndexType) const
GraphicalModelType::LabelType LabelType
visitors::TimingVisitor< MQPBO< GM, ACC > > TimingVisitorType
visitors::EmptyVisitor< MQPBO< GM, ACC > > EmptyVisitorType
PermutationType permutationType_
InferenceTermination infer()
const GmType & graphicalModel() const
const std::vector< opengm::Tribool > & partialOptimality(IndexType var) const