2 #ifndef OPENGM_LSATR_HXX 3 #define OPENGM_LSATR_HXX 14 #include <maxflowlib.h> 17 #include "vigra/multi_distance.hxx" 18 #include "vigra/multi_array.hxx" 47 template<
class LabelType>
55 void init(
const GM&,
const std::vector<LabelType>& );
56 void set(
const double);
57 void set(
const std::vector<LabelType>&,
const double);
58 double optimize(std::vector<LabelType>&);
61 double eval(
const std::vector<LabelType>&)
const;
62 double evalAprox(
const std::vector<LabelType>&,
const std::vector<LabelType>&,
const double)
const;
63 void evalBoth(
const std::vector<LabelType>& label,
const std::vector<LabelType>& workingPoint,
const double lambda,
double& value,
double& valueAprox)
const;
66 typedef maxflowLib::Graph<double,double,double> graph_type;
67 typedef maxflowLib::Block<typename graph_type::node_id> block_type;
69 void updateDistance();
74 double constTermApproximation_;
75 double constTermTrustRegion_;
76 std::vector<LabelType> workingPoint_;
77 std::vector<double> distance_;
78 std::vector<double> unaries_;
79 std::vector<double> approxUnaries_;
80 std::vector< LSA_TR_WeightedEdge> supEdges_;
81 std::vector< LSA_TR_WeightedEdge> subEdges_;
83 block_type* changedList_;
86 std::vector<size_t> shape_;
90 template<
class GM,
class ACC>
107 template<
class _GM,
class _ACC>
127 initialLambda_ = 0.1;
128 precisionLambda_ = 1e-9;
129 lambdaMultiplier_ = 2;
130 reductionRatio_ = 0.25;
131 distance_ = EUCLIDEAN;
136 : randSeed_(p.randSeed_),
137 maxLambda_(p.maxLambda_),
138 initialLambda_(p.initialLambda_),
139 precisionLambda_(p.precisionLambda_),
140 lambdaMultiplier_(p.lambdaMultiplier_),
141 reductionRatio_(p.reductionRatio_),
142 distance_(p.distance_){
147 LSA_TR(
const GraphicalModelType&);
150 std::string name()
const;
151 const GraphicalModelType& graphicalModel()
const;
154 template<
class VisitorType>
156 void setStartingPoint(
typename std::vector<LabelType>::const_iterator);
162 double findMinimalChangeBrakPoint(
const double lambda,
const std::vector<LabelType>& workingPoint);
165 const GraphicalModelType& gm_;
167 std::vector<LabelType> curState_;
171 std::vector<ValueType> unaries_;
172 std::vector<LSA_TR_WeightedEdge> subEdges_;
173 std::vector<LSA_TR_WeightedEdge> supEdges_;
174 std::vector<ValueType> approxUnaries_;
179 template<
class LabelType>
182 typedef size_t IndexType;
184 numVar_ = gm.numberOfVariables();
185 workingPoint_ = workingPoint;
188 unaries_.resize(numVar_,0);
189 distance_.resize(numVar_,0);
195 for(IndexType f=0; f<gm.numberOfFactors();++f){
197 if(gm[f].numberOfVariables() == 0){
198 constTerm_ += gm[f](label00);
200 else if(gm[f].numberOfVariables() == 1){
201 const double v0 = gm[f](label00);
202 const double v1 = gm[f](label11);
203 const IndexType var0 = gm[f].variableIndex(0);
205 unaries_[var0] += v1-v0;
207 else if(gm[f].numberOfVariables() == 2){
208 const double v00 = gm[f](label00);
209 const double v01 = gm[f](label01);
210 const double v10 = gm[f](label10);
211 const double v11 = gm[f](label11);
212 const IndexType var0 = gm[f].variableIndex(0);
213 const IndexType var1 = gm[f].variableIndex(1);
215 const double D = 0.5*(v11-v00);
216 const double M = 0.5*(v10-v01);
217 unaries_[var0] += D+M;
218 unaries_[var1] += D-M;
219 const double V = v10-v00-D-M;
230 std::cout << std::endl;
231 std::cout << subEdges_.size() <<
" submodular edges."<<std::endl;
232 std::cout << supEdges_.size() <<
" supermodular edges."<<std::endl;
234 graph_ =
new graph_type(gm.numberOfVariables(),subEdges_.size()+1);
235 changedList_ =
new block_type(gm.numberOfVariables());
237 graph_->add_node(numVar_);
238 for(
size_t i=0; i<subEdges_.size(); ++i){
239 graph_->add_edge( subEdges_[i].
u, subEdges_[i].
v, subEdges_[i].
w, subEdges_[i].w);
241 approxUnaries_.assign(unaries_.begin(),unaries_.end());
242 for(
size_t i=0; i<supEdges_.size(); ++i){
243 const size_t var0 = supEdges_[i].u;
244 const size_t var1 = supEdges_[i].v;
245 const double w = supEdges_[i].w;
246 if(workingPoint[var0]==1)
247 approxUnaries_[var1] +=
w;
248 if(workingPoint[var1]==1)
249 approxUnaries_[var0] +=
w;
250 if(workingPoint[var0]==1 && workingPoint[var1]==1)
251 constTermApproximation_ -=
w;
255 shape_.resize(1,numVar_);
256 std::vector<size_t> neigbor_count(numVar_,0);
257 for(
size_t i=0; i<supEdges_.size(); ++i){
258 ++neigbor_count[supEdges_[i].u];
259 ++neigbor_count[supEdges_[i].v];
261 for(
size_t i=0; i<subEdges_.size(); ++i){
262 ++neigbor_count[subEdges_[i].u];
263 ++neigbor_count[subEdges_[i].v];
265 size_t min_deg = *std::min_element(neigbor_count.begin(),neigbor_count.end());
266 std::vector<size_t> corners;
267 for(
size_t i=0; i<neigbor_count.size(); ++i)
268 if (neigbor_count[i] == min_deg)
269 corners.push_back(i);
270 if(corners.size()==4){
271 if( !(corners[1]-corners[0] != corners[3]-corners[2])&&
272 !(corners[0] != 0 || corners[3] != numVar_-1) ){
274 shape_[0] = corners[1]-corners[0]+1;
275 shape_[1] = numVar_ / shape_[0];
278 if(shape_.size() ==1 && distanceType_ == EUCLIDEAN)
279 std::cout <<
"Warning : Shape of labeling is 1 and Euclidean distance does not make sense! Maybe autodetection of shape fails ..." <<std::endl;
284 constTermTrustRegion_ = 0;
285 for(
int i=0; i<approxUnaries_.size(); ++i){
286 approxUnaries_[i] += lambda_*distance_[i];
287 graph_->add_tweights( i, 0, approxUnaries_[i]);
289 constTermTrustRegion_-=lambda_*distance_[i];
293 template<
class LabelType>
295 if (distanceType_==HAMMING){
296 for(
int i=0; i<numVar_; ++i){
297 if(workingPoint_[i]==0){
306 else if(distanceType_==EUCLIDEAN){
307 std::cout <<
"Warning : The useage of euclidean distance requires VIGRA!" <<std::endl;
308 std::cout <<
" Vigra is disabled -> Switch to Hamming distance!" <<std::endl;
309 distanceType_=HAMMING;
310 for(
int i=0; i<numVar_; ++i){
311 if(workingPoint_[i]==0){
320 else if(distanceType_==EUCLIDEAN){
321 std::vector<size_t> s = shape_;
322 std::vector<double> dist0(numVar_,0);
323 std::vector<double> dist1(numVar_,0);
325 typedef vigra::MultiArrayView<1, LabelType> ArrayType;
326 typedef vigra::MultiArrayView<1, double> DArrayType;
327 typedef typename ArrayType::difference_type ShapeType;
328 ShapeType shape(s[0]);
332 ArrayType source( shape, stride, &workingPoint_[0] );
333 DArrayType dest0( shape, stride, &dist0[0] );
334 DArrayType dest1( shape, stride, &dist1[0] );
336 vigra::separableMultiDistance(source, dest0,
false);
337 vigra::separableMultiDistance(source, dest1,
true);
338 for(
int i=0; i<numVar_; ++i){
339 if(workingPoint_[i]==0){
340 distance_[i] = (dist1[i]-0.5);
343 distance_[i] = -(dist0[i]-0.5);
347 else if(s.size()==2){
348 typedef vigra::MultiArrayView<2, LabelType> ArrayType;
349 typedef vigra::MultiArrayView<2, double> DArrayType;
350 typedef typename ArrayType::difference_type ShapeType;
351 ShapeType shape(s[0],s[1]);
352 ShapeType stride(1,s[0]);
355 ArrayType source( shape, stride, &workingPoint_[0] );
356 DArrayType dest0( shape, stride, &dist0[0] );
357 DArrayType dest1( shape, stride, &dist1[0] );
359 vigra::separableMultiDistance(source, dest0,
false);
360 vigra::separableMultiDistance(source, dest1,
true);
361 for(
int i=0; i<numVar_; ++i){
362 if(workingPoint_[i]==0){
363 distance_[i] = (dist1[i]-0.5);
366 distance_[i] = -(dist0[i]-0.5);
370 else if(s.size()==3){
371 typedef vigra::MultiArrayView<3, LabelType> ArrayType;
372 typedef vigra::MultiArrayView<3, double> DArrayType;
373 typedef typename ArrayType::difference_type ShapeType;
374 ShapeType shape(s[0],s[1],s[2]);
375 ShapeType stride(1,s[0],s[0]*s[1]);
378 ArrayType source( shape, stride, &workingPoint_[0] );
379 DArrayType dest0( shape, stride, &dist0[0] );
380 DArrayType dest1( shape, stride, &dist1[0] );
382 vigra::separableMultiDistance(source, dest0,
false);
383 vigra::separableMultiDistance(source, dest1,
true);
384 for(
int i=0; i<numVar_; ++i){
385 if(workingPoint_[i]==0){
386 distance_[i] = (dist1[i]-0.5);
389 distance_[i] = -(dist0[i]-0.5);
396 std::cout <<
"Unknown distance"<<std::endl;
401 template<
class LabelType>
406 value = graph_->maxflow(
true,changedList_);
407 for (
typename graph_type::node_id* ptr = changedList_->ScanFirst(); ptr; ptr = changedList_->ScanNext()) {
408 typename graph_type::node_id var = *ptr;
410 graph_->remove_from_changed_list(var);
413 for(
size_t var=0; var<numVar_; ++var) {
414 if (graph_->what_segment(var) == graph_type::SOURCE) { label[var]=1;}
415 else { label[var]=0;}
417 changedList_->Reset();
420 value = graph_->maxflow();
421 for(
size_t var=0; var<numVar_; ++var) {
422 if (graph_->what_segment(var) == graph_type::SOURCE) { label[var]=1;}
423 else { label[var]=0;}
427 return value + constTerm_ + constTermApproximation_ + constTermTrustRegion_;
430 template<
class LabelType>
432 if( newLambda == lambda_ )
return;
433 double difLambda = newLambda - lambda_;
435 constTermTrustRegion_ = 0;
437 for(
int i=0; i<approxUnaries_.size(); ++i){
438 double oldcap = graph_->get_trcap(i);
439 approxUnaries_[i] += difLambda*distance_[i];
440 graph_->add_tweights( i, 0, difLambda*distance_[i] );
442 constTermTrustRegion_ -= difLambda*distance_[i];
443 double newcap = graph_->get_trcap(i);
444 if (!((newcap > 0 && oldcap > 0)||(newcap < 0 && oldcap < 0))){
445 graph_->mark_node(i);
449 for(
int i=0; i<approxUnaries_.size(); ++i){
450 approxUnaries_[i] += difLambda*distance_[i];
451 graph_->add_tweights( i, 0, difLambda*distance_[i] );
453 constTermTrustRegion_ -= difLambda*distance_[i];
458 template<
class LabelType>
460 workingPoint_ = newWorkingPoint;
462 constTermTrustRegion_ = 0;
463 constTermApproximation_ = 0;
467 std::vector<double> newApproxUnaries = unaries_;
468 for(
size_t i=0; i<supEdges_.size(); ++i){
469 const size_t var0 = supEdges_[i].u;
470 const size_t var1 = supEdges_[i].v;
471 const double w = supEdges_[i].w;
472 if(workingPoint_[var0]==1)
473 newApproxUnaries[var1] +=
w;
474 if(workingPoint_[var1]==1)
475 newApproxUnaries[var0] +=
w;
476 if(workingPoint_[var0]==1 && workingPoint_[var1]==1)
477 constTermApproximation_ -=
w;
480 for(
int i=0; i<numVar_; ++i){
481 double oldcap = graph_->get_trcap(i);
482 newApproxUnaries[i] += lambda_*distance_[i];
483 graph_->add_tweights( i, 0, newApproxUnaries[i]-approxUnaries_[i] );
485 constTermTrustRegion_ -= lambda_*distance_[i];
486 double newcap = graph_->get_trcap(i);
487 if (!((newcap > 0 && oldcap > 0)||(newcap < 0 && oldcap < 0))){
488 graph_->mark_node(i);
492 for(
int i=0; i<numVar_; ++i){
493 newApproxUnaries[i] += lambda_*distance_[i];
494 graph_->add_tweights( i, 0, newApproxUnaries[i]-approxUnaries_[i]);
496 constTermTrustRegion_ -= lambda_*distance_[i];
499 approxUnaries_.assign(newApproxUnaries.begin(),newApproxUnaries.end());
504 template<
class LabelType>
507 typedef double ValueType;
508 ValueType
v = constTerm_;
509 for(
size_t var=0; var<numVar_;++var)
512 for(
size_t i=0; i<subEdges_.size(); ++i)
513 if(label[subEdges_[i].
u] != label[subEdges_[i].v])
515 for(
size_t i=0; i<supEdges_.size(); ++i)
516 if(label[supEdges_[i].
u] == 1 && label[supEdges_[i].v] == 1)
521 template<
class LabelType>
524 typedef double ValueType;
525 ValueType
v = constTerm_;
526 for(
size_t var=0; var<numVar_;++var)
529 for(
size_t i=0; i<subEdges_.size(); ++i)
530 if(label[subEdges_[i].
u] != label[subEdges_[i].v])
532 for(
size_t i=0; i<supEdges_.size(); ++i){
533 if(label[supEdges_[i].
u] == 1 && workingPoint[supEdges_[i].v] == 1 )
535 if(workingPoint[supEdges_[i].
u] == 1 && label[supEdges_[i].v] == 1 )
537 if(workingPoint[supEdges_[i].
u] == 1 && workingPoint[supEdges_[i].v] == 1 )
540 for(
size_t i=0; i<numVar_; ++i){
541 if(label[i] != workingPoint[i])
542 v += lambda * std::fabs(distance_[i]);
547 template<
class LabelType>
548 void LSA_TR_HELPER<LabelType>::evalBoth(
const std::vector<LabelType>& label,
const std::vector<LabelType>& workingPoint,
const double lambda,
double& value,
double& valueAprox)
const 551 for(
size_t var=0; var<numVar_;++var)
553 value += unaries_[var];
554 for(
size_t i=0; i<subEdges_.size(); ++i)
555 if(label[subEdges_[i].
u] != label[subEdges_[i].
v])
556 value += subEdges_[i].w;
558 for(
size_t i=0; i<supEdges_.size(); ++i){
559 if(label[supEdges_[i].
u] == 1 && label[supEdges_[i].v] == 1 )
560 value += supEdges_[i].w;
561 if(label[supEdges_[i].
u] == 1 && workingPoint[supEdges_[i].v] == 1 )
562 valueAprox += supEdges_[i].w;
563 if(workingPoint[supEdges_[i].
u] == 1 && label[supEdges_[i].v] == 1 )
564 valueAprox += supEdges_[i].w;
565 if(workingPoint[supEdges_[i].
u] == 1 && workingPoint[supEdges_[i].v] == 1 )
566 valueAprox -= supEdges_[i].w;
568 for(
size_t i=0; i<numVar_; ++i){
569 if(label[i] != workingPoint[i])
570 valueAprox += lambda * std::fabs(distance_[i]);
578 template<
class GM,
class ACC>
581 template<
class GM,
class ACC>
593 template<
class GM,
class ACC>
605 template<
class GM,
class ACC>
608 srand(param_.randSeed_);
609 numVar_ = gm_.numberOfVariables();
610 curState_.resize(numVar_,1);
611 for (
size_t i=0; i<numVar_; ++i) curState_[i]= rand()%2;
612 helper_.init(gm_, curState_);
613 if(param_.distance_ == Parameter::HAMMING)
615 else if(param_.distance_ == Parameter::EUCLIDEAN)
618 std::cout <<
"Warning: Unknown distance type !"<<std::endl;
622 template<
class GM,
class ACC>
626 curState_.resize(numVar_,1);
629 template<
class GM,
class ACC>
632 curState_.assign(begin, begin+numVar_);
635 template<
class GM,
class ACC>
642 template<
class GM,
class ACC>
649 template<
class GM,
class ACC>
658 template<
class GM,
class ACC>
659 template<
class VisitorType>
666 const ValueType tau2 = param_.reductionRatio_;
668 std::vector<LabelType> label(numVar_);
669 std::vector<ValueType> energies;
670 std::vector<ValueType> energiesAprox;
671 double lambda = param_.initialLambda_;
672 helper_.set(curState_,lambda);
673 visitor.begin(*
this);
675 ValueType curr_value_aprox = helper_.evalAprox(curState_, curState_, lambda);
676 ValueType curr_value = helper_.eval(curState_);
677 bool changedWorkingpoint =
false;
678 bool changedLambda =
false;
682 OPENGM_ASSERT(std::fabs(curr_value-gm_.evaluate(curState_))<0.0001);
683 for (
size_t i=0; i<10000 ; ++i){
685 if(lambda>param_.maxLambda_)
break;
687 if(changedWorkingpoint)
688 helper_.set(curState_,lambda);
689 else if(changedLambda)
691 changedWorkingpoint =
false;
692 changedLambda =
false;
693 helper_.optimize(label);
694 helper_.evalBoth(label, curState_, lambda, value_after, value_after_aprox);
698 OPENGM_ASSERT(std::fabs(helper_.eval(curState_)-gm_.evaluate(curState_))<0.0001);
700 OPENGM_ASSERT(std::fabs(helper_.eval(label)-gm_.evaluate(label))<0.0001);
702 const ValueType P = curr_value_aprox - value_after_aprox;
703 const ValueType R = curr_value - value_after;
711 lambda = findMinimalChangeBrakPoint(lambda, curState_);
713 helper_.optimize(label);
716 helper_.evalBoth(label, curState_, lambda, value_after, value_after_aprox);
717 const ValueType P = curr_value_aprox - value_after_aprox;
718 const ValueType R = curr_value - value_after;
725 curState_.assign(label.begin(),label.end());
726 changedWorkingpoint =
true;
727 curr_value = value_after;
728 curr_value_aprox = value_after;
733 if(P<0) std::cout <<
"WARNING : "<< curr_value_aprox <<
" < " << value_after_aprox << std::endl;
737 curState_.assign(label.begin(),label.end());
738 changedWorkingpoint =
true;
740 curr_value = value_after;
741 curr_value_aprox = value_after;
748 lambda = lambda / param_.lambdaMultiplier_;
749 changedLambda =
true;
754 lambda = lambda * param_.lambdaMultiplier_;
755 changedLambda =
true;
761 energies.push_back (curr_value);
762 energiesAprox.push_back(value_after_aprox);
772 template<
class GM,
class ACC>
776 std::vector<LabelType>& x,
784 x.assign(curState_.begin(), curState_.end());
793 template<
class GM,
class ACC>
797 ValueType bottomLambda = param_.precisionLambda_;
798 std::vector<LabelType> topLabel(numVar_);
799 std::vector<LabelType> bottomLabel(numVar_);
800 std::vector<LabelType> label(numVar_);
803 helper_.set(topLambda);
804 helper_.optimize(topLabel);
805 if(!std::equal(topLabel.begin(),topLabel.end(),workingPoint.begin()))
806 topLambda = topLambda * 2;
812 helper_.set(bottomLambda);
813 helper_.optimize(bottomLabel);
817 double middleLambda = (topLambda + bottomLambda)/2.0;
819 helper_.set(middleLambda);
820 helper_.optimize(label);
822 if(!std::equal(label.begin(),label.end(),topLabel.begin())){
823 bottomLambda = middleLambda;
826 else if(!std::equal(label.begin(),label.end(),bottomLabel.begin())){
827 topLambda = middleLambda;
833 if((topLambda-bottomLambda) < param_.precisionLambda_){
841 #endif // #ifndef OPENGM_LSATR_HXX
opengm::visitors::EmptyVisitor< LSA_TR< GM, ACC > > EmptyVisitorType
void infer(const typename INF::GraphicalModelType &gm, const typename INF::Parameter ¶m, std::vector< typename INF::LabelType > &conf)
double eval(const std::vector< LabelType > &) const
#define OPENGM_ASSERT(expression)
void init(const GM &, const std::vector< LabelType > &)
virtual ValueType value() const
return the solution (value)
void setDistanceType(const DISTANCE d)
opengm::visitors::TimingVisitor< LSA_TR< GM, ACC > > TimingVisitorType
void setStartingPoint(typename std::vector< LabelType >::const_iterator)
set initial labeling
const GraphicalModelType & graphicalModel() const
double optimize(std::vector< LabelType > &)
double evalAprox(const std::vector< LabelType > &, const std::vector< LabelType > &, const double) const
GraphicalModelType::ValueType ValueType
Local Submodular Approximation with Trust Region regularization .
Inference algorithm interface.
virtual InferenceTermination arg(std::vector< LabelType > &, const size_t=1) const
output a solution
LSA_TR_WeightedEdge(double aw, size_t au, size_t av)
GraphicalModelType::LabelType LabelType
opengm::visitors::VerboseVisitor< LSA_TR< GM, ACC > > VerboseVisitorType
static const size_t ContinueInf
void evalBoth(const std::vector< LabelType > &label, const std::vector< LabelType > &workingPoint, const double lambda, double &value, double &valueAprox) const
LSA_TR(const GraphicalModelType &)
InferenceTermination infer()