Add CBC support (#204)
authorBalazs Dezso <deba@inf.elte.hu>
Wed, 01 Apr 2009 22:58:58 +0200
changeset 5673314f58e7b25
parent 566 e7017ec2d5cd
child 568 b53a9068e3e4
Add CBC support (#204)
Makefile.am
configure.ac
lemon/Makefile.am
lemon/cbc.cc
lemon/cbc.h
lemon/config.h.in
m4/lx_check_cbc.m4
test/mip_test.cc
     1.1 --- a/Makefile.am	Thu Apr 02 19:29:56 2009 +0200
     1.2 +++ b/Makefile.am	Wed Apr 01 22:58:58 2009 +0200
     1.3 @@ -11,6 +11,8 @@
     1.4  	m4/lx_check_cplex.m4 \
     1.5  	m4/lx_check_glpk.m4 \
     1.6  	m4/lx_check_soplex.m4 \
     1.7 +	m4/lx_check_clp.m4 \
     1.8 +	m4/lx_check_cbc.m4 \
     1.9  	CMakeLists.txt \
    1.10  	cmake/FindGhostscript.cmake \
    1.11  	cmake/FindGLPK.cmake \
     2.1 --- a/configure.ac	Thu Apr 02 19:29:56 2009 +0200
     2.2 +++ b/configure.ac	Wed Apr 01 22:58:58 2009 +0200
     2.3 @@ -60,6 +60,7 @@
     2.4  LX_CHECK_CPLEX
     2.5  LX_CHECK_SOPLEX
     2.6  LX_CHECK_CLP
     2.7 +LX_CHECK_CBC
     2.8  
     2.9  AM_CONDITIONAL([HAVE_LP], [test x"$lx_lp_found" = x"yes"])
    2.10  AM_CONDITIONAL([HAVE_MIP], [test x"$lx_mip_found" = x"yes"])
    2.11 @@ -119,6 +120,7 @@
    2.12  echo CPLEX support................. : $lx_cplex_found
    2.13  echo SOPLEX support................ : $lx_soplex_found
    2.14  echo CLP support................... : $lx_clp_found
    2.15 +echo CBC support................... : $lx_cbc_found
    2.16  echo
    2.17  echo Build additional tools........ : $enable_tools
    2.18  echo
     3.1 --- a/lemon/Makefile.am	Thu Apr 02 19:29:56 2009 +0200
     3.2 +++ b/lemon/Makefile.am	Wed Apr 01 22:58:58 2009 +0200
     3.3 @@ -12,7 +12,7 @@
     3.4  	lemon/color.cc \
     3.5  	lemon/lp_base.cc \
     3.6  	lemon/lp_skeleton.cc \
     3.7 -        lemon/random.cc \
     3.8 +	lemon/random.cc \
     3.9  	lemon/bits/windows.cc
    3.10  
    3.11  
    3.12 @@ -21,13 +21,15 @@
    3.13  	$(GLPK_CFLAGS) \
    3.14  	$(CPLEX_CFLAGS) \
    3.15  	$(SOPLEX_CXXFLAGS) \
    3.16 -	$(CLP_CXXFLAGS)
    3.17 +	$(CLP_CXXFLAGS) \
    3.18 +	$(CBC_CXXFLAGS)
    3.19  
    3.20  lemon_libemon_la_LDFLAGS = \
    3.21  	$(GLPK_LIBS) \
    3.22  	$(CPLEX_LIBS) \
    3.23  	$(SOPLEX_LIBS) \
    3.24 -	$(CLP_LIBS)
    3.25 +	$(CLP_LIBS) \
    3.26 +	$(CBC_LIBS)
    3.27  
    3.28  if HAVE_GLPK
    3.29  lemon_libemon_la_SOURCES += lemon/glpk.cc
    3.30 @@ -45,6 +47,10 @@
    3.31  lemon_libemon_la_SOURCES += lemon/clp.cc
    3.32  endif
    3.33  
    3.34 +if HAVE_CBC
    3.35 +lemon_libemon_la_SOURCES += lemon/cbc.cc
    3.36 +endif
    3.37 +
    3.38  lemon_HEADERS += \
    3.39  	lemon/adaptors.h \
    3.40  	lemon/arg_parser.h \
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/lemon/cbc.cc	Wed Apr 01 22:58:58 2009 +0200
     4.3 @@ -0,0 +1,460 @@
     4.4 +/* -*- mode: C++; indent-tabs-mode: nil; -*-
     4.5 + *
     4.6 + * This file is a part of LEMON, a generic C++ optimization library.
     4.7 + *
     4.8 + * Copyright (C) 2003-2009
     4.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    4.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    4.11 + *
    4.12 + * Permission to use, modify and distribute this software is granted
    4.13 + * provided that this copyright notice appears in all copies. For
    4.14 + * precise terms see the accompanying LICENSE file.
    4.15 + *
    4.16 + * This software is provided "AS IS" with no warranty of any kind,
    4.17 + * express or implied, and with no claim as to its suitability for any
    4.18 + * purpose.
    4.19 + *
    4.20 + */
    4.21 +
    4.22 +///\file
    4.23 +///\brief Implementation of the CBC MIP solver interface.
    4.24 +
    4.25 +#include "cbc.h"
    4.26 +
    4.27 +#include <coin/CoinModel.hpp>
    4.28 +#include <coin/CbcModel.hpp>
    4.29 +#include <coin/OsiSolverInterface.hpp>
    4.30 +
    4.31 +#ifdef COIN_HAS_CLP
    4.32 +#include "coin/OsiClpSolverInterface.hpp"
    4.33 +#endif
    4.34 +#ifdef COIN_HAS_OSL
    4.35 +#include "coin/OsiOslSolverInterface.hpp"
    4.36 +#endif
    4.37 +
    4.38 +#include "coin/CbcCutGenerator.hpp"
    4.39 +#include "coin/CbcHeuristicLocal.hpp"
    4.40 +#include "coin/CbcHeuristicGreedy.hpp"
    4.41 +#include "coin/CbcHeuristicFPump.hpp"
    4.42 +#include "coin/CbcHeuristicRINS.hpp"
    4.43 +
    4.44 +#include "coin/CglGomory.hpp"
    4.45 +#include "coin/CglProbing.hpp"
    4.46 +#include "coin/CglKnapsackCover.hpp"
    4.47 +#include "coin/CglOddHole.hpp"
    4.48 +#include "coin/CglClique.hpp"
    4.49 +#include "coin/CglFlowCover.hpp"
    4.50 +#include "coin/CglMixedIntegerRounding.hpp"
    4.51 +
    4.52 +#include "coin/CbcHeuristic.hpp"
    4.53 +
    4.54 +namespace lemon {
    4.55 +
    4.56 +  CbcMip::CbcMip() {
    4.57 +    _prob = new CoinModel();
    4.58 +    _prob->setProblemName("LEMON");
    4.59 +    _osi_solver = 0;
    4.60 +    _cbc_model = 0;
    4.61 +  }
    4.62 +
    4.63 +  CbcMip::CbcMip(const CbcMip& other) {
    4.64 +    _prob = new CoinModel(*other._prob);
    4.65 +    _osi_solver = 0;
    4.66 +    _cbc_model = 0;
    4.67 +  }
    4.68 +
    4.69 +  CbcMip::~CbcMip() {
    4.70 +    delete _prob;
    4.71 +    if (_osi_solver) delete _osi_solver;
    4.72 +    if (_cbc_model) delete _cbc_model;
    4.73 +  }
    4.74 +
    4.75 +  const char* CbcMip::_solverName() const { return "CbcMip"; }
    4.76 +
    4.77 +  int CbcMip::_addCol() {
    4.78 +    _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false);
    4.79 +    return _prob->numberColumns() - 1;
    4.80 +  }
    4.81 +
    4.82 +  CbcMip* CbcMip::newSolver() const {
    4.83 +    CbcMip* newlp = new CbcMip;
    4.84 +    return newlp;
    4.85 +  }
    4.86 +
    4.87 +  CbcMip* CbcMip::cloneSolver() const {
    4.88 +    CbcMip* copylp = new CbcMip(*this);
    4.89 +    return copylp;
    4.90 +  }
    4.91 +
    4.92 +  int CbcMip::_addRow() {
    4.93 +    _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
    4.94 +    return _prob->numberRows() - 1;
    4.95 +  }
    4.96 +
    4.97 +
    4.98 +  void CbcMip::_eraseCol(int i) {
    4.99 +    _prob->deleteColumn(i);
   4.100 +  }
   4.101 +
   4.102 +  void CbcMip::_eraseRow(int i) {
   4.103 +    _prob->deleteRow(i);
   4.104 +  }
   4.105 +
   4.106 +  void CbcMip::_eraseColId(int i) {
   4.107 +    cols.eraseIndex(i);
   4.108 +  }
   4.109 +
   4.110 +  void CbcMip::_eraseRowId(int i) {
   4.111 +    rows.eraseIndex(i);
   4.112 +  }
   4.113 +
   4.114 +  void CbcMip::_getColName(int c, std::string& name) const {
   4.115 +    name = _prob->getColumnName(c);
   4.116 +  }
   4.117 +
   4.118 +  void CbcMip::_setColName(int c, const std::string& name) {
   4.119 +    _prob->setColumnName(c, name.c_str());
   4.120 +  }
   4.121 +
   4.122 +  int CbcMip::_colByName(const std::string& name) const {
   4.123 +    return _prob->column(name.c_str());
   4.124 +  }
   4.125 +
   4.126 +  void CbcMip::_getRowName(int r, std::string& name) const {
   4.127 +    name = _prob->getRowName(r);
   4.128 +  }
   4.129 +
   4.130 +  void CbcMip::_setRowName(int r, const std::string& name) {
   4.131 +    _prob->setRowName(r, name.c_str());
   4.132 +  }
   4.133 +
   4.134 +  int CbcMip::_rowByName(const std::string& name) const {
   4.135 +    return _prob->row(name.c_str());
   4.136 +  }
   4.137 +
   4.138 +  void CbcMip::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
   4.139 +    for (ExprIterator it = b; it != e; ++it) {
   4.140 +      _prob->setElement(i, it->first, it->second);
   4.141 +    }
   4.142 +  }
   4.143 +
   4.144 +  void CbcMip::_getRowCoeffs(int ix, InsertIterator b) const {
   4.145 +    int length = _prob->numberRows();
   4.146 +
   4.147 +    std::vector<int> indices(length);
   4.148 +    std::vector<Value> values(length);
   4.149 +
   4.150 +    length = _prob->getRow(ix, &indices[0], &values[0]);
   4.151 +
   4.152 +    for (int i = 0; i < length; ++i) {
   4.153 +      *b = std::make_pair(indices[i], values[i]);
   4.154 +      ++b;
   4.155 +    }
   4.156 +  }
   4.157 +
   4.158 +  void CbcMip::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
   4.159 +    for (ExprIterator it = b; it != e; ++it) {
   4.160 +      _prob->setElement(it->first, ix, it->second);
   4.161 +    }
   4.162 +  }
   4.163 +
   4.164 +  void CbcMip::_getColCoeffs(int ix, InsertIterator b) const {
   4.165 +    int length = _prob->numberColumns();
   4.166 +
   4.167 +    std::vector<int> indices(length);
   4.168 +    std::vector<Value> values(length);
   4.169 +
   4.170 +    length = _prob->getColumn(ix, &indices[0], &values[0]);
   4.171 +
   4.172 +    for (int i = 0; i < length; ++i) {
   4.173 +      *b = std::make_pair(indices[i], values[i]);
   4.174 +      ++b;
   4.175 +    }
   4.176 +  }
   4.177 +
   4.178 +  void CbcMip::_setCoeff(int ix, int jx, Value value) {
   4.179 +    _prob->setElement(ix, jx, value);
   4.180 +  }
   4.181 +
   4.182 +  CbcMip::Value CbcMip::_getCoeff(int ix, int jx) const {
   4.183 +    return _prob->getElement(ix, jx);
   4.184 +  }
   4.185 +
   4.186 +
   4.187 +  void CbcMip::_setColLowerBound(int i, Value lo) {
   4.188 +    LEMON_ASSERT(lo != INF, "Invalid bound");
   4.189 +    _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
   4.190 +  }
   4.191 +
   4.192 +  CbcMip::Value CbcMip::_getColLowerBound(int i) const {
   4.193 +    double val = _prob->getColumnLower(i);
   4.194 +    return val == - COIN_DBL_MAX ? - INF : val;
   4.195 +  }
   4.196 +
   4.197 +  void CbcMip::_setColUpperBound(int i, Value up) {
   4.198 +    LEMON_ASSERT(up != -INF, "Invalid bound");
   4.199 +    _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
   4.200 +  }
   4.201 +
   4.202 +  CbcMip::Value CbcMip::_getColUpperBound(int i) const {
   4.203 +    double val = _prob->getColumnUpper(i);
   4.204 +    return val == COIN_DBL_MAX ? INF : val;
   4.205 +  }
   4.206 +
   4.207 +  void CbcMip::_setRowLowerBound(int i, Value lo) {
   4.208 +    LEMON_ASSERT(lo != INF, "Invalid bound");
   4.209 +    _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
   4.210 +  }
   4.211 +
   4.212 +  CbcMip::Value CbcMip::_getRowLowerBound(int i) const {
   4.213 +    double val = _prob->getRowLower(i);
   4.214 +    return val == - COIN_DBL_MAX ? - INF : val;
   4.215 +  }
   4.216 +
   4.217 +  void CbcMip::_setRowUpperBound(int i, Value up) {
   4.218 +    LEMON_ASSERT(up != -INF, "Invalid bound");
   4.219 +    _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
   4.220 +  }
   4.221 +
   4.222 +  CbcMip::Value CbcMip::_getRowUpperBound(int i) const {
   4.223 +    double val = _prob->getRowUpper(i);
   4.224 +    return val == COIN_DBL_MAX ? INF : val;
   4.225 +  }
   4.226 +
   4.227 +  void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) {
   4.228 +    int num = _prob->numberColumns();
   4.229 +    for (int i = 0; i < num; ++i) {
   4.230 +      _prob->setColumnObjective(i, 0.0);
   4.231 +    }
   4.232 +    for (ExprIterator it = b; it != e; ++it) {
   4.233 +      _prob->setColumnObjective(it->first, it->second);
   4.234 +    }
   4.235 +  }
   4.236 +
   4.237 +  void CbcMip::_getObjCoeffs(InsertIterator b) const {
   4.238 +    int num = _prob->numberColumns();
   4.239 +    for (int i = 0; i < num; ++i) {
   4.240 +      Value coef = _prob->getColumnObjective(i);
   4.241 +      if (coef != 0.0) {
   4.242 +        *b = std::make_pair(i, coef);
   4.243 +        ++b;
   4.244 +      }
   4.245 +    }
   4.246 +  }
   4.247 +
   4.248 +  void CbcMip::_setObjCoeff(int i, Value obj_coef) {
   4.249 +    _prob->setColumnObjective(i, obj_coef);
   4.250 +  }
   4.251 +
   4.252 +  CbcMip::Value CbcMip::_getObjCoeff(int i) const {
   4.253 +    return _prob->getColumnObjective(i);
   4.254 +  }
   4.255 +
   4.256 +  CbcMip::SolveExitStatus CbcMip::_solve() {
   4.257 +
   4.258 +    if (_osi_solver) {
   4.259 +      delete _osi_solver;
   4.260 +    }
   4.261 +#ifdef COIN_HAS_CLP
   4.262 +    _osi_solver = new OsiClpSolverInterface();
   4.263 +#elif COIN_HAS_OSL
   4.264 +    _osi_solver = new OsiOslSolverInterface();
   4.265 +#else
   4.266 +#error Cannot instantiate Osi solver
   4.267 +#endif
   4.268 +
   4.269 +    _osi_solver->loadFromCoinModel(*_prob);
   4.270 +
   4.271 +    if (_cbc_model) {
   4.272 +      delete _cbc_model;
   4.273 +    }
   4.274 +    _cbc_model= new CbcModel(*_osi_solver);
   4.275 +
   4.276 +    switch (_message_level) {
   4.277 +    case MESSAGE_NO_OUTPUT:
   4.278 +      _osi_solver->messageHandler()->setLogLevel(0);
   4.279 +      _cbc_model->setLogLevel(0);
   4.280 +      break;
   4.281 +    case MESSAGE_ERROR_MESSAGE:
   4.282 +      _osi_solver->messageHandler()->setLogLevel(1);
   4.283 +      _cbc_model->setLogLevel(1);
   4.284 +      break;
   4.285 +    case MESSAGE_NORMAL_OUTPUT:
   4.286 +      _osi_solver->messageHandler()->setLogLevel(2);
   4.287 +      _cbc_model->setLogLevel(2);
   4.288 +      break;
   4.289 +    case MESSAGE_FULL_OUTPUT:
   4.290 +      _osi_solver->messageHandler()->setLogLevel(3);
   4.291 +      _cbc_model->setLogLevel(3);
   4.292 +      break;
   4.293 +    }
   4.294 +
   4.295 +    _cbc_model->initialSolve();
   4.296 +    _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
   4.297 +
   4.298 +    if (!_cbc_model->isInitialSolveAbandoned() &&
   4.299 +        _cbc_model->isInitialSolveProvenOptimal() &&
   4.300 +        !_cbc_model->isInitialSolveProvenPrimalInfeasible() &&
   4.301 +        !_cbc_model->isInitialSolveProvenDualInfeasible()) {
   4.302 +
   4.303 +      CglProbing generator1;
   4.304 +      generator1.setUsingObjective(true);
   4.305 +      generator1.setMaxPass(3);
   4.306 +      generator1.setMaxProbe(100);
   4.307 +      generator1.setMaxLook(50);
   4.308 +      generator1.setRowCuts(3);
   4.309 +      _cbc_model->addCutGenerator(&generator1, -1, "Probing");
   4.310 +
   4.311 +      CglGomory generator2;
   4.312 +      generator2.setLimit(300);
   4.313 +      _cbc_model->addCutGenerator(&generator2, -1, "Gomory");
   4.314 +
   4.315 +      CglKnapsackCover generator3;
   4.316 +      _cbc_model->addCutGenerator(&generator3, -1, "Knapsack");
   4.317 +
   4.318 +      CglOddHole generator4;
   4.319 +      generator4.setMinimumViolation(0.005);
   4.320 +      generator4.setMinimumViolationPer(0.00002);
   4.321 +      generator4.setMaximumEntries(200);
   4.322 +      _cbc_model->addCutGenerator(&generator4, -1, "OddHole");
   4.323 +
   4.324 +      CglClique generator5;
   4.325 +      generator5.setStarCliqueReport(false);
   4.326 +      generator5.setRowCliqueReport(false);
   4.327 +      _cbc_model->addCutGenerator(&generator5, -1, "Clique");
   4.328 +
   4.329 +      CglMixedIntegerRounding mixedGen;
   4.330 +      _cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding");
   4.331 +
   4.332 +      CglFlowCover flowGen;
   4.333 +      _cbc_model->addCutGenerator(&flowGen, -1, "FlowCover");
   4.334 +
   4.335 +#ifdef COIN_HAS_CLP
   4.336 +      OsiClpSolverInterface* osiclp =
   4.337 +        dynamic_cast<OsiClpSolverInterface*>(_cbc_model->solver());
   4.338 +      if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) {
   4.339 +        osiclp->setupForRepeatedUse(2, 0);
   4.340 +      }
   4.341 +#endif
   4.342 +
   4.343 +      CbcRounding heuristic1(*_cbc_model);
   4.344 +      heuristic1.setWhen(3);
   4.345 +      _cbc_model->addHeuristic(&heuristic1);
   4.346 +
   4.347 +      CbcHeuristicLocal heuristic2(*_cbc_model);
   4.348 +      heuristic2.setWhen(3);
   4.349 +      _cbc_model->addHeuristic(&heuristic2);
   4.350 +
   4.351 +      CbcHeuristicGreedyCover heuristic3(*_cbc_model);
   4.352 +      heuristic3.setAlgorithm(11);
   4.353 +      heuristic3.setWhen(3);
   4.354 +      _cbc_model->addHeuristic(&heuristic3);
   4.355 +
   4.356 +      CbcHeuristicFPump heuristic4(*_cbc_model);
   4.357 +      heuristic4.setWhen(3);
   4.358 +      _cbc_model->addHeuristic(&heuristic4);
   4.359 +
   4.360 +      CbcHeuristicRINS heuristic5(*_cbc_model);
   4.361 +      heuristic5.setWhen(3);
   4.362 +      _cbc_model->addHeuristic(&heuristic5);
   4.363 +
   4.364 +      if (_cbc_model->getNumCols() < 500) {
   4.365 +        _cbc_model->setMaximumCutPassesAtRoot(-100);
   4.366 +      } else if (_cbc_model->getNumCols() < 5000) {
   4.367 +        _cbc_model->setMaximumCutPassesAtRoot(100);
   4.368 +      } else {
   4.369 +        _cbc_model->setMaximumCutPassesAtRoot(20);
   4.370 +      }
   4.371 +
   4.372 +      if (_cbc_model->getNumCols() < 5000) {
   4.373 +        _cbc_model->setNumberStrong(10);
   4.374 +      }
   4.375 +
   4.376 +      _cbc_model->solver()->setIntParam(OsiMaxNumIterationHotStart, 100);
   4.377 +      _cbc_model->branchAndBound();
   4.378 +    }
   4.379 +
   4.380 +    if (_cbc_model->isAbandoned()) {
   4.381 +      return UNSOLVED;
   4.382 +    } else {
   4.383 +      return SOLVED;
   4.384 +    }
   4.385 +  }
   4.386 +
   4.387 +  CbcMip::Value CbcMip::_getSol(int i) const {
   4.388 +    return _cbc_model->getColSolution()[i];
   4.389 +  }
   4.390 +
   4.391 +  CbcMip::Value CbcMip::_getSolValue() const {
   4.392 +    return _cbc_model->getObjValue();
   4.393 +  }
   4.394 +
   4.395 +  CbcMip::ProblemType CbcMip::_getType() const {
   4.396 +    if (_cbc_model->isProvenOptimal()) {
   4.397 +      return OPTIMAL;
   4.398 +    } else if (_cbc_model->isContinuousUnbounded()) {
   4.399 +      return UNBOUNDED;
   4.400 +    }
   4.401 +    return FEASIBLE;
   4.402 +  }
   4.403 +
   4.404 +  void CbcMip::_setSense(Sense sense) {
   4.405 +    switch (sense) {
   4.406 +    case MIN:
   4.407 +      _prob->setOptimizationDirection(1.0);
   4.408 +      break;
   4.409 +    case MAX:
   4.410 +      _prob->setOptimizationDirection(- 1.0);
   4.411 +      break;
   4.412 +    }
   4.413 +  }
   4.414 +
   4.415 +  CbcMip::Sense CbcMip::_getSense() const {
   4.416 +    if (_prob->optimizationDirection() > 0.0) {
   4.417 +      return MIN;
   4.418 +    } else if (_prob->optimizationDirection() < 0.0) {
   4.419 +      return MAX;
   4.420 +    } else {
   4.421 +      LEMON_ASSERT(false, "Wrong sense");
   4.422 +      return CbcMip::Sense();
   4.423 +    }
   4.424 +  }
   4.425 +
   4.426 +  void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) {
   4.427 +    switch (col_type){
   4.428 +    case INTEGER:
   4.429 +      _prob->setInteger(i);
   4.430 +      break;
   4.431 +    case REAL:
   4.432 +      _prob->setContinuous(i);
   4.433 +      break;
   4.434 +    default:;
   4.435 +      LEMON_ASSERT(false, "Wrong sense");
   4.436 +    }
   4.437 +  }
   4.438 +
   4.439 +  CbcMip::ColTypes CbcMip::_getColType(int i) const {
   4.440 +    return _prob->getColumnIsInteger(i) ? INTEGER : REAL;
   4.441 +  }
   4.442 +
   4.443 +  void CbcMip::_clear() {
   4.444 +    delete _prob;
   4.445 +    if (_osi_solver) {
   4.446 +      delete _osi_solver;
   4.447 +      _osi_solver = 0;
   4.448 +    }
   4.449 +    if (_cbc_model) {
   4.450 +      delete _cbc_model;
   4.451 +      _cbc_model = 0;
   4.452 +    }
   4.453 +
   4.454 +    _prob = new CoinModel();
   4.455 +    rows.clear();
   4.456 +    cols.clear();
   4.457 +  }
   4.458 +
   4.459 +  void CbcMip::messageLevel(MessageLevel m) {
   4.460 +    _message_level = m;
   4.461 +  }
   4.462 +
   4.463 +} //END OF NAMESPACE LEMON
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/lemon/cbc.h	Wed Apr 01 22:58:58 2009 +0200
     5.3 @@ -0,0 +1,150 @@
     5.4 +/* -*- mode: C++; indent-tabs-mode: nil; -*-
     5.5 + *
     5.6 + * This file is a part of LEMON, a generic C++ optimization library.
     5.7 + *
     5.8 + * Copyright (C) 2003-2009
     5.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    5.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    5.11 + *
    5.12 + * Permission to use, modify and distribute this software is granted
    5.13 + * provided that this copyright notice appears in all copies. For
    5.14 + * precise terms see the accompanying LICENSE file.
    5.15 + *
    5.16 + * This software is provided "AS IS" with no warranty of any kind,
    5.17 + * express or implied, and with no claim as to its suitability for any
    5.18 + * purpose.
    5.19 + *
    5.20 + */
    5.21 +
    5.22 +// -*- C++ -*-
    5.23 +#ifndef LEMON_CBC_H
    5.24 +#define LEMON_CBC_H
    5.25 +
    5.26 +///\file
    5.27 +///\brief Header of the LEMON-CBC mip solver interface.
    5.28 +///\ingroup lp_group
    5.29 +
    5.30 +#include <lemon/lp_base.h>
    5.31 +
    5.32 +class CoinModel;
    5.33 +class OsiSolverInterface;
    5.34 +class CbcModel;
    5.35 +
    5.36 +namespace lemon {
    5.37 +
    5.38 +  /// \brief Interface for the CBC MIP solver
    5.39 +  ///
    5.40 +  /// This class implements an interface for the CBC MIP solver.
    5.41 +  ///\ingroup lp_group
    5.42 +  class CbcMip : public MipSolver {
    5.43 +  protected:
    5.44 +
    5.45 +    CoinModel *_prob;
    5.46 +    OsiSolverInterface *_osi_solver;
    5.47 +    CbcModel *_cbc_model;
    5.48 +
    5.49 +  public:
    5.50 +
    5.51 +    /// \e
    5.52 +    CbcMip();
    5.53 +    /// \e
    5.54 +    CbcMip(const CbcMip&);
    5.55 +    /// \e
    5.56 +    ~CbcMip();
    5.57 +    /// \e
    5.58 +    virtual CbcMip* newSolver() const;
    5.59 +    /// \e
    5.60 +    virtual CbcMip* cloneSolver() const;
    5.61 +
    5.62 +  protected:
    5.63 +
    5.64 +    virtual const char* _solverName() const;
    5.65 +
    5.66 +    virtual int _addCol();
    5.67 +    virtual int _addRow();
    5.68 +
    5.69 +    virtual void _eraseCol(int i);
    5.70 +    virtual void _eraseRow(int i);
    5.71 +
    5.72 +    virtual void _eraseColId(int i);
    5.73 +    virtual void _eraseRowId(int i);
    5.74 +
    5.75 +    virtual void _getColName(int col, std::string& name) const;
    5.76 +    virtual void _setColName(int col, const std::string& name);
    5.77 +    virtual int _colByName(const std::string& name) const;
    5.78 +
    5.79 +    virtual void _getRowName(int row, std::string& name) const;
    5.80 +    virtual void _setRowName(int row, const std::string& name);
    5.81 +    virtual int _rowByName(const std::string& name) const;
    5.82 +
    5.83 +    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
    5.84 +    virtual void _getRowCoeffs(int i, InsertIterator b) const;
    5.85 +
    5.86 +    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
    5.87 +    virtual void _getColCoeffs(int i, InsertIterator b) const;
    5.88 +
    5.89 +    virtual void _setCoeff(int row, int col, Value value);
    5.90 +    virtual Value _getCoeff(int row, int col) const;
    5.91 +
    5.92 +    virtual void _setColLowerBound(int i, Value value);
    5.93 +    virtual Value _getColLowerBound(int i) const;
    5.94 +    virtual void _setColUpperBound(int i, Value value);
    5.95 +    virtual Value _getColUpperBound(int i) const;
    5.96 +
    5.97 +    virtual void _setRowLowerBound(int i, Value value);
    5.98 +    virtual Value _getRowLowerBound(int i) const;
    5.99 +    virtual void _setRowUpperBound(int i, Value value);
   5.100 +    virtual Value _getRowUpperBound(int i) const;
   5.101 +
   5.102 +    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
   5.103 +    virtual void _getObjCoeffs(InsertIterator b) const;
   5.104 +
   5.105 +    virtual void _setObjCoeff(int i, Value obj_coef);
   5.106 +    virtual Value _getObjCoeff(int i) const;
   5.107 +
   5.108 +    virtual void _setSense(Sense sense);
   5.109 +    virtual Sense _getSense() const;
   5.110 +
   5.111 +    virtual ColTypes _getColType(int col) const;
   5.112 +    virtual void _setColType(int col, ColTypes col_type);
   5.113 +
   5.114 +    virtual SolveExitStatus _solve();
   5.115 +    virtual ProblemType _getType() const;
   5.116 +    virtual Value _getSol(int i) const;
   5.117 +    virtual Value _getSolValue() const;
   5.118 +
   5.119 +    virtual void _clear();
   5.120 +
   5.121 +  public:
   5.122 +
   5.123 +    ///Enum for \c messageLevel() parameter
   5.124 +    enum MessageLevel {
   5.125 +      /// no output (default value)
   5.126 +      MESSAGE_NO_OUTPUT = 0,
   5.127 +      /// error messages only
   5.128 +      MESSAGE_ERROR_MESSAGE = 1,
   5.129 +      /// normal output
   5.130 +      MESSAGE_NORMAL_OUTPUT = 2,
   5.131 +      /// full output (includes informational messages)
   5.132 +      MESSAGE_FULL_OUTPUT = 3
   5.133 +    };
   5.134 +
   5.135 +  private:
   5.136 +
   5.137 +    MessageLevel _message_level;
   5.138 +
   5.139 +  public:
   5.140 +
   5.141 +    ///Set the verbosity of the messages
   5.142 +
   5.143 +    ///Set the verbosity of the messages
   5.144 +    ///
   5.145 +    ///\param m is the level of the messages output by the solver routines.
   5.146 +    void messageLevel(MessageLevel m);
   5.147 +
   5.148 +
   5.149 +  };
   5.150 +
   5.151 +}
   5.152 +
   5.153 +#endif
     6.1 --- a/lemon/config.h.in	Thu Apr 02 19:29:56 2009 +0200
     6.2 +++ b/lemon/config.h.in	Wed Apr 01 22:58:58 2009 +0200
     6.3 @@ -18,3 +18,6 @@
     6.4  
     6.5  /* Define to 1 if you have CLP */
     6.6  #undef HAVE_CLP
     6.7 +
     6.8 +/* Define to 1 if you have CBC */
     6.9 +#undef HAVE_CBC
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/m4/lx_check_cbc.m4	Wed Apr 01 22:58:58 2009 +0200
     7.3 @@ -0,0 +1,73 @@
     7.4 +AC_DEFUN([LX_CHECK_CBC],
     7.5 +[
     7.6 +  AC_ARG_WITH([cbc],
     7.7 +AS_HELP_STRING([--with-cbc@<:@=PREFIX@:>@], [search for CBC under PREFIX or under the default search paths if PREFIX is not given @<:@default@:>@])
     7.8 +AS_HELP_STRING([--without-cbc], [disable checking for CBC]),
     7.9 +              [], [with_cbc=yes])
    7.10 +
    7.11 +  AC_ARG_WITH([cbc-includedir],
    7.12 +AS_HELP_STRING([--with-cbc-includedir=DIR], [search for CBC headers in DIR]),
    7.13 +              [], [with_cbc_includedir=no])
    7.14 +
    7.15 +  AC_ARG_WITH([cbc-libdir],
    7.16 +AS_HELP_STRING([--with-cbc-libdir=DIR], [search for CBC libraries in DIR]),
    7.17 +              [], [with_cbc_libdir=no])
    7.18 +
    7.19 +  lx_cbc_found=no
    7.20 +  if test x"$with_cbc" != x"no"; then
    7.21 +    AC_MSG_CHECKING([for CBC])
    7.22 +
    7.23 +    if test x"$with_cbc_includedir" != x"no"; then
    7.24 +      CBC_CXXFLAGS="-I$with_cbc_includedir"
    7.25 +    elif test x"$with_cbc" != x"yes"; then
    7.26 +      CBC_CXXFLAGS="-I$with_cbc/include"
    7.27 +    fi
    7.28 +
    7.29 +    if test x"$with_cbc_libdir" != x"no"; then
    7.30 +      CBC_LDFLAGS="-L$with_cbc_libdir"
    7.31 +    elif test x"$with_cbc" != x"yes"; then
    7.32 +      CBC_LDFLAGS="-L$with_cbc/lib"
    7.33 +    fi
    7.34 +    CBC_LIBS="-lOsi -lCbc -lOsiCbc -lCbcSolver -lClp -lOsiClp -lCoinUtils -lVol -lOsiVol -lCgl -lm -llapack -lblas"
    7.35 +
    7.36 +    lx_save_cxxflags="$CXXFLAGS"
    7.37 +    lx_save_ldflags="$LDFLAGS"
    7.38 +    lx_save_libs="$LIBS"
    7.39 +    CXXFLAGS="$CBC_CXXFLAGS"
    7.40 +    LDFLAGS="$CBC_LDFLAGS"
    7.41 +    LIBS="$CBC_LIBS"
    7.42 +
    7.43 +    lx_cbc_test_prog='
    7.44 +      #include <coin/CbcModel.hpp>
    7.45 +
    7.46 +      int main(int argc, char** argv)
    7.47 +      {
    7.48 +        CbcModel cbc;
    7.49 +        return 0;
    7.50 +      }'
    7.51 +
    7.52 +    AC_LANG_PUSH(C++)
    7.53 +    AC_LINK_IFELSE([$lx_cbc_test_prog], [lx_cbc_found=yes], [lx_cbc_found=no])
    7.54 +    AC_LANG_POP(C++)
    7.55 +
    7.56 +    CXXFLAGS="$lx_save_cxxflags"
    7.57 +    LDFLAGS="$lx_save_ldflags"
    7.58 +    LIBS="$lx_save_libs"
    7.59 +
    7.60 +    if test x"$lx_cbc_found" = x"yes"; then
    7.61 +      AC_DEFINE([HAVE_CBC], [1], [Define to 1 if you have CBC.])
    7.62 +      lx_lp_found=yes
    7.63 +      AC_DEFINE([HAVE_LP], [1], [Define to 1 if you have any LP solver.])
    7.64 +      AC_MSG_RESULT([yes])
    7.65 +    else
    7.66 +      CBC_CXXFLAGS=""
    7.67 +      CBC_LDFLAGS=""
    7.68 +      CBC_LIBS=""
    7.69 +      AC_MSG_RESULT([no])
    7.70 +    fi
    7.71 +  fi
    7.72 +  CBC_LIBS="$CBC_LDFLAGS $CBC_LIBS"
    7.73 +  AC_SUBST(CBC_CXXFLAGS)
    7.74 +  AC_SUBST(CBC_LIBS)
    7.75 +  AM_CONDITIONAL([HAVE_CBC], [test x"$lx_cbc_found" = x"yes"])
    7.76 +])
     8.1 --- a/test/mip_test.cc	Thu Apr 02 19:29:56 2009 +0200
     8.2 +++ b/test/mip_test.cc	Wed Apr 01 22:58:58 2009 +0200
     8.3 @@ -18,7 +18,6 @@
     8.4  
     8.5  #include "test_tools.h"
     8.6  
     8.7 -
     8.8  #ifdef HAVE_CONFIG_H
     8.9  #include <lemon/config.h>
    8.10  #endif
    8.11 @@ -31,6 +30,10 @@
    8.12  #include <lemon/glpk.h>
    8.13  #endif
    8.14  
    8.15 +#ifdef HAVE_CBC
    8.16 +#include <lemon/cbc.h>
    8.17 +#endif
    8.18 +
    8.19  
    8.20  using namespace lemon;
    8.21  
    8.22 @@ -57,14 +60,13 @@
    8.23  
    8.24  void aTest(MipSolver& mip)
    8.25  {
    8.26 - //The following example is very simple
    8.27 +  //The following example is very simple
    8.28  
    8.29  
    8.30    typedef MipSolver::Row Row;
    8.31    typedef MipSolver::Col Col;
    8.32  
    8.33  
    8.34 -
    8.35    Col x1 = mip.addCol();
    8.36    Col x2 = mip.addCol();
    8.37  
    8.38 @@ -74,23 +76,24 @@
    8.39  
    8.40    mip.max();
    8.41  
    8.42 -
    8.43    //Unconstrained optimization
    8.44    mip.solve();
    8.45    //Check it out!
    8.46  
    8.47    //Constraints
    8.48 -  mip.addRow(2*x1+x2 <=2);
    8.49 -  mip.addRow(x1-2*x2 <=0);
    8.50 +  mip.addRow(2 * x1 + x2 <= 2);
    8.51 +  Row y2 = mip.addRow(x1 - 2 * x2 <= 0);
    8.52  
    8.53    //Nonnegativity of the variable x1
    8.54    mip.colLowerBound(x1, 0);
    8.55  
    8.56 +
    8.57    //Maximization of x1
    8.58    //over the triangle with vertices (0,0),(4/5,2/5),(0,2)
    8.59    double expected_opt=4.0/5.0;
    8.60    solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
    8.61  
    8.62 +
    8.63    //Restrict x2 to integer
    8.64    mip.colType(x2,MipSolver::INTEGER);
    8.65    expected_opt=1.0/2.0;
    8.66 @@ -102,10 +105,15 @@
    8.67    expected_opt=0;
    8.68    solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
    8.69  
    8.70 -
    8.71 +  //Erase a variable
    8.72 +  mip.erase(x2);
    8.73 +  mip.rowUpperBound(y2, 8);
    8.74 +  expected_opt=1;
    8.75 +  solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
    8.76  
    8.77  }
    8.78  
    8.79 +
    8.80  template<class MIP>
    8.81  void cloneTest()
    8.82  {
    8.83 @@ -144,6 +152,14 @@
    8.84    }
    8.85  #endif
    8.86  
    8.87 +#ifdef HAVE_CBC
    8.88 +  {
    8.89 +    CbcMip mip1;
    8.90 +    aTest(mip1);
    8.91 +    cloneTest<CbcMip>();
    8.92 +  }
    8.93 +#endif
    8.94 +
    8.95    return 0;
    8.96  
    8.97  }