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    //Set Problem Type
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    //Calculate Neighbourhood
00148    neighbours_.resize(gm_.numberOfVariables());
00149    edgeWeight_.resize(numberOfInternalEdges_,0);
00150    constant_=0;
00151    LPIndexType numberOfInternalEdges=0;
00152    // Add edges that have to be included
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    // Current Partition-Sets
00247    std::vector<VariableSetType> partitionSets;
00248 
00249    // Set-Up Partition-Sets from current/initial partitioning
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       // std::cout << numberOfPartitions << " conncted subsets."<<std::endl;
00261       change = false;
00262       std::vector<size_t> pruneSets;
00263       // Check all pairs of partitions
00264       for(size_t part0=0; part0<numberOfPartitions; ++part0){
00265          //std::cout <<"*"<<std::flush;
00266          // Find neighbord sets
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             //for(size_t part1=part0+1; part1<numberOfPartitions; ++part1){
00280             if(partitionSets[part0].size()==0 || partitionSets[part1].size()==0)
00281                continue;
00282             double improvement = solveBinaryKL(partitionSets[part0],partitionSets[part1]);
00283             //std::cout <<part0<<" vs "<<part1<<" : " <<improvement<<std::endl;
00284             OPENGM_ASSERT(improvement<1e-8);
00285             if(-1e-8>improvement){
00286                change = true; // Partition has been improved  
00287             }
00288          }
00289       } 
00290       // Check for each Partition ...
00291       for(size_t part0=0; part0<numberOfPartitions; ++part0){
00292          // ... if it is empty and can be pruned
00293          if(partitionSets[part0].size()==0){
00294             //std::cout <<"Remove "<<part0<<std::endl;
00295             pruneSets.push_back(part0);
00296          }
00297          // ... or if it can be splited into two sets
00298          else if(partitionSets[part0].size()>1){
00299             // std::cout <<part0<<" vs "<<"NULL"<<std::endl;
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       // Remove sets marked as to prune
00311       //std::cout << "Remove " <<pruneSets.size() << " subsets."<<std::endl;
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       // Update Labeling
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    //std::cout << "Set0: "<< set0.size() <<" Set1: "<< set1.size() << std::endl; 
00337 
00338    for(size_t outerIt=0; outerIt<100;++outerIt){ 
00339       // Compute D[n] = E_n - I_n
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       // Search a gready move sequence
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       // Build sequence of greedy best moves
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          // Search over moves from set0
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          // Search over moves from set1
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          // No more moves?
00423          if(moved == false){
00424             break;
00425          }
00426          
00427          // Move node and recalculate D
00428          //std::cout << " " <<improveSumSequence.back()+improve;
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        // Perform Move
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       // Search for the next move if this move has give improvement
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 } // end namespace opengm
00493 
00494 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Mon Jun 17 16:31:05 2013 for OpenGM by  doxygen 1.6.3