2 #ifndef OPENGM_MQPBO_HXX 3 #define OPENGM_MQPBO_HXX 18 #ifdef MQPBOHotFixOutPutPartialOPtimalityMap 36 template<
class GM,
class ACC>
54 template<
class _GM,
class _ACC>
65 Parameter(): useKovtunsMethod_(true), probing_(false), strongPersistency_(false), rounds_(0), permutationType_(
NONE) {};
71 useKovtunsMethod_(p.useKovtunsMethod_),
73 strongPersistency_(p.strongPersistency_),
75 permutationType_(p.permutationType_){
89 std::string
name()
const;
93 typename GM::ValueType
bound()
const;
94 typename GM::ValueType
value()
const;
95 template<
class VisitorType>
99 void setStartingPoint(
typename std::vector<typename GM::LabelType>::const_iterator);
115 kolmogorov::qpbo::QPBO<GraphValueType>* qpbo_;
121 std::vector<std::vector<LabelType> > permutation_;
122 std::vector<std::vector<LabelType> > inversePermutation_;
123 std::vector<std::vector<opengm::Tribool> > partialOptimality_;
124 std::vector<bool> optimal_;
125 std::vector<LabelType> label_;
126 std::vector<size_t> variableOffset_;
131 GraphValueType scale;
137 template<
class GM,
class ACC>
147 for(
size_t j = 0; j < gm_.numberOfFactors(); ++j) {
148 if(gm_[j].numberOfVariables() > 2) {
149 throw RuntimeError(
"This implementation of MQPBO supports only factors of order <= 2.");
154 permutation_.resize(gm_.numberOfVariables());
155 inversePermutation_.resize(gm_.numberOfVariables());
156 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
157 permutation_[var].resize(gm_.numberOfLabels(var));
158 inversePermutation_[var].resize(gm_.numberOfLabels(var));
162 partialOptimality_.resize(gm_.numberOfVariables());
163 optimal_.resize(gm_.numberOfVariables(),
false);
164 label_.resize(gm_.numberOfVariables());
165 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
173 variableOffset_.resize(gm_.numberOfVariables(),0);
174 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
175 variableOffset_[var] = numNodes_;
176 numNodes_ += gm_.numberOfLabels(var)-1;
178 for(
IndexType var=1; var<gm_.numberOfVariables(); ++var){
179 OPENGM_ASSERT( variableOffset_[var-1]< variableOffset_[var]);
182 for(
IndexType f=0; f<gm_.numberOfFactors(); ++f){
183 if(gm_[f].numberOfVariables()==1)
184 numEdges_ += gm_[f].numberOfLabels(0)-2;
185 if(gm_[f].numberOfVariables()==2){
186 numEdges_ += (gm_[f].numberOfLabels(0)-1);
191 if(param_.rounds_>0){
193 qpbo_ =
new kolmogorov::qpbo::QPBO<GraphValueType > (numNodes_, numEdges_);
194 qpbo_->AddNode(numNodes_);
198 qpbo_ =
new kolmogorov::qpbo::QPBO<GraphValueType > (gm_.numberOfVariables(), numSOF);
199 qpbo_->AddNode(gm_.numberOfVariables());
203 template<
class GM,
class ACC>
213 template<
class GM,
class ACC>
221 template<
class GM,
class ACC>
225 typename std::vector<typename GM::LabelType>::const_iterator begin
231 template<
class GM,
class ACC>
238 template<
class GM,
class ACC>
246 template<
class GM,
class ACC>
249 qpbo_->AddUnaryTerm(var, scale*v0, scale*v1);
252 template<
class GM,
class ACC>
255 qpbo_->AddPairwiseTerm(var0, var1,scale*v00,scale*v01,scale*v10,scale*v11);
258 template<
class GM,
class ACC>
263 qpbo_->AddNode(gm_.numberOfVariables());
264 for(
size_t f = 0; f < gm_.numberOfFactors(); ++f) {
265 if(gm_[f].numberOfVariables() == 0) {
268 else if(gm_[f].numberOfVariables() == 1) {
269 const LabelType numLabels = gm_[f].numberOfLabels(0);
270 const IndexType var = gm_[f].variableIndex(0);
275 ACC::op(gm_[f](&i),v1);
276 for(
LabelType i=guess+1; i<numLabels; ++i)
277 ACC::op(gm_[f](&i),v1);
278 AddUnaryTerm(var, v0, v1);
280 else if(gm_[f].numberOfVariables() == 2) {
281 const IndexType var0 = gm_[f].variableIndex(0);
282 const IndexType var1 = gm_[f].variableIndex(1);
291 AddPairwiseTerm(var0, var1,v00,v01,v10,v11);
294 qpbo_->MergeParallelEdges();
296 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
297 if(qpbo_->GetLabel(var)==0){
298 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
310 template<
class GM,
class ACC>
315 qpbo_->AddNode(gm_.numberOfVariables());
317 for(
size_t var=0; var<gm_.numberOfVariables(); ++var){
318 std::vector<ValueType> v(gm_.numberOfLabels(var),0);
319 for(
size_t i=0; i<gm_.numberOfFactors(var); ++i){
320 size_t f = gm_.factorOfVariable(var, i);
321 if(gm_[f].numberOfVariables()==1){
322 for(
size_t j=0; j<v.size(); ++j){
327 else if(gm_[f].numberOfVariables() == 2) {
328 LabelType c[] = {guess[gm_[f].variableIndex(0)],guess[gm_[f].variableIndex(1)]};
329 if(gm_[f].variableIndex(0)==var){
330 for(c[0]=0; c[0]<guess[var]; ++c[0]){
331 v[c[0]] += gm_[f](c);
333 for(c[0]=guess[var]+1; c[0]<v.size(); ++c[0]){
334 v[c[0]] += gm_[f](c);
337 else if(gm_[f].variableIndex(1)==var){
338 for(c[1]=0; c[1]<guess[var]; ++c[1]){
339 v[c[1]] += gm_[f](c);
341 for(c[1]=guess[var]+1; c[1]<v.size(); ++c[1]){
342 v[c[1]] += gm_[f](c);
352 for(
size_t j=0; j<guess[var]; ++j){
355 for(
size_t j=guess[var]+1; j<v.size(); ++j){
358 AddUnaryTerm(var, v0, v1);
362 for(
size_t f = 0; f < gm_.numberOfFactors(); ++f) {
363 if(gm_[f].numberOfVariables() < 2) {
366 else if(gm_[f].numberOfVariables() == 2) {
367 const IndexType var0 = gm_[f].variableIndex(0);
368 const IndexType var1 = gm_[f].variableIndex(1);
370 LabelType c[2] = {guess[var0],guess[var1]};
371 LabelType c0[2] = {guess[var0],guess[var1]};
372 LabelType c1[2] = {guess[var0],guess[var1]};
378 for(c[0]=0; c[0]<gm_[f].numberOfLabels(0); ++c[0]){
379 for(c[1]=0; c[1]<gm_[f].numberOfLabels(1); ++c[1]){
380 if(c[0]==guess[var0] || c[1]==guess[var1]){
386 ValueType v = gm_[f](c) - gm_[f](c0) - gm_[f](c1);
391 AddPairwiseTerm(var0, var1,v00,v01,v10,v11);
394 qpbo_->MergeParallelEdges();
396 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
397 if(qpbo_->GetLabel(var)==0){
398 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
403 label_[var]=guess[var];
409 template<
class GM,
class ACC>
414 std::vector<IndexType> var2VarR(gm_.numberOfVariables());
415 std::vector<IndexType> varR2Var;
416 std::vector<size_t> varROffset;
418 for(
size_t var = 0; var < gm_.numberOfVariables(); ++var) {
423 varROffset.push_back(numBVar);
424 numBVar = numBVar + gm_.numberOfLabels(var)-1;
425 var2VarR[var]=varR2Var.size();
426 varR2Var.push_back(var);
429 std::cout << varR2Var.size() <<
" / "<<gm_.numberOfVariables()<<std::endl;
432 if(permutationType==
NONE){
433 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
434 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
435 permutation_[var][l]=l;
439 else if(permutationType==
RANDOM){
440 srand (
unsigned ( time (NULL) ) );
441 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
442 LabelType numStates = gm_.numberOfLabels(var);
445 permutation_[var][i]=i;
448 std::random_shuffle(permutation_[var].begin(),permutation_[var].end());
451 else if(permutationType==MINMARG){
457 std::vector<LabelType> numberOfLabels(varR2Var.size());
458 for(
size_t i=0; i<varR2Var.size(); ++i)
460 typename SUBGM::SpaceType subspace(numberOfLabels.begin(),numberOfLabels.end());
462 for(
IndexType f=0; f<gm_.numberOfFactors();++f){
463 std::vector<PositionAndLabel<IndexType, LabelType> > fixed;
464 std::vector<IndexType> vars;
465 for(
IndexType i=0; i<gm_[f].numberOfVariables();++i){
466 const IndexType var = gm_[f].variableIndex(i);
468 fixed.push_back(PositionAndLabel<IndexType, LabelType>(i,label_[var]));
471 vars.push_back(var2VarR[var]);
475 gm.addFactor(gm.addFunction(func),vars.begin(),vars.end());
479 typename LBP::Parameter para;
480 para.maximumNumberOfSteps_ = 100;
486 for(
IndexType varR=0; varR<gm.numberOfVariables(); ++varR){
488 LabelType numStates = gm_.numberOfLabels(var);
489 typename GM::IndependentFactorType marg;
490 bp.marginal(varR, marg);
493 std::vector<LabelType> list(numStates);
500 if(marg(&list[j])<marg(&list[i])){
508 permutation_[var][i] = list[i];
516 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
517 for(
LabelType l=0; l<gm_.numberOfLabels(var); ++l){
518 inversePermutation_[var][permutation_[var][l]]=l;
526 qpbo_->AddNode(numBVar);
529 for(
IndexType varR = 0; varR < varR2Var.size(); ++varR) {
531 for(
size_t l = 0; l+1<gm_.numberOfLabels(var); ++l){
532 AddUnaryTerm((
int) (varROffset[varR]+l), 0.0, 0.0);
534 for(
LabelType l=1; l+1<gm_.numberOfLabels(var); ++l){
535 AddPairwiseTerm((
int) (varROffset[varR]+l-1), (
int) (varROffset[varR]+l), 0.0, 1e30, 0.0, 0.0);
549 for(
size_t f = 0; f < gm_.numberOfFactors(); ++f) {
550 if(gm_[f].numberOfVariables() == 0) {
552 constValue += gm_[f](&l);
554 else if(gm_[f].numberOfVariables() == 1) {
555 const LabelType numLabels = gm_[f].numberOfLabels(0);
556 const IndexType var = gm_[f].variableIndex(0);
558 constValue += gm_[f](&(label_[var]));
561 LabelType l0 = inversePermutation_[var][0];
563 constValue += gm_[f](&l0);
566 l0 = inversePermutation_[var][i-1];
567 l1 = inversePermutation_[var][i];
568 AddUnaryTerm((
int) (varROffset[varR]+i-1), 0.0, gm_[f](&l1)-gm_[f](&l0));
573 else if(gm_[f].numberOfVariables() == 2) {
574 const IndexType var0 = gm_[f].variableIndex(0);
575 const IndexType var1 = gm_[f].variableIndex(1);
579 if(optimal_[var0]&&optimal_[var1]){
580 LabelType l[2] = { label_[var0], label_[var1]};
581 constValue += gm_[f](l);
583 else if(optimal_[var0]){
584 const LabelType numLabels = gm_[f].numberOfLabels(1);
585 LabelType l0[2] = { label_[var0], inversePermutation_[var1][0]};
587 constValue += gm_[f](l0);
589 l0[1] = inversePermutation_[var1][i-1];
590 l1[1] = inversePermutation_[var1][i];
592 AddUnaryTerm((
int) (varROffset[varR1]+i-1), 0.0, gm_[f](l1)-gm_[f](l0));
595 else if(optimal_[var1]){
596 const LabelType numLabels = gm_[f].numberOfLabels(0);
597 LabelType l0[2] = { inversePermutation_[var0][0], label_[var1]};
599 constValue += gm_[f](l0);
601 l0[0] = inversePermutation_[var0][i-1];
602 l1[0] = inversePermutation_[var0][i];
603 AddUnaryTerm((
int) (varROffset[varR0]+i-1), 0.0, gm_[f](l1)-gm_[f](l0));
609 const LabelType l[2]={inversePermutation_[var0][0],inversePermutation_[var1][0]};
610 constValue += gm_[f](l);
612 for(
size_t i=1; i<gm_[f].numberOfLabels(0);++i){
613 const LabelType l1[2]={inversePermutation_[var0][i] ,inversePermutation_[var1][0]};
614 const LabelType l2[2]={inversePermutation_[var0][i-1],inversePermutation_[var1][0]};
615 AddUnaryTerm((
int) (varROffset[varR0]+i-1), 0.0, gm_[f](l1)-gm_[f](l2));
618 for(
size_t i=1; i<gm_[f].numberOfLabels(1);++i){
619 const LabelType l1[2]={inversePermutation_[var0][0],inversePermutation_[var1][i]};
620 const LabelType l2[2]={inversePermutation_[var0][0],inversePermutation_[var1][i-1]};
621 AddUnaryTerm((
int) (varROffset[varR1]+i-1), 0.0, gm_[f](l1)-gm_[f](l2));
624 for(
size_t i=1; i<gm_[f].numberOfLabels(0);++i){
625 for(
size_t j=1; j<gm_[f].numberOfLabels(1);++j){
626 const int node0 = varROffset[varR0]+i-1;
627 const int node1 = varROffset[varR1]+j-1;
631 int l[2] = {(int)inversePermutation_[var0][i],(
int)inversePermutation_[var1][j]}; v += gm_[f](l);
632 l[0]=inversePermutation_[var0][i-1]; v -= gm_[f](l);
633 l[1]=inversePermutation_[var1][j-1]; v += gm_[f](l);
634 l[0]=inversePermutation_[var0][i]; v -= gm_[f](l);
636 AddPairwiseTerm(node0, node1,0.0,0.0,0.0,v);
642 qpbo_->MergeParallelEdges();
647 if(!param_.strongPersistency_)
648 qpbo_->ComputeWeakPersistencies();
653 bound_ = constValue + 0.5 * qpbo_->ComputeTwiceLowerBound();
656 if(param_.probing_) {
657 std::cout <<
"Start Probing ..."<<std::endl;
659 int *mapping =
new int[numBVar];
661 for(
int i = 0; i < static_cast<int>(numBVar); ++i) {
663 qpbo_->SetLabel(i, qpbo_->GetLabel(i));
666 typename kolmogorov::qpbo::QPBO<GraphValueType>::ProbeOptions options;
667 options.C = 1000000000;
668 if(!param_.strongPersistency_)
669 options.weak_persistencies = 1;
671 options.weak_persistencies = 0;
672 qpbo_->Probe(mapping, options);
673 if(!param_.strongPersistency_)
674 qpbo_->ComputeWeakPersistencies();
676 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
677 if(optimal_[var])
continue;
681 int l = qpbo_->GetLabel(mapping[varROffset[varR]]/2);
682 if(l>=0) l = (l + mapping[varROffset[varR]]) % 2;
691 int l = qpbo_->GetLabel(mapping[varROffset[varR]+gm_.numberOfLabels(var)-2]/2);
692 if(l>=0) l = (l + mapping[varROffset[varR]+gm_.numberOfLabels(var)-2]) % 2;
695 if(l==0) {partialOptimality_[var][inversePermutation_[var][gm_.numberOfLabels(var)-1]]&=
opengm::Tribool::False;}
696 else if(l==1){partialOptimality_[var][inversePermutation_[var][gm_.numberOfLabels(var)-1]]&=
opengm::Tribool::True;}
697 else {partialOptimality_[var][inversePermutation_[var][gm_.numberOfLabels(var)-1]]&=
opengm::Tribool::Maybe;}
701 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l)
703 int l1 = qpbo_->GetLabel(mapping[varROffset[varR]+l-1]/2);
704 int l2 = qpbo_->GetLabel(mapping[varROffset[varR]+l]/2);
705 if(l1>=0) l1 = (l1 + mapping[varROffset[varR]+l-1]) % 2;
706 if(l2>=0) l2 = (l2 + mapping[varROffset[varR]+l]) % 2;
722 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
723 if(optimal_[var])
continue;
727 int l = qpbo_->GetLabel(varROffset[varR]);
741 int l = qpbo_->GetLabel(varROffset[varR]+gm_.numberOfLabels(var)-2);
755 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l)
757 int l1 = qpbo_->GetLabel(varROffset[varR]+l-1);
758 int l2 = qpbo_->GetLabel(varROffset[varR]+l);
780 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
781 if(optimal_[var])
continue;
784 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l){
792 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l){
799 if(countFALSE+1==gm_.numberOfLabels(var)){
801 for(
LabelType l=1; l+1<gm_.numberOfLabels(var);++l){
812 template<
class GM,
class ACC>
816 EmptyVisitorType visitor;
817 return infer(visitor);
820 template<
class GM,
class ACC>
821 template<
class VisitorType>
827 visitor.addLog(
"optimality");
828 visitor.addLog(
"optimalityV");
829 if(param_.rounds_>1 && param_.strongPersistency_==
false)
830 std::cout <<
"WARNING: Using weak persistency and several rounds may lead to wrong results if solution is not unique!"<<std::endl;
833 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
834 maxNumberOfLabels = std::max(maxNumberOfLabels, gm_.numberOfLabels(var));
838 for(
IndexType f=0; f< gm_.numberOfFactors(); ++f){
839 if(gm_[f].numberOfVariables()<2)
continue;
840 isPotts &= gm_[f].isPotts();
844 visitor.begin(*
this);
846 if(param_.useKovtunsMethod_){
849 for(
LabelType l=0; l<maxNumberOfLabels; ++l) {
854 visitor.log(
"optimality",xoptimality);
855 visitor.log(
"optimalityV",xoptimalityV);
861 std::cout <<
"Use Kovtuns method for non-potts is not supported yet"<<std::endl;
879 if(param_.rounds_>0){
880 std::cout <<
"Start "<<param_.rounds_ <<
" of multilabel QPBO for different permutations" <<std::endl;
881 for(
size_t rr=0; rr<param_.rounds_;++rr){
886 visitor.log(
"optimality",xoptimality);
887 visitor.log(
"optimalityV",xoptimalityV);
893 #ifdef MQPBOHotFixOutPutPartialOPtimalityMap 895 std::vector<double> optimal;
896 for(
size_t i=0; i<optimal_.size();++i)
897 optimal.push_back((
double)(optimal_[i]));
907 template<
class GM,
class ACC>
913 size_t unlabeled = 0;
914 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
915 for(
LabelType l=0; l<gm_.numberOfLabels(var);++l){
922 return labeled*1.0/(labeled+unlabeled);
925 template<
class GM,
class ACC>
931 for(
IndexType var=0; var<gm_.numberOfVariables();++var){
932 for(
LabelType l=0; l<gm_.numberOfLabels(var);++l){
939 return labeled*1.0/gm_.numberOfVariables();
942 template<
class GM,
class ACC>
943 typename GM::ValueType
950 template<
class GM,
class ACC>
952 std::vector<LabelType> states;
954 return gm_.evaluate(states);
957 template<
class GM,
class ACC>
961 std::vector<LabelType>& x,
966 x.resize(gm_.numberOfVariables(),0);
968 for(
IndexType var=0; var<gm_.numberOfVariables(); ++var){
969 size_t countTrue = 0;
970 size_t countFalse = 0;
971 size_t countMaybe = 0;
973 for(
LabelType l=0; l<gm_.numberOfLabels(var);++l){
986 OPENGM_ASSERT(countTrue+countFalse+countMaybe == gm_.numberOfLabels(var));
998 #endif // #ifndef OPENGM_MQPBO_HXX
GM::ValueType value() const
return the solution (value)
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.
void reset()
reset assumes that the structure of the graphical model has not changed
double optimalityV() const
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)
bool partialOptimality(IndexType var, LabelType &l) const
LabelType numberOfLabels(const IndexType) const
GraphicalModelType::IndexType IndexType
MQPBO(const GmType &, const Parameter &=Parameter())
[class mqpbo]
GM::ValueType bound() const
return a bound on the solution
GraphicalModelType::ValueType ValueType
Inference algorithm interface.
visitors::VerboseVisitor< MQPBO< GM, ACC > > VerboseVisitorType
virtual InferenceTermination arg(std::vector< LabelType > &, const size_t=1) const
output a solution
void closeFile(const hid_t &)
Close an HDF5 file.
void save(const hid_t &, const std::string &, const Marray< T > &)
Save an Marray as an HDF5 dataset.
InferenceTermination testQuess(std::vector< LabelType > &guess)
double optimality() const
Funcion that refers to a factor of another GraphicalModel in which some variables are fixed...
std::vector< LabelType > label_
GraphicalModelType::LabelType LabelType
visitors::TimingVisitor< MQPBO< GM, ACC > > TimingVisitorType
const GmType & graphicalModel() const
visitors::EmptyVisitor< MQPBO< GM, ACC > > EmptyVisitorType
const std::vector< opengm::Tribool > & partialOptimality(IndexType var) const
PermutationType permutationType_
InferenceTermination infer()