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
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