partition-move.hxx
Go to the documentation of this file.00001 #pragma once
00002 #ifndef OPENGM_PARTITIONMOVE_HXX
00003 #define OPENGM_PARTITIONMOVE_HXX
00004
00005 #include <algorithm>
00006 #include <vector>
00007 #include <queue>
00008 #include <utility>
00009 #include <string>
00010 #include <iostream>
00011 #include <fstream>
00012 #include <typeinfo>
00013 #include <limits>
00014 #ifndef WIDTH_BOOST
00015 #include <boost/unordered_map.hpp>
00016 #include <boost/unordered_set.hpp>
00017 #else
00018 #include <ext/hash_map>
00019 #include <ext/hash_set>
00020 #endif
00021
00022 #include "opengm/opengm.hxx"
00023 #include "opengm/inference/inference.hxx"
00024 #include "opengm/inference/visitors/visitor.hxx"
00025
00026
00027 namespace opengm {
00028
00038 template<class GM, class ACC>
00039 class PartitionMove : public Inference<GM, ACC>
00040 {
00041 public:
00042 typedef ACC AccumulationType;
00043 typedef GM GraphicalModelType;
00044 OPENGM_GM_TYPE_TYPEDEFS;
00045 typedef size_t LPIndexType;
00046 typedef VerboseVisitor<PartitionMove<GM,ACC> > VerboseVisitorType;
00047 typedef EmptyVisitor<PartitionMove<GM,ACC> > EmptyVisitorType;
00048 typedef TimingVisitor<PartitionMove<GM,ACC> > TimingVisitorType;
00049 #ifndef WIDTH_BOOST
00050 typedef boost::unordered_map<IndexType, LPIndexType> EdgeMapType;
00051 typedef boost::unordered_set<IndexType> VariableSetType;
00052 #else
00053 typedef __gnu_cxx::hash_map<IndexType, LPIndexType> EdgeMapType;
00054 typedef __gnu_cxx::hash_set<IndexType> VariableSetType;
00055 #endif
00056
00057
00058 struct Parameter{
00059 Parameter ( ) {};
00060 };
00061
00062 ~PartitionMove();
00063 PartitionMove(const GraphicalModelType&, Parameter para=Parameter());
00064 virtual std::string name() const {return "PartitionMove";}
00065 const GraphicalModelType& graphicalModel() const {return gm_;}
00066 virtual InferenceTermination infer();
00067 template<class VisitorType> InferenceTermination infer(VisitorType&);
00068 virtual InferenceTermination arg(std::vector<LabelType>&, const size_t = 1) const;
00069
00070 private:
00071 enum ProblemType {INVALID, MC, MWC};
00072
00073 const GraphicalModelType& gm_;
00074 ProblemType problemType_;
00075 Parameter parameter_;
00076
00077 LabelType numberOfTerminals_;
00078 LPIndexType numberOfInternalEdges_;
00079
00080
00083 std::vector<EdgeMapType > neighbours_;
00084 std::vector<double> edgeWeight_;
00085 double constant_;
00086 std::vector<LabelType> states_;
00087
00088 template<class VisitorType> InferenceTermination inferKL(VisitorType&);
00089 double solveBinaryKL(VariableSetType&, VariableSetType&);
00090
00091 };
00092
00093
00094 template<class GM, class ACC>
00095 PartitionMove<GM, ACC>::~PartitionMove() {
00096 ;
00097 }
00098
00099 template<class GM, class ACC>
00100 PartitionMove<GM, ACC>::PartitionMove
00101 (
00102 const GraphicalModelType& gm,
00103 Parameter para
00104 ) : gm_(gm), parameter_(para)
00105 {
00106 if(typeid(ACC) != typeid(opengm::Minimizer) || typeid(OperatorType) != typeid(opengm::Adder)) {
00107 throw RuntimeError("This implementation does only supports Min-Plus-Semiring.");
00108 }
00109
00110
00111
00112 problemType_ = MC;
00113 numberOfInternalEdges_ = 0;
00114 numberOfTerminals_ = gm_.numberOfLabels(0);
00115 for(size_t i=0; i<gm_.numberOfVariables(); ++i){
00116 if(gm_.numberOfLabels(i)<gm_.numberOfVariables()) {
00117 problemType_ = MWC;
00118 numberOfTerminals_ = std::max(numberOfTerminals_ ,gm_.numberOfLabels(i));
00119 }
00120 }
00121 for(size_t f=0; f<gm_.numberOfFactors();++f) {
00122 if(gm_[f].numberOfVariables()==0) {
00123 continue;
00124 }
00125 else if(gm_[f].numberOfVariables()==1) {
00126 problemType_ = MWC;
00127 }
00128 else if(gm_[f].numberOfVariables()==2) {
00129 ++numberOfInternalEdges_;
00130 if(!gm_[f].isPotts()) {
00131 problemType_ = INVALID;
00132 break;
00133 }
00134 }
00135 else{
00136 problemType_ = INVALID;
00137 break;
00138 }
00139 }
00140
00141 if(problemType_ == INVALID)
00142 throw RuntimeError("Invalid Model for Multicut-Solver! Solver requires a potts model!");
00143 if(problemType_ == MWC)
00144 throw RuntimeError("Invalid Model for Multicut-Solver! Solver currently do not support first order terms!");
00145
00146
00147
00148 neighbours_.resize(gm_.numberOfVariables());
00149 edgeWeight_.resize(numberOfInternalEdges_,0);
00150 constant_=0;
00151 LPIndexType numberOfInternalEdges=0;
00152
00153 for(size_t f=0; f<gm_.numberOfFactors(); ++f) {
00154 if(gm_[f].numberOfVariables()==0) {
00155 const LabelType l=0;
00156 constant_+=gm_[f](&l);
00157 }
00158 else if(gm_[f].numberOfVariables()==2) {
00159 LabelType cc0[] = {0,0};
00160 LabelType cc1[] = {0,1};
00161 edgeWeight_[numberOfInternalEdges] += gm_[f](cc1) - gm_[f](cc0);
00162 constant_ += gm_[f](cc0);
00163 IndexType u = gm_[f].variableIndex(0);
00164 IndexType v = gm_[f].variableIndex(1);
00165 neighbours_[u][v] = numberOfInternalEdges;
00166 neighbours_[v][u] = numberOfInternalEdges;
00167 ++numberOfInternalEdges;
00168 }
00169 else{
00170 throw RuntimeError("Only supports second order Potts functions!");
00171 }
00172 }
00173 OPENGM_ASSERT(numberOfInternalEdges==numberOfInternalEdges_);
00174
00175 states_.resize(gm_.numberOfVariables(),0);
00176 size_t init = 2;
00177
00178 if(init==1){
00179 for(size_t i=0; i<states_.size();++i){
00180 states_[i]=rand()%10;
00181 }
00182 }
00183
00184 if(init==2){
00185 LabelType p=0;
00186 std::vector<bool> assigned(states_.size(),false);
00187 for(IndexType node=0; node<states_.size(); ++node) {
00188 if(assigned[node])
00189 continue;
00190 else{
00191 std::list<IndexType> nodeList;
00192 states_[node] = p;
00193 assigned[node] = true;
00194 nodeList.push_back(node);
00195 while(!nodeList.empty()) {
00196 size_t n=nodeList.front(); nodeList.pop_front();
00197 for(typename EdgeMapType::const_iterator it=neighbours_[n].begin() ; it != neighbours_[n].end(); ++it) {
00198 const IndexType node2 = (*it).first;
00199 if(!assigned[node2] && edgeWeight_[(*it).second]>0) {
00200 states_[node2] = p;
00201 assigned[node2] = true;
00202 nodeList.push_back(node2);
00203 }
00204 }
00205 }
00206 ++p;
00207 }
00208 }
00209 }
00210
00211 if(init==3){
00212 for(size_t i=0; i<states_.size();++i){
00213 states_[i]=i;
00214 }
00215 }
00216
00217
00218 }
00219
00220
00221 template <class GM, class ACC>
00222 InferenceTermination
00223 PartitionMove<GM,ACC>::infer()
00224 {
00225 EmptyVisitorType visitor;
00226 return infer(visitor);
00227 }
00228
00229
00230 template <class GM, class ACC>
00231 template<class VisitorType>
00232 InferenceTermination
00233 PartitionMove<GM,ACC>::infer(VisitorType& visitor)
00234 {
00235 visitor.begin(*this);
00236 inferKL(visitor);
00237 visitor.end(*this);
00238 return NORMAL;
00239 }
00240
00241 template <class GM, class ACC>
00242 template<class VisitorType>
00243 InferenceTermination
00244 PartitionMove<GM,ACC>::inferKL(VisitorType& visitor)
00245 {
00246
00247 std::vector<VariableSetType> partitionSets;
00248
00249
00250 LabelType numberOfPartitions =0;
00251 for(size_t i=0; i<states_.size(); ++i)
00252 if(states_[i]+1>numberOfPartitions) numberOfPartitions=states_[i]+1;
00253 partitionSets.resize(numberOfPartitions);
00254 for(IndexType i=0; i<states_.size(); ++i){
00255 partitionSets[states_[i]].insert(i);
00256 }
00257
00258 bool change = true;
00259 while(change){
00260
00261 change = false;
00262 std::vector<size_t> pruneSets;
00263
00264 for(size_t part0=0; part0<numberOfPartitions; ++part0){
00265
00266
00267 std::set<size_t> neighbordSets;
00268 for(typename VariableSetType::const_iterator it=partitionSets[part0].begin(); it!=partitionSets[part0].end(); ++it){
00269 const IndexType node = (*it);
00270 for(typename EdgeMapType::const_iterator nit=neighbours_[node].begin() ; nit != neighbours_[node].end(); ++nit) {
00271 const IndexType node2 = (*nit).first;
00272 if(states_[node2]>part0){
00273 neighbordSets.insert(states_[node2]);
00274 }
00275 }
00276 }
00277 for(std::set<size_t>::const_iterator it=neighbordSets.begin(); it!=neighbordSets.end();++it){
00278 size_t part1 = *it;
00279
00280 if(partitionSets[part0].size()==0 || partitionSets[part1].size()==0)
00281 continue;
00282 double improvement = solveBinaryKL(partitionSets[part0],partitionSets[part1]);
00283
00284 OPENGM_ASSERT(improvement<1e-8);
00285 if(-1e-8>improvement){
00286 change = true;
00287 }
00288 }
00289 }
00290
00291 for(size_t part0=0; part0<numberOfPartitions; ++part0){
00292
00293 if(partitionSets[part0].size()==0){
00294
00295 pruneSets.push_back(part0);
00296 }
00297
00298 else if(partitionSets[part0].size()>1){
00299
00300
00301 VariableSetType emptySet(partitionSets[part0].size());
00302 double improvement = solveBinaryKL(partitionSets[part0], emptySet);
00303 if(emptySet.size()>0){
00304 OPENGM_ASSERT(improvement<0);
00305 partitionSets.push_back(emptySet);
00306 change = true;
00307 }
00308 }
00309 }
00310
00311
00312 for(size_t i=0; i<pruneSets.size(); ++i){
00313 size_t part = pruneSets[pruneSets.size()-1-i];
00314 partitionSets.erase( partitionSets.begin()+part);
00315 }
00316
00317 numberOfPartitions = partitionSets.size();
00318 for(size_t part=0; part<numberOfPartitions; ++part){
00319 for(typename VariableSetType::const_iterator it=partitionSets[part].begin(); it!=partitionSets[part].end(); ++it){
00320 states_[*it] = part;
00321 }
00322 }
00323 visitor(*this);
00324 }
00325 return NORMAL;
00326 }
00327
00328 template <class GM, class ACC>
00329 double PartitionMove<GM,ACC>::solveBinaryKL
00330 (
00331 VariableSetType& set0,
00332 VariableSetType& set1
00333 )
00334 {
00335 double improvement = 0.0;
00336
00337
00338 for(size_t outerIt=0; outerIt<100;++outerIt){
00339
00340 std::vector<double> D(gm_.numberOfVariables(),0);
00341 for(typename VariableSetType::const_iterator it=set0.begin(); it!=set0.end(); ++it){
00342 double E_a = 0.0;
00343 double I_a = 0.0;
00344 const IndexType node = *it;
00345 for (typename EdgeMapType::const_iterator eit=neighbours_[node].begin(); eit!=neighbours_[node].end(); ++eit){
00346 const IndexType node2 = (*eit).first;
00347 const double weight = edgeWeight_[(*eit).second];
00348
00349 if (set0.find(node2) != set0.end()) {
00350 I_a += weight;
00351 }
00352 else if(set1.find(node2) != set1.end()){
00353 E_a += weight;
00354 }
00355 }
00356 D[node] = -(E_a - I_a);
00357 }
00358 for(typename VariableSetType::const_iterator it=set1.begin(); it!=set1.end(); ++it){
00359 double E_a = 0.0;
00360 double I_a = 0.0;
00361 const IndexType node = *it;
00362 for(typename EdgeMapType::const_iterator eit=neighbours_[node].begin(); eit!=neighbours_[node].end(); ++eit){
00363 const IndexType node2 = (*eit).first;
00364 const double weight = edgeWeight_[(*eit).second];
00365
00366 if (set1.find(node2) != set1.end()) {
00367 I_a += weight;
00368 }
00369 else if(set0.find(node2) != set0.end()){
00370 E_a += weight;
00371 }
00372 }
00373 D[node] = -(E_a - I_a);
00374 }
00375
00376 double d=0;
00377 for(size_t i=0; i<D.size(); ++i){
00378 if(D[i]<d)
00379 d=D[i];
00380 }
00381
00382
00383
00384 std::vector<bool> isMovedNode(gm_.numberOfVariables(),false);
00385 std::vector<IndexType> nodeSequence;
00386 std::vector<double> improveSequence;
00387 std::vector<double> improveSumSequence(1,0.0);
00388 size_t bestMove=0;
00389
00390
00391 for(size_t innerIt=0; innerIt<1000; ++innerIt){
00392 double improve = std::numeric_limits<double>::infinity();
00393 IndexType node;
00394 bool moved = false;
00395
00396 for(typename VariableSetType::const_iterator it=set0.begin(); it!=set0.end(); ++it){
00397 if(isMovedNode[*it]){
00398 continue;
00399 }
00400 else{
00401 if(D[*it]<improve){
00402 improve = D[*it];
00403 node = *it;
00404 moved = true;
00405 }
00406 }
00407 }
00408
00409 for(typename VariableSetType::const_iterator it=set1.begin(); it!=set1.end(); ++it){
00410 if(isMovedNode[*it]){
00411 continue;
00412 }
00413 else{
00414 if(D[*it]<improve){
00415 improve = D[*it];
00416 node = *it;
00417 moved = true;
00418 }
00419 }
00420 }
00421
00422
00423 if(moved == false){
00424 break;
00425 }
00426
00427
00428
00429 isMovedNode[node]=true;
00430 nodeSequence.push_back(node);
00431 improveSumSequence.push_back(improveSumSequence.back()+improve);
00432 improveSequence.push_back(improve);
00433 if (improveSumSequence[bestMove]>improveSumSequence.back()) {
00434 bestMove = improveSumSequence.size()-1;
00435 }
00436
00437 VariableSetType& mySet = set0.find(node) != set0.end() ? set0 : set1;
00438 for(typename EdgeMapType::const_iterator eit=neighbours_[node].begin(); eit!=neighbours_[node].end(); ++eit){
00439 IndexType node2 = (*eit).first;
00440 double weight = edgeWeight_[(*eit).second];
00441 if(mySet.find(node2) != mySet.end()){
00442 D[node2] -= 2.0 * weight;
00443 }
00444 else{
00445 D[node2] += 2.0 * weight;
00446 }
00447
00448 }
00449 }
00450
00451
00452 if(improveSumSequence[bestMove]>-1e-10)
00453 break;
00454 else{
00455 improvement += improveSumSequence[bestMove];
00456 for (size_t i = 0; i < bestMove; ++i) {
00457 int node = nodeSequence[i];
00458 if (set0.find(node) != set0.end()) {
00459 set0.erase(node);
00460 set1.insert(node);
00461 }
00462 else{
00463 set1.erase(node);
00464 set0.insert(node);
00465 }
00466 }
00467 }
00468
00469 }
00470 return improvement;
00471 }
00472
00473 template <class GM, class ACC>
00474 InferenceTermination
00475 PartitionMove<GM,ACC>::arg
00476 (
00477 std::vector<typename PartitionMove<GM,ACC>::LabelType>& x,
00478 const size_t N
00479 ) const
00480 {
00481 if(N!=1) {
00482 return UNKNOWN;
00483 }
00484 else{
00485 x.resize(gm_.numberOfVariables());
00486 for(size_t i=0; i<gm_.numberOfVariables(); ++i)
00487 x[i] = states_[i];
00488 return NORMAL;
00489 }
00490 }
00491
00492 }
00493
00494 #endif