lpcplex.hxx

Go to the documentation of this file.
00001 #pragma once
00002 #ifndef OPENGM_LP_CPLEX_HXX
00003 #define OPENGM_LP_CPLEX_HXX
00004 
00005 #include <vector>
00006 #include <string>
00007 #include <iostream>
00008 #include <fstream>
00009 #include <stdexcept>
00010 #include <typeinfo>
00011 
00012 #include <ilcplex/ilocplex.h>
00013 
00014 #include "opengm/datastructures/marray/marray.hxx"
00015 #include "opengm/opengm.hxx"
00016 #include "opengm/operations/adder.hxx"
00017 #include "opengm/operations/minimizer.hxx"
00018 #include "opengm/operations/maximizer.hxx"
00019 #include "opengm/inference/inference.hxx"
00020 #include "opengm/inference/visitors/visitor.hxx"
00021 
00022 namespace opengm {
00023 
00036 template<class GM, class ACC>
00037 class LPCplex : public Inference<GM, ACC> {
00038 public:
00039    typedef ACC AccumulationType; 
00040    typedef ACC AccumulatorType;
00041    typedef GM GraphicalModelType;
00042    OPENGM_GM_TYPE_TYPEDEFS; 
00043    typedef VerboseVisitor<LPCplex<GM, ACC> > VerboseVisitorType;
00044    typedef TimingVisitor<LPCplex<GM, ACC> > TimingVisitorType;
00045    typedef EmptyVisitor< LPCplex<GM, ACC> > EmptyVisitorType;
00046  
00047    class Parameter {
00048    public:
00049       bool integerConstraint_; // ILP=true, 1order-LP=false
00050       int numberOfThreads_;    // number of threads (0=autosect)
00051       bool verbose_;           // switch on/off verbode mode 
00052       double cutUp_;           // upper cutoff
00053       double epGap_;           // relative optimality gap tolerance
00054       double workMem_;         // maximal ammount of memory in MB used for workspace
00055       double treeMemoryLimit_; // maximal ammount of memory in MB used for treee
00056       double timeLimit_;       // maximal time in seconds the solver has
00057       int probeingLevel_;
00058       int coverCutLevel_;
00059       int disjunctiverCutLevel_;
00060       int cliqueCutLevel_;
00061       int MIRCutLevel_;
00062 
00066       Parameter
00067       (
00068          int numberOfThreads = 0, 
00069          double cutUp = 1.0e+75,
00070        double epGap=0
00071       )
00072       :  numberOfThreads_(numberOfThreads), 
00073          //integerConstraint_(false), 
00074          verbose_(false), 
00075          cutUp_(cutUp),
00076     epGap_(epGap),
00077          workMem_(128.0),
00078          treeMemoryLimit_(1e+75),
00079          timeLimit_(1e+75),
00080          probeingLevel_(0),
00081          coverCutLevel_(0),
00082          disjunctiverCutLevel_(0),
00083          cliqueCutLevel_(0),
00084          MIRCutLevel_(0)
00085          {
00086             numberOfThreads_   = numberOfThreads; 
00087             integerConstraint_ = false;
00088          };
00089    };
00090 
00091    LPCplex(const GraphicalModelType&, const Parameter& = Parameter());
00092    ~LPCplex();
00093    virtual std::string name() const 
00094       { return "LPCplex"; }
00095    const GraphicalModelType& graphicalModel() const;
00096    virtual InferenceTermination infer();
00097    template<class VisitorType>
00098    InferenceTermination infer(VisitorType&);
00099    virtual InferenceTermination arg(std::vector<LabelType>&, const size_t = 1) const;
00100    virtual InferenceTermination args(std::vector<std::vector<LabelType> >&) const 
00101       { return UNKNOWN; };
00102    void variable(const size_t, IndependentFactorType& out) const;     
00103    void factorVariable(const size_t, IndependentFactorType& out) const;
00104    typename GM::ValueType bound() const; 
00105    typename GM::ValueType value() const;
00106 
00107    size_t lpNodeVi(const IndexType variableIndex,const LabelType label)const;
00108    size_t lpFactorVi(const IndexType factorIndex,const size_t labelingIndex)const;
00109    template<class LABELING_ITERATOR>
00110    size_t lpFactorVi(const IndexType factorIndex,LABELING_ITERATOR labelingBegin,LABELING_ITERATOR labelingEnd)const;
00111    template<class LPVariableIndexIterator, class CoefficientIterator>
00112    void addConstraint(LPVariableIndexIterator, LPVariableIndexIterator, CoefficientIterator,const ValueType&, const ValueType&);
00113 
00114 private:
00115    const GraphicalModelType& gm_;
00116    Parameter parameter_;
00117    std::vector<size_t> idNodesBegin_; 
00118    std::vector<size_t> idFactorsBegin_; 
00119    std::vector<std::vector<size_t> > unaryFactors_;
00120     
00121    IloEnv env_;
00122    IloModel model_;
00123    IloNumVarArray x_;
00124    IloRangeArray c_;
00125    IloObjective obj_;
00126    IloNumArray sol_;
00127    IloCplex cplex_;
00128 };
00129 
00130 template<class GM, class ACC>
00131 LPCplex<GM, ACC>::LPCplex
00132 (
00133    const GraphicalModelType& gm, 
00134    const Parameter& para
00135 )
00136 :  gm_(gm) 
00137 {
00138    if(typeid(OperatorType) != typeid(opengm::Adder)) {
00139       throw RuntimeError("This implementation does only supports Min-Plus-Semiring and Max-Plus-Semiring.");
00140    }
00141       
00142    parameter_ = para;
00143    idNodesBegin_.resize(gm_.numberOfVariables());
00144    unaryFactors_.resize(gm_.numberOfVariables());
00145    idFactorsBegin_.resize(gm_.numberOfFactors());
00146 
00147    // temporal variables
00148    IloInt numberOfElements = 0;
00149    IloInt numberOfVariableElements = 0;
00150    IloInt numberOfFactorElements   = 0;
00151    // enumerate variables
00152    size_t idCounter = 0;
00153    for(size_t node = 0; node < gm_.numberOfVariables(); ++node) {
00154       numberOfVariableElements += gm_.numberOfLabels(node);
00155       idNodesBegin_[node] = idCounter;
00156       idCounter += gm_.numberOfLabels(node);
00157    }
00158    // enumerate factors
00159    for(size_t f = 0; f < gm_.numberOfFactors(); ++f) {
00160       if(gm_[f].numberOfVariables() == 1) {
00161          size_t node = gm_[f].variableIndex(0);
00162          unaryFactors_[node].push_back(f);
00163          idFactorsBegin_[f] = idNodesBegin_[node];
00164       }
00165       else {
00166          idFactorsBegin_[f] = idCounter;
00167          idCounter += gm_[f].size();
00168          numberOfFactorElements += gm_[f].size();
00169       }
00170    }
00171    numberOfElements = numberOfVariableElements + numberOfFactorElements;
00172     
00173    // build LP
00174    model_ = IloModel(env_);
00175    x_ = IloNumVarArray(env_);
00176    c_ = IloRangeArray(env_);
00177    sol_ = IloNumArray(env_);
00178 
00179    if(typeid(ACC) == typeid(opengm::Minimizer)) {
00180      obj_ = IloMinimize(env_);
00181    } else if(typeid(ACC) == typeid(opengm::Maximizer)){
00182      obj_ = IloMaximize(env_);
00183    } else {
00184      throw RuntimeError("This implementation does only support Minimizer or Maximizer accumulators");
00185    }
00186     
00187    // set variables and objective
00188    if(parameter_.integerConstraint_) {
00189       x_.add(IloNumVarArray(env_, numberOfVariableElements, 0, 1, ILOBOOL));
00190    }
00191    else {
00192       x_.add(IloNumVarArray(env_, numberOfVariableElements, 0, 1));
00193    }
00194    x_.add(IloNumVarArray(env_, numberOfFactorElements, 0, 1));
00195    IloNumArray obj(env_, numberOfElements);
00196 
00197    for(size_t node = 0; node < gm_.numberOfVariables(); ++node) {
00198       for(size_t i = 0; i < gm_.numberOfLabels(node); ++i) {
00199          ValueType t = 0;
00200          for(size_t n=0; n<unaryFactors_[node].size();++n) {
00201             t += gm_[unaryFactors_[node][n]](&i);
00202          }
00203          obj[idNodesBegin_[node]+i] = t;
00204       }
00205    }
00206    for(size_t f = 0; f < gm_.numberOfFactors(); ++f) {
00207       if(gm_[f].numberOfVariables() == 2) {
00208          size_t index[2];
00209          size_t counter = idFactorsBegin_[f];
00210          for(index[1]=0; index[1]<gm_[f].numberOfLabels(1);++index[1])
00211             for(index[0]=0; index[0]<gm_[f].numberOfLabels(0);++index[0])
00212                obj[counter++] = gm_[f](index);
00213       }
00214       else if(gm_[f].numberOfVariables() == 3) {
00215          size_t index[3];
00216          size_t counter = idFactorsBegin_[f] ;
00217          for(index[2]=0; index[2]<gm_[f].numberOfLabels(2);++index[2])
00218             for(index[1]=0; index[1]<gm_[f].numberOfLabels(1);++index[1])
00219                for(index[0]=0; index[0]<gm_[f].numberOfLabels(0);++index[0])
00220                   obj[counter++] = gm_[f](index);
00221       } 
00222       else if(gm_[f].numberOfVariables() == 4) {
00223          size_t index[4];
00224          size_t counter = idFactorsBegin_[f];
00225          for(index[3]=0; index[3]<gm_[f].numberOfLabels(3);++index[3])
00226             for(index[2]=0; index[2]<gm_[f].numberOfLabels(2);++index[2])
00227                for(index[1]=0; index[1]<gm_[f].numberOfLabels(1);++index[1])
00228                   for(index[0]=0; index[0]<gm_[f].numberOfLabels(0);++index[0])
00229                      obj[counter++] = gm_[f](index);
00230       }
00231       else if(gm_[f].numberOfVariables() > 4) {
00232          size_t counter = idFactorsBegin_[f];
00233          std::vector<size_t> coordinate(gm_[f].numberOfVariables());   
00234          marray::Marray<bool> temp(gm_[f].shapeBegin(), gm_[f].shapeEnd());
00235          for(marray::Marray<bool>::iterator mit = temp.begin(); mit != temp.end(); ++mit) {
00236             mit.coordinate(coordinate.begin());
00237             obj[counter++] = gm_[f](coordinate.begin());
00238          }
00239       }
00240    }
00241    obj_.setLinearCoefs(x_, obj);
00242    // set constraints
00243    size_t constraintCounter = 0;
00244    // \sum_i \mu_i = 1
00245    for(size_t node = 0; node < gm_.numberOfVariables(); ++node) {
00246       c_.add(IloRange(env_, 1, 1));
00247       for(size_t i = 0; i < gm_.numberOfLabels(node); ++i) {
00248          c_[constraintCounter].setLinearCoef(x_[idNodesBegin_[node]+i], 1);
00249       }
00250       ++constraintCounter;
00251    }
00252    // \sum_i \mu_{f;i_1,...,i_n} - \mu{b;j}= 0
00253    for(size_t f = 0; f < gm_.numberOfFactors(); ++f) {
00254       if(gm_[f].numberOfVariables() > 1) {
00255          marray::Marray<size_t> temp(gm_[f].shapeBegin(), gm_[f].shapeEnd());
00256          size_t counter = idFactorsBegin_[f];
00257          for(marray::Marray<size_t>::iterator mit = temp.begin(); mit != temp.end(); ++mit) {
00258             *mit = counter++;
00259          }
00260          for(size_t n = 0; n < gm_[f].numberOfVariables(); ++n) {
00261             size_t node = gm_[f].variableIndex(n);
00262             for(size_t i = 0; i < gm_.numberOfLabels(node); ++i) {
00263                c_.add(IloRange(env_, 0, 0));
00264                c_[constraintCounter].setLinearCoef(x_[idNodesBegin_[node]+i], -1);
00265                marray::View<size_t> view = temp.boundView(n, i);
00266                for(marray::View<size_t>::iterator vit = view.begin(); vit != view.end(); ++vit) {
00267                   c_[constraintCounter].setLinearCoef(x_[*vit], 1);
00268                }
00269                ++constraintCounter;
00270             }
00271          }
00272       }
00273    } 
00274 
00275    model_.add(obj_);
00276    model_.add(c_);
00277    // initialize solver
00278    try {
00279 cplex_ = IloCplex(model_);
00280    }
00281    catch(IloCplex::Exception& e) {
00282       std::cout << e << std::endl;
00283    throw std::runtime_error("CPLEX exception");
00284    } 
00285 }
00286 
00287 template <class GM, class ACC>
00288 InferenceTermination
00289 LPCplex<GM, ACC>::infer() {
00290    EmptyVisitorType v; 
00291    return infer(v); 
00292 }
00293 
00294 template<class GM, class ACC>
00295 template<class VisitorType>
00296 InferenceTermination 
00297 LPCplex<GM, ACC>::infer
00298 (
00299    VisitorType& visitor
00300 ) { 
00301    visitor.begin(*this,ACC::template neutral<ValueType>(),ACC::template ineutral<ValueType>());
00302    try {
00303       // verbose options
00304       if(parameter_.verbose_ == false) {
00305    cplex_.setParam(IloCplex::MIPDisplay, 0);
00306    cplex_.setParam(IloCplex::SimDisplay, 0);
00307    cplex_.setParam(IloCplex::SiftDisplay, 0);
00308    } 
00309          
00310       // tolarance settings
00311       cplex_.setParam(IloCplex::EpOpt, 1e-9); // Optimality Tolerance
00312       cplex_.setParam(IloCplex::EpInt, 0);    // amount by which an integer variable can differ from an integer
00313       cplex_.setParam(IloCplex::EpAGap, 0);   // Absolute MIP gap tolerance
00314       cplex_.setParam(IloCplex::EpGap, parameter_.epGap_); // Relative MIP gap tolerance
00315 
00316       // set hints
00317       cplex_.setParam(IloCplex::CutUp, parameter_.cutUp_);
00318 
00319       // memory setting
00320       cplex_.setParam(IloCplex::WorkMem, parameter_.workMem_);
00321       cplex_.setParam(IloCplex::ClockType,2);//wall-clock-time=2 cpu-time=1
00322       cplex_.setParam(IloCplex::TiLim,parameter_.treeMemoryLimit_);
00323       cplex_.setParam(IloCplex::MemoryEmphasis, 1);
00324 
00325       // time limit
00326       cplex_.setParam(IloCplex::TiLim, parameter_.timeLimit_);
00327 
00328       // multo-threading options
00329       cplex_.setParam(IloCplex::Threads, parameter_.numberOfThreads_);
00330 
00331       // Tuning
00332       cplex_.setParam(IloCplex::Probe, parameter_.probeingLevel_);
00333       cplex_.setParam(IloCplex::Covers, parameter_.coverCutLevel_);
00334       cplex_.setParam(IloCplex::DisjCuts, parameter_.disjunctiverCutLevel_);
00335       cplex_.setParam(IloCplex::Cliques, parameter_.cliqueCutLevel_);
00336       cplex_.setParam(IloCplex::MIRCuts, parameter_.MIRCutLevel_);
00337 
00338       // solve problem
00339       if(!cplex_.solve()) {
00340          std::cout << "failed to optimize." << std::endl;
00341          return UNKNOWN;
00342       }
00343       cplex_.getValues(sol_, x_);
00344    }
00345    catch(IloCplex::Exception e) {
00346       std::cout << "caught CPLEX exception: " << e << std::endl;
00347       return UNKNOWN;
00348    } 
00349    visitor.end(*this,this->value(),this->bound());
00350    return NORMAL;
00351 }
00352  
00353 template <class GM, class ACC>
00354 LPCplex<GM, ACC>::~LPCplex() {
00355    env_.end();
00356 }
00357 
00358 template <class GM, class ACC>
00359 inline InferenceTermination
00360 LPCplex<GM, ACC>::arg
00361 (
00362    std::vector<typename LPCplex<GM, ACC>::LabelType>& x, 
00363    const size_t N
00364 ) const {
00365    x.resize(gm_.numberOfVariables());
00366    for(size_t node = 0; node < gm_.numberOfVariables(); ++node) {
00367       ValueType value = sol_[idNodesBegin_[node]];
00368       size_t state = 0;
00369       for(size_t i = 1; i < gm_.numberOfLabels(node); ++i) {
00370          if(sol_[idNodesBegin_[node]+i] > value) {
00371             value = sol_[idNodesBegin_[node]+i];
00372             state = i;
00373          }
00374       }
00375       x[node] = state;
00376    }
00377    return NORMAL;
00378 }
00379 
00380 template <class GM, class ACC>
00381 void LPCplex<GM, ACC>::variable
00382 (
00383    const size_t nodeId, 
00384    IndependentFactorType& out
00385 ) const {
00386    size_t var[] = {nodeId};
00387    size_t shape[] = {gm_.numberOfLabels(nodeId)};
00388    out.assign(var, var + 1, shape, shape + 1);
00389    for(size_t i = 0; i < gm_.numberOfLabels(nodeId); ++i) {
00390       out(i) = sol_[idNodesBegin_[nodeId]+i];
00391    }
00392    //return UNKNOWN;
00393 }
00394 
00395 template <class GM, class ACC>
00396 void LPCplex<GM, ACC>::factorVariable
00397 (
00398    const size_t factorId, 
00399    IndependentFactorType& out
00400 ) const {
00401    std::vector<size_t> var(gm_[factorId].numberOfVariables());
00402    std::vector<size_t> shape(gm_[factorId].numberOfVariables());
00403    for(size_t i = 0; i < gm_[factorId].numberOfVariables(); ++i) {
00404       var[i] = gm_[factorId].variableIndex(i);
00405       shape[i] = gm_[factorId].shape(i);
00406    }
00407    out.assign(var.begin(), var.end(), shape.begin(), shape.end());
00408    if(gm_[factorId].numberOfVariables() == 1) {
00409       size_t nodeId = gm_[factorId].variableIndex(0);
00410       marginal(nodeId, out);
00411    }
00412    else {
00413       size_t c = 0;
00414       for(size_t n = idFactorsBegin_[factorId]; n<idFactorsBegin_[factorId]+gm_[factorId].size(); ++n) {
00415          out(c++) = sol_[n];
00416       }
00417    }
00418    //return UNKNOWN;
00419 }
00420 
00421 template<class GM, class ACC>
00422 inline const typename LPCplex<GM, ACC>::GraphicalModelType&
00423 LPCplex<GM, ACC>::graphicalModel() const 
00424 {
00425    return gm_;
00426 }
00427 
00428 template<class GM, class ACC>
00429 typename GM::ValueType LPCplex<GM, ACC>::value() const { 
00430    std::vector<LabelType> states;
00431    arg(states);
00432    return gm_.evaluate(states);
00433 }
00434 
00435 template<class GM, class ACC>
00436 typename GM::ValueType LPCplex<GM, ACC>::bound() const {
00437    if(parameter_.integerConstraint_) {
00438       return cplex_.getBestObjValue();
00439    }
00440    else{
00441       return  cplex_.getObjValue();
00442    }
00443 }
00444 
00445 
00446 template <class GM, class ACC>
00447 inline size_t 
00448 LPCplex<GM, ACC>::lpNodeVi
00449 (
00450    const typename LPCplex<GM, ACC>::IndexType variableIndex,
00451    const typename LPCplex<GM, ACC>::LabelType label
00452 )const{
00453    OPENGM_ASSERT(variableIndex<gm_.numberOfVariables());
00454    OPENGM_ASSERT(label<gm_.numberOfLabels(variableIndex));
00455    return idNodesBegin_[variableIndex]+label;
00456 }
00457 
00458 
00459 template <class GM, class ACC>
00460 inline size_t 
00461 LPCplex<GM, ACC>::lpFactorVi
00462 (
00463    const typename LPCplex<GM, ACC>::IndexType factorIndex,
00464    const size_t labelingIndex
00465 )const{
00466    OPENGM_ASSERT(factorIndex<gm_.numberOfFactors());
00467    OPENGM_ASSERT(labelingIndex<gm_[factorIndex].size());
00468    return idFactorsBegin_[factorIndex]+labelingIndex;
00469 }
00470 
00471 
00472 template <class GM, class ACC>
00473 template<class LABELING_ITERATOR>
00474 inline size_t 
00475 LPCplex<GM, ACC>::lpFactorVi
00476 (
00477    const typename LPCplex<GM, ACC>::IndexType factorIndex,
00478    LABELING_ITERATOR labelingBegin,
00479    LABELING_ITERATOR labelingEnd
00480 )const{
00481    OPENGM_ASSERT(factorIndex<gm_.numberOfFactors());
00482    OPENGM_ASSERT(std::distance(labelingBegin,labelingEnd)==gm_[factorIndex].numberOfVariables());
00483    const size_t numVar=gm_[factorIndex].numberOfVariables();
00484    size_t labelingIndex=labelingBegin[0];
00485    size_t strides=gm_[factorIndex].numberOfLabels(0);
00486    for(size_t vi=1;vi<numVar;++vi){
00487       OPENGM_ASSERT(labelingBegin[vi]<gm_[factorIndex].numberOfLabels(vi));
00488       labelingIndex+=strides*labelingBegin[vi];
00489       strides*=gm_[factorIndex].numberOfLabels(vi);
00490    }
00491    return idFactorsBegin_[factorIndex]+labelingIndex;
00492 }
00493 
00494 
00495 
00496 
00508 template<class GM, class ACC>
00509 template<class LPVariableIndexIterator, class CoefficientIterator>
00510 inline void LPCplex<GM, ACC>::addConstraint(
00511    LPVariableIndexIterator viBegin, 
00512    LPVariableIndexIterator viEnd, 
00513    CoefficientIterator coefficient, 
00514    const ValueType& lowerBound, 
00515    const ValueType& upperBound
00516 ) {
00517    IloRange constraint(env_, lowerBound, upperBound);
00518    while(viBegin != viEnd) {
00519       constraint.setLinearCoef(x_[*viBegin], *coefficient);
00520       ++viBegin;
00521       ++coefficient;
00522    }
00523    model_.add(constraint);
00524    // adding constraints does not require a re-initialization of the
00525    // object cplex_. cplex_ is initialized in the constructor.
00526 }
00527 
00528 } // end namespace opengm
00529 
00530 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Mon Jun 17 16:31:03 2013 for OpenGM by  doxygen 1.6.3