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_;
00050 int numberOfThreads_;
00051 bool verbose_;
00052 double cutUp_;
00053 double epGap_;
00054 double workMem_;
00055 double treeMemoryLimit_;
00056 double timeLimit_;
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
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
00148 IloInt numberOfElements = 0;
00149 IloInt numberOfVariableElements = 0;
00150 IloInt numberOfFactorElements = 0;
00151
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
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
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
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
00243 size_t constraintCounter = 0;
00244
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
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
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
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
00311 cplex_.setParam(IloCplex::EpOpt, 1e-9);
00312 cplex_.setParam(IloCplex::EpInt, 0);
00313 cplex_.setParam(IloCplex::EpAGap, 0);
00314 cplex_.setParam(IloCplex::EpGap, parameter_.epGap_);
00315
00316
00317 cplex_.setParam(IloCplex::CutUp, parameter_.cutUp_);
00318
00319
00320 cplex_.setParam(IloCplex::WorkMem, parameter_.workMem_);
00321 cplex_.setParam(IloCplex::ClockType,2);
00322 cplex_.setParam(IloCplex::TiLim,parameter_.treeMemoryLimit_);
00323 cplex_.setParam(IloCplex::MemoryEmphasis, 1);
00324
00325
00326 cplex_.setParam(IloCplex::TiLim, parameter_.timeLimit_);
00327
00328
00329 cplex_.setParam(IloCplex::Threads, parameter_.numberOfThreads_);
00330
00331
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
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
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
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
00525
00526 }
00527
00528 }
00529
00530 #endif