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>
115 initialLambda_ = 0.1;
116 precisionLambda_ = 1e-9;
117 lambdaMultiplier_ = 2;
118 reductionRatio_ = 0.25;
123 LSA_TR(
const GraphicalModelType&);
124 LSA_TR(
const GraphicalModelType&,
const Parameter&);
126 std::string
name()
const;
130 template<
class VisitorType>
138 double findMinimalChangeBrakPoint(
const double lambda,
const std::vector<LabelType>& workingPoint);
141 const GraphicalModelType& gm_;
143 std::vector<LabelType> curState_;
147 std::vector<ValueType> unaries_;
148 std::vector<LSA_TR_WeightedEdge> subEdges_;
149 std::vector<LSA_TR_WeightedEdge> supEdges_;
150 std::vector<ValueType> approxUnaries_;
155 template<
class LabelType>
158 typedef size_t IndexType;
160 numVar_ = gm.numberOfVariables();
161 workingPoint_ = workingPoint;
164 unaries_.resize(numVar_,0);
165 distance_.resize(numVar_,0);
171 for(IndexType f=0; f<gm.numberOfFactors();++f){
173 if(gm[f].numberOfVariables() == 0){
174 constTerm_ += gm[f](label00);
176 else if(gm[f].numberOfVariables() == 1){
177 const double v0 = gm[f](label00);
178 const double v1 = gm[f](label11);
179 const IndexType var0 = gm[f].variableIndex(0);
181 unaries_[var0] += v1-v0;
183 else if(gm[f].numberOfVariables() == 2){
184 const double v00 = gm[f](label00);
185 const double v01 = gm[f](label01);
186 const double v10 = gm[f](label10);
187 const double v11 = gm[f](label11);
188 const IndexType var0 = gm[f].variableIndex(0);
189 const IndexType var1 = gm[f].variableIndex(1);
191 const double D = 0.5*(v11-v00);
192 const double M = 0.5*(v10-v01);
193 unaries_[var0] += D+M;
194 unaries_[var1] += D-M;
195 const double V = v10-v00-D-M;
206 std::cout << std::endl;
207 std::cout << subEdges_.size() <<
" submodular edges."<<std::endl;
208 std::cout << supEdges_.size() <<
" supermodular edges."<<std::endl;
210 graph_ =
new graph_type(gm.numberOfVariables(),subEdges_.size()+1);
211 changedList_ =
new block_type(gm.numberOfVariables());
213 graph_->add_node(numVar_);
214 for(
size_t i=0; i<subEdges_.size(); ++i){
215 graph_->add_edge( subEdges_[i].u, subEdges_[i].v, subEdges_[i].w, subEdges_[i].w);
217 approxUnaries_.assign(unaries_.begin(),unaries_.end());
218 for(
size_t i=0; i<supEdges_.size(); ++i){
219 const size_t var0 = supEdges_[i].u;
220 const size_t var1 = supEdges_[i].v;
221 const double w = supEdges_[i].w;
222 if(workingPoint[var0]==1)
223 approxUnaries_[var1] += w;
224 if(workingPoint[var1]==1)
225 approxUnaries_[var0] += w;
226 if(workingPoint[var0]==1 && workingPoint[var1]==1)
227 constTermApproximation_ -= w;
231 shape_.resize(1,numVar_);
232 std::vector<size_t> neigbor_count(numVar_,0);
233 for(
size_t i=0; i<supEdges_.size(); ++i){
234 ++neigbor_count[supEdges_[i].u];
235 ++neigbor_count[supEdges_[i].v];
237 for(
size_t i=0; i<subEdges_.size(); ++i){
238 ++neigbor_count[subEdges_[i].u];
239 ++neigbor_count[subEdges_[i].v];
241 size_t min_deg = *std::min_element(neigbor_count.begin(),neigbor_count.end());
242 std::vector<size_t> corners;
243 for(
size_t i=0; i<neigbor_count.size(); ++i)
244 if (neigbor_count[i] == min_deg)
245 corners.push_back(i);
246 if(corners.size()==4){
247 if( !(corners[1]-corners[0] != corners[3]-corners[2])&&
248 !(corners[0] != 0 || corners[3] != numVar_-1) ){
250 shape_[0] = corners[1]-corners[0]+1;
251 shape_[1] = numVar_ / shape_[0];
254 if(shape_.size() ==1 && distanceType_ == EUCLIDEAN)
255 std::cout <<
"Warning : Shape of labeling is 1 and Euclidean distance does not make sense! Maybe autodetection of shape fails ..." <<std::endl;
260 constTermTrustRegion_ = 0;
261 for(
int i=0; i<approxUnaries_.size(); ++i){
262 approxUnaries_[i] += lambda_*distance_[i];
263 graph_->add_tweights( i, 0, approxUnaries_[i]);
265 constTermTrustRegion_-=lambda_*distance_[i];
269 template<
class LabelType>
271 if (distanceType_==HAMMING){
272 for(
int i=0; i<numVar_; ++i){
273 if(workingPoint_[i]==0){
282 else if(distanceType_==EUCLIDEAN){
283 std::cout <<
"Warning : The useage of euclidean distance requires VIGRA!" <<std::endl;
284 std::cout <<
" Vigra is disabled -> Switch to Hamming distance!" <<std::endl;
285 distanceType_=HAMMING;
286 for(
int i=0; i<numVar_; ++i){
287 if(workingPoint_[i]==0){
296 else if(distanceType_==EUCLIDEAN){
297 std::vector<size_t> s = shape_;
298 std::vector<double> dist0(numVar_,0);
299 std::vector<double> dist1(numVar_,0);
301 typedef vigra::MultiArrayView<1, LabelType> ArrayType;
302 typedef vigra::MultiArrayView<1, double> DArrayType;
303 typedef typename ArrayType::difference_type ShapeType;
304 ShapeType shape(s[0]);
308 ArrayType source( shape, stride, &workingPoint_[0] );
309 DArrayType dest0( shape, stride, &dist0[0] );
310 DArrayType dest1( shape, stride, &dist1[0] );
312 vigra::separableMultiDistance(source, dest0,
false);
313 vigra::separableMultiDistance(source, dest1,
true);
314 for(
int i=0; i<numVar_; ++i){
315 if(workingPoint_[i]==0){
316 distance_[i] = (dist1[i]-0.5);
319 distance_[i] = -(dist0[i]-0.5);
323 else if(s.size()==2){
324 typedef vigra::MultiArrayView<2, LabelType> ArrayType;
325 typedef vigra::MultiArrayView<2, double> DArrayType;
326 typedef typename ArrayType::difference_type ShapeType;
327 ShapeType shape(s[0],s[1]);
328 ShapeType stride(1,s[0]);
331 ArrayType source( shape, stride, &workingPoint_[0] );
332 DArrayType dest0( shape, stride, &dist0[0] );
333 DArrayType dest1( shape, stride, &dist1[0] );
335 vigra::separableMultiDistance(source, dest0,
false);
336 vigra::separableMultiDistance(source, dest1,
true);
337 for(
int i=0; i<numVar_; ++i){
338 if(workingPoint_[i]==0){
339 distance_[i] = (dist1[i]-0.5);
342 distance_[i] = -(dist0[i]-0.5);
346 else if(s.size()==3){
347 typedef vigra::MultiArrayView<3, LabelType> ArrayType;
348 typedef vigra::MultiArrayView<3, double> DArrayType;
349 typedef typename ArrayType::difference_type ShapeType;
350 ShapeType shape(s[0],s[1],s[2]);
351 ShapeType stride(1,s[0],s[0]*s[1]);
354 ArrayType source( shape, stride, &workingPoint_[0] );
355 DArrayType dest0( shape, stride, &dist0[0] );
356 DArrayType dest1( shape, stride, &dist1[0] );
358 vigra::separableMultiDistance(source, dest0,
false);
359 vigra::separableMultiDistance(source, dest1,
true);
360 for(
int i=0; i<numVar_; ++i){
361 if(workingPoint_[i]==0){
362 distance_[i] = (dist1[i]-0.5);
365 distance_[i] = -(dist0[i]-0.5);
372 std::cout <<
"Unknown distance"<<std::endl;
377 template<
class LabelType>
382 value = graph_->maxflow(
true,changedList_);
383 for (
typename graph_type::node_id* ptr = changedList_->ScanFirst(); ptr; ptr = changedList_->ScanNext()) {
384 typename graph_type::node_id var = *ptr;
386 graph_->remove_from_changed_list(var);
389 for(
size_t var=0; var<numVar_; ++var) {
390 if (graph_->what_segment(var) == graph_type::SOURCE) { label[var]=1;}
391 else { label[var]=0;}
393 changedList_->Reset();
396 value = graph_->maxflow();
397 for(
size_t var=0; var<numVar_; ++var) {
398 if (graph_->what_segment(var) == graph_type::SOURCE) { label[var]=1;}
399 else { label[var]=0;}
403 return value + constTerm_ + constTermApproximation_ + constTermTrustRegion_;
406 template<
class LabelType>
408 if( newLambda == lambda_ )
return;
409 double difLambda = newLambda - lambda_;
411 constTermTrustRegion_ = 0;
413 for(
int i=0; i<approxUnaries_.size(); ++i){
414 double oldcap = graph_->get_trcap(i);
415 approxUnaries_[i] += difLambda*distance_[i];
416 graph_->add_tweights( i, 0, difLambda*distance_[i] );
418 constTermTrustRegion_ -= difLambda*distance_[i];
419 double newcap = graph_->get_trcap(i);
420 if (!((newcap > 0 && oldcap > 0)||(newcap < 0 && oldcap < 0))){
421 graph_->mark_node(i);
425 for(
int i=0; i<approxUnaries_.size(); ++i){
426 approxUnaries_[i] += difLambda*distance_[i];
427 graph_->add_tweights( i, 0, difLambda*distance_[i] );
429 constTermTrustRegion_ -= difLambda*distance_[i];
434 template<
class LabelType>
436 workingPoint_ = newWorkingPoint;
438 constTermTrustRegion_ = 0;
439 constTermApproximation_ = 0;
443 std::vector<double> newApproxUnaries = unaries_;
444 for(
size_t i=0; i<supEdges_.size(); ++i){
445 const size_t var0 = supEdges_[i].u;
446 const size_t var1 = supEdges_[i].v;
447 const double w = supEdges_[i].w;
448 if(workingPoint_[var0]==1)
449 newApproxUnaries[var1] += w;
450 if(workingPoint_[var1]==1)
451 newApproxUnaries[var0] += w;
452 if(workingPoint_[var0]==1 && workingPoint_[var1]==1)
453 constTermApproximation_ -= w;
456 for(
int i=0; i<numVar_; ++i){
457 double oldcap = graph_->get_trcap(i);
458 newApproxUnaries[i] += lambda_*distance_[i];
459 graph_->add_tweights( i, 0, newApproxUnaries[i]-approxUnaries_[i] );
461 constTermTrustRegion_ -= lambda_*distance_[i];
462 double newcap = graph_->get_trcap(i);
463 if (!((newcap > 0 && oldcap > 0)||(newcap < 0 && oldcap < 0))){
464 graph_->mark_node(i);
468 for(
int i=0; i<numVar_; ++i){
469 newApproxUnaries[i] += lambda_*distance_[i];
470 graph_->add_tweights( i, 0, newApproxUnaries[i]-approxUnaries_[i]);
472 constTermTrustRegion_ -= lambda_*distance_[i];
475 approxUnaries_.assign(newApproxUnaries.begin(),newApproxUnaries.end());
480 template<
class LabelType>
483 typedef double ValueType;
484 ValueType v = constTerm_;
485 for(
size_t var=0; var<numVar_;++var)
488 for(
size_t i=0; i<subEdges_.size(); ++i)
489 if(label[subEdges_[i].u] != label[subEdges_[i].v])
491 for(
size_t i=0; i<supEdges_.size(); ++i)
492 if(label[supEdges_[i].u] == 1 && label[supEdges_[i].v] == 1)
497 template<
class LabelType>
500 typedef double ValueType;
501 ValueType v = constTerm_;
502 for(
size_t var=0; var<numVar_;++var)
505 for(
size_t i=0; i<subEdges_.size(); ++i)
506 if(label[subEdges_[i].u] != label[subEdges_[i].v])
508 for(
size_t i=0; i<supEdges_.size(); ++i){
509 if(label[supEdges_[i].u] == 1 && workingPoint[supEdges_[i].v] == 1 )
511 if(workingPoint[supEdges_[i].u] == 1 && label[supEdges_[i].v] == 1 )
513 if(workingPoint[supEdges_[i].u] == 1 && workingPoint[supEdges_[i].v] == 1 )
516 for(
size_t i=0; i<numVar_; ++i){
517 if(label[i] != workingPoint[i])
518 v += lambda * std::fabs(distance_[i]);
523 template<
class LabelType>
524 void LSA_TR_HELPER<LabelType>::evalBoth(
const std::vector<LabelType>& label,
const std::vector<LabelType>& workingPoint,
const double lambda,
double& value,
double& valueAprox)
const
527 for(
size_t var=0; var<numVar_;++var)
529 value += unaries_[var];
530 for(
size_t i=0; i<subEdges_.size(); ++i)
531 if(label[subEdges_[i].u] != label[subEdges_[i].v])
532 value += subEdges_[i].w;
534 for(
size_t i=0; i<supEdges_.size(); ++i){
535 if(label[supEdges_[i].u] == 1 && label[supEdges_[i].v] == 1 )
536 value += supEdges_[i].w;
537 if(label[supEdges_[i].u] == 1 && workingPoint[supEdges_[i].v] == 1 )
538 valueAprox += supEdges_[i].w;
539 if(workingPoint[supEdges_[i].u] == 1 && label[supEdges_[i].v] == 1 )
540 valueAprox += supEdges_[i].w;
541 if(workingPoint[supEdges_[i].u] == 1 && workingPoint[supEdges_[i].v] == 1 )
542 valueAprox -= supEdges_[i].w;
544 for(
size_t i=0; i<numVar_; ++i){
545 if(label[i] != workingPoint[i])
546 valueAprox += lambda * std::fabs(distance_[i]);
554 template<
class GM,
class ACC>
557 template<
class GM,
class ACC>
569 template<
class GM,
class ACC>
581 template<
class GM,
class ACC>
584 srand(param_.randSeed_);
585 numVar_ = gm_.numberOfVariables();
586 curState_.resize(numVar_,1);
587 for (
size_t i=0; i<numVar_; ++i) curState_[i]= rand()%2;
588 helper_.init(gm_, curState_);
589 if(param_.distance_ == Parameter::HAMMING)
591 else if(param_.distance_ == Parameter::EUCLIDEAN)
594 std::cout <<
"Warning: Unknown distance type !"<<std::endl;
598 template<
class GM,
class ACC>
602 curState_.resize(numVar_,1);
605 template<
class GM,
class ACC>
608 curState_.assign(begin, begin+numVar_);
611 template<
class GM,
class ACC>
618 template<
class GM,
class ACC>
625 template<
class GM,
class ACC>
634 template<
class GM,
class ACC>
635 template<
class VisitorType>
642 const ValueType tau2 = param_.reductionRatio_;
644 std::vector<LabelType> label(numVar_);
645 std::vector<ValueType> energies;
646 std::vector<ValueType> energiesAprox;
647 double lambda = param_.initialLambda_;
648 helper_.set(curState_,lambda);
649 visitor.begin(*
this);
651 ValueType curr_value_aprox = helper_.evalAprox(curState_, curState_, lambda);
652 ValueType curr_value = helper_.eval(curState_);
653 bool changedWorkingpoint =
false;
654 bool changedLambda =
false;
658 OPENGM_ASSERT(std::fabs(curr_value-gm_.evaluate(curState_))<0.0001);
659 for (
size_t i=0; i<10000 ; ++i){
661 if(lambda>param_.maxLambda_)
break;
663 if(changedWorkingpoint)
664 helper_.set(curState_,lambda);
665 else if(changedLambda)
667 changedWorkingpoint =
false;
668 changedLambda =
false;
669 helper_.optimize(label);
670 helper_.evalBoth(label, curState_, lambda, value_after, value_after_aprox);
674 OPENGM_ASSERT(std::fabs(helper_.eval(curState_)-gm_.evaluate(curState_))<0.0001);
676 OPENGM_ASSERT(std::fabs(helper_.eval(label)-gm_.evaluate(label))<0.0001);
678 const ValueType P = curr_value_aprox - value_after_aprox;
679 const ValueType R = curr_value - value_after;
687 lambda = findMinimalChangeBrakPoint(lambda, curState_);
689 helper_.optimize(label);
692 helper_.evalBoth(label, curState_, lambda, value_after, value_after_aprox);
693 const ValueType P = curr_value_aprox - value_after_aprox;
694 const ValueType R = curr_value - value_after;
701 curState_.assign(label.begin(),label.end());
702 changedWorkingpoint =
true;
703 curr_value = value_after;
704 curr_value_aprox = value_after;
709 if(P<0) std::cout <<
"WARNING : "<< curr_value_aprox <<
" < " << value_after_aprox << std::endl;
713 curState_.assign(label.begin(),label.end());
714 changedWorkingpoint =
true;
716 curr_value = value_after;
717 curr_value_aprox = value_after;
724 lambda = lambda / param_.lambdaMultiplier_;
725 changedLambda =
true;
730 lambda = lambda * param_.lambdaMultiplier_;
731 changedLambda =
true;
737 energies.push_back (curr_value);
738 energiesAprox.push_back(value_after_aprox);
748 template<
class GM,
class ACC>
752 std::vector<LabelType>& x,
760 x.assign(curState_.begin(), curState_.end());
769 template<
class GM,
class ACC>
772 ValueType topLambda = lambda;
773 ValueType bottomLambda = param_.precisionLambda_;
774 std::vector<LabelType> topLabel(numVar_);
775 std::vector<LabelType> bottomLabel(numVar_);
776 std::vector<LabelType> label(numVar_);
779 helper_.set(topLambda);
780 helper_.optimize(topLabel);
781 if(!std::equal(topLabel.begin(),topLabel.end(),workingPoint.begin()))
782 topLambda = topLambda * 2;
788 helper_.set(bottomLambda);
789 helper_.optimize(bottomLabel);
793 double middleLambda = (topLambda + bottomLambda)/2.0;
795 helper_.set(middleLambda);
796 helper_.optimize(label);
798 if(!std::equal(label.begin(),label.end(),topLabel.begin())){
799 bottomLambda = middleLambda;
802 else if(!std::equal(label.begin(),label.end(),bottomLabel.begin())){
803 topLambda = middleLambda;
809 if((topLambda-bottomLambda) < param_.precisionLambda_){
817 #endif // #ifndef OPENGM_LSATR_HXX
opengm::visitors::EmptyVisitor< LSA_TR< GM, ACC > > EmptyVisitorType
#define OPENGM_ASSERT(expression)
double evalAprox(const std::vector< LabelType > &, const std::vector< LabelType > &, const double) const
void init(const GM &, const std::vector< LabelType > &)
void setDistanceType(const DISTANCE d)
opengm::visitors::TimingVisitor< LSA_TR< GM, ACC > > TimingVisitorType
void setStartingPoint(typename std::vector< LabelType >::const_iterator)
set initial labeling
double optimize(std::vector< LabelType > &)
GraphicalModelType::ValueType ValueType
Local Submodular Approximation with Trust Region regularization .
Inference algorithm interface.
LSA_TR_WeightedEdge(double aw, size_t au, size_t av)
void evalBoth(const std::vector< LabelType > &label, const std::vector< LabelType > &workingPoint, const double lambda, double &value, double &valueAprox) const
GraphicalModelType::LabelType LabelType
double eval(const std::vector< LabelType > &) const
const GraphicalModelType & graphicalModel() const
opengm::visitors::VerboseVisitor< LSA_TR< GM, ACC > > VerboseVisitorType
static const size_t ContinueInf
virtual ValueType value() const
return the solution (value)
virtual InferenceTermination arg(std::vector< LabelType > &, const size_t=1) const
output a solution
LSA_TR(const GraphicalModelType &)
InferenceTermination infer()