deba@559: /* -*- mode: C++; indent-tabs-mode: nil; -*- deba@559: * deba@559: * This file is a part of LEMON, a generic C++ optimization library. deba@559: * deba@559: * Copyright (C) 2003-2009 deba@559: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@559: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@559: * deba@559: * Permission to use, modify and distribute this software is granted deba@559: * provided that this copyright notice appears in all copies. For deba@559: * precise terms see the accompanying LICENSE file. deba@559: * deba@559: * This software is provided "AS IS" with no warranty of any kind, deba@559: * express or implied, and with no claim as to its suitability for any deba@559: * purpose. deba@559: * deba@559: */ deba@559: deba@559: ///\file deba@559: ///\brief Implementation of the CBC MIP solver interface. deba@559: deba@559: #include "cbc.h" deba@559: deba@559: #include deba@559: #include deba@559: #include deba@559: deba@559: #ifdef COIN_HAS_CLP deba@559: #include "coin/OsiClpSolverInterface.hpp" deba@559: #endif deba@559: #ifdef COIN_HAS_OSL deba@559: #include "coin/OsiOslSolverInterface.hpp" deba@559: #endif deba@559: deba@559: #include "coin/CbcCutGenerator.hpp" deba@559: #include "coin/CbcHeuristicLocal.hpp" deba@559: #include "coin/CbcHeuristicGreedy.hpp" deba@559: #include "coin/CbcHeuristicFPump.hpp" deba@559: #include "coin/CbcHeuristicRINS.hpp" deba@559: deba@559: #include "coin/CglGomory.hpp" deba@559: #include "coin/CglProbing.hpp" deba@559: #include "coin/CglKnapsackCover.hpp" deba@559: #include "coin/CglOddHole.hpp" deba@559: #include "coin/CglClique.hpp" deba@559: #include "coin/CglFlowCover.hpp" deba@559: #include "coin/CglMixedIntegerRounding.hpp" deba@559: deba@559: #include "coin/CbcHeuristic.hpp" deba@559: deba@559: namespace lemon { deba@559: deba@559: CbcMip::CbcMip() { deba@559: _prob = new CoinModel(); deba@559: _prob->setProblemName("LEMON"); deba@559: _osi_solver = 0; deba@559: _cbc_model = 0; deba@568: messageLevel(MESSAGE_NOTHING); deba@559: } deba@559: deba@559: CbcMip::CbcMip(const CbcMip& other) { deba@559: _prob = new CoinModel(*other._prob); deba@568: _prob->setProblemName("LEMON"); deba@559: _osi_solver = 0; deba@559: _cbc_model = 0; deba@568: messageLevel(MESSAGE_NOTHING); deba@559: } deba@559: deba@559: CbcMip::~CbcMip() { deba@559: delete _prob; deba@559: if (_osi_solver) delete _osi_solver; deba@559: if (_cbc_model) delete _cbc_model; deba@559: } deba@559: deba@559: const char* CbcMip::_solverName() const { return "CbcMip"; } deba@559: deba@559: int CbcMip::_addCol() { deba@559: _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false); deba@559: return _prob->numberColumns() - 1; deba@559: } deba@559: deba@559: CbcMip* CbcMip::newSolver() const { deba@559: CbcMip* newlp = new CbcMip; deba@559: return newlp; deba@559: } deba@559: deba@559: CbcMip* CbcMip::cloneSolver() const { deba@559: CbcMip* copylp = new CbcMip(*this); deba@559: return copylp; deba@559: } deba@559: deba@559: int CbcMip::_addRow() { deba@559: _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX); deba@559: return _prob->numberRows() - 1; deba@559: } deba@559: deba@559: deba@559: void CbcMip::_eraseCol(int i) { deba@559: _prob->deleteColumn(i); deba@559: } deba@559: deba@559: void CbcMip::_eraseRow(int i) { deba@559: _prob->deleteRow(i); deba@559: } deba@559: deba@559: void CbcMip::_eraseColId(int i) { deba@559: cols.eraseIndex(i); deba@559: } deba@559: deba@559: void CbcMip::_eraseRowId(int i) { deba@559: rows.eraseIndex(i); deba@559: } deba@559: deba@559: void CbcMip::_getColName(int c, std::string& name) const { deba@559: name = _prob->getColumnName(c); deba@559: } deba@559: deba@559: void CbcMip::_setColName(int c, const std::string& name) { deba@559: _prob->setColumnName(c, name.c_str()); deba@559: } deba@559: deba@559: int CbcMip::_colByName(const std::string& name) const { deba@559: return _prob->column(name.c_str()); deba@559: } deba@559: deba@559: void CbcMip::_getRowName(int r, std::string& name) const { deba@559: name = _prob->getRowName(r); deba@559: } deba@559: deba@559: void CbcMip::_setRowName(int r, const std::string& name) { deba@559: _prob->setRowName(r, name.c_str()); deba@559: } deba@559: deba@559: int CbcMip::_rowByName(const std::string& name) const { deba@559: return _prob->row(name.c_str()); deba@559: } deba@559: deba@559: void CbcMip::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { deba@559: for (ExprIterator it = b; it != e; ++it) { deba@559: _prob->setElement(i, it->first, it->second); deba@559: } deba@559: } deba@559: deba@559: void CbcMip::_getRowCoeffs(int ix, InsertIterator b) const { deba@559: int length = _prob->numberRows(); deba@559: deba@559: std::vector indices(length); deba@559: std::vector values(length); deba@559: deba@559: length = _prob->getRow(ix, &indices[0], &values[0]); deba@559: deba@559: for (int i = 0; i < length; ++i) { deba@559: *b = std::make_pair(indices[i], values[i]); deba@559: ++b; deba@559: } deba@559: } deba@559: deba@559: void CbcMip::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) { deba@559: for (ExprIterator it = b; it != e; ++it) { deba@559: _prob->setElement(it->first, ix, it->second); deba@559: } deba@559: } deba@559: deba@559: void CbcMip::_getColCoeffs(int ix, InsertIterator b) const { deba@559: int length = _prob->numberColumns(); deba@559: deba@559: std::vector indices(length); deba@559: std::vector values(length); deba@559: deba@559: length = _prob->getColumn(ix, &indices[0], &values[0]); deba@559: deba@559: for (int i = 0; i < length; ++i) { deba@559: *b = std::make_pair(indices[i], values[i]); deba@559: ++b; deba@559: } deba@559: } deba@559: deba@559: void CbcMip::_setCoeff(int ix, int jx, Value value) { deba@559: _prob->setElement(ix, jx, value); deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getCoeff(int ix, int jx) const { deba@559: return _prob->getElement(ix, jx); deba@559: } deba@559: deba@559: deba@559: void CbcMip::_setColLowerBound(int i, Value lo) { deba@559: LEMON_ASSERT(lo != INF, "Invalid bound"); deba@559: _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo); deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getColLowerBound(int i) const { deba@559: double val = _prob->getColumnLower(i); deba@559: return val == - COIN_DBL_MAX ? - INF : val; deba@559: } deba@559: deba@559: void CbcMip::_setColUpperBound(int i, Value up) { deba@559: LEMON_ASSERT(up != -INF, "Invalid bound"); deba@559: _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up); deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getColUpperBound(int i) const { deba@559: double val = _prob->getColumnUpper(i); deba@559: return val == COIN_DBL_MAX ? INF : val; deba@559: } deba@559: deba@559: void CbcMip::_setRowLowerBound(int i, Value lo) { deba@559: LEMON_ASSERT(lo != INF, "Invalid bound"); deba@559: _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo); deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getRowLowerBound(int i) const { deba@559: double val = _prob->getRowLower(i); deba@559: return val == - COIN_DBL_MAX ? - INF : val; deba@559: } deba@559: deba@559: void CbcMip::_setRowUpperBound(int i, Value up) { deba@559: LEMON_ASSERT(up != -INF, "Invalid bound"); deba@559: _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up); deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getRowUpperBound(int i) const { deba@559: double val = _prob->getRowUpper(i); deba@559: return val == COIN_DBL_MAX ? INF : val; deba@559: } deba@559: deba@559: void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) { deba@559: int num = _prob->numberColumns(); deba@559: for (int i = 0; i < num; ++i) { deba@559: _prob->setColumnObjective(i, 0.0); deba@559: } deba@559: for (ExprIterator it = b; it != e; ++it) { deba@559: _prob->setColumnObjective(it->first, it->second); deba@559: } deba@559: } deba@559: deba@559: void CbcMip::_getObjCoeffs(InsertIterator b) const { deba@559: int num = _prob->numberColumns(); deba@559: for (int i = 0; i < num; ++i) { deba@559: Value coef = _prob->getColumnObjective(i); deba@559: if (coef != 0.0) { deba@559: *b = std::make_pair(i, coef); deba@559: ++b; deba@559: } deba@559: } deba@559: } deba@559: deba@559: void CbcMip::_setObjCoeff(int i, Value obj_coef) { deba@559: _prob->setColumnObjective(i, obj_coef); deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getObjCoeff(int i) const { deba@559: return _prob->getColumnObjective(i); deba@559: } deba@559: deba@559: CbcMip::SolveExitStatus CbcMip::_solve() { deba@559: deba@559: if (_osi_solver) { deba@559: delete _osi_solver; deba@559: } deba@559: #ifdef COIN_HAS_CLP deba@559: _osi_solver = new OsiClpSolverInterface(); deba@559: #elif COIN_HAS_OSL deba@559: _osi_solver = new OsiOslSolverInterface(); deba@559: #else deba@559: #error Cannot instantiate Osi solver deba@559: #endif deba@559: deba@559: _osi_solver->loadFromCoinModel(*_prob); deba@559: deba@559: if (_cbc_model) { deba@559: delete _cbc_model; deba@559: } deba@559: _cbc_model= new CbcModel(*_osi_solver); deba@559: deba@568: _osi_solver->messageHandler()->setLogLevel(_message_level); deba@568: _cbc_model->setLogLevel(_message_level); deba@559: deba@559: _cbc_model->initialSolve(); deba@559: _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry); deba@559: deba@559: if (!_cbc_model->isInitialSolveAbandoned() && deba@559: _cbc_model->isInitialSolveProvenOptimal() && deba@559: !_cbc_model->isInitialSolveProvenPrimalInfeasible() && deba@559: !_cbc_model->isInitialSolveProvenDualInfeasible()) { deba@559: deba@559: CglProbing generator1; deba@559: generator1.setUsingObjective(true); deba@559: generator1.setMaxPass(3); deba@559: generator1.setMaxProbe(100); deba@559: generator1.setMaxLook(50); deba@559: generator1.setRowCuts(3); deba@559: _cbc_model->addCutGenerator(&generator1, -1, "Probing"); deba@559: deba@559: CglGomory generator2; deba@559: generator2.setLimit(300); deba@559: _cbc_model->addCutGenerator(&generator2, -1, "Gomory"); deba@559: deba@559: CglKnapsackCover generator3; deba@559: _cbc_model->addCutGenerator(&generator3, -1, "Knapsack"); deba@559: deba@559: CglOddHole generator4; deba@559: generator4.setMinimumViolation(0.005); deba@559: generator4.setMinimumViolationPer(0.00002); deba@559: generator4.setMaximumEntries(200); deba@559: _cbc_model->addCutGenerator(&generator4, -1, "OddHole"); deba@559: deba@559: CglClique generator5; deba@559: generator5.setStarCliqueReport(false); deba@559: generator5.setRowCliqueReport(false); deba@559: _cbc_model->addCutGenerator(&generator5, -1, "Clique"); deba@559: deba@559: CglMixedIntegerRounding mixedGen; deba@559: _cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding"); deba@559: deba@559: CglFlowCover flowGen; deba@559: _cbc_model->addCutGenerator(&flowGen, -1, "FlowCover"); deba@559: deba@559: #ifdef COIN_HAS_CLP deba@559: OsiClpSolverInterface* osiclp = deba@559: dynamic_cast(_cbc_model->solver()); deba@559: if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) { deba@559: osiclp->setupForRepeatedUse(2, 0); deba@559: } deba@559: #endif deba@559: deba@559: CbcRounding heuristic1(*_cbc_model); deba@559: heuristic1.setWhen(3); deba@559: _cbc_model->addHeuristic(&heuristic1); deba@559: deba@559: CbcHeuristicLocal heuristic2(*_cbc_model); deba@559: heuristic2.setWhen(3); deba@559: _cbc_model->addHeuristic(&heuristic2); deba@559: deba@559: CbcHeuristicGreedyCover heuristic3(*_cbc_model); deba@559: heuristic3.setAlgorithm(11); deba@559: heuristic3.setWhen(3); deba@559: _cbc_model->addHeuristic(&heuristic3); deba@559: deba@559: CbcHeuristicFPump heuristic4(*_cbc_model); deba@559: heuristic4.setWhen(3); deba@559: _cbc_model->addHeuristic(&heuristic4); deba@559: deba@559: CbcHeuristicRINS heuristic5(*_cbc_model); deba@559: heuristic5.setWhen(3); deba@559: _cbc_model->addHeuristic(&heuristic5); deba@559: deba@559: if (_cbc_model->getNumCols() < 500) { deba@559: _cbc_model->setMaximumCutPassesAtRoot(-100); deba@559: } else if (_cbc_model->getNumCols() < 5000) { deba@559: _cbc_model->setMaximumCutPassesAtRoot(100); deba@559: } else { deba@559: _cbc_model->setMaximumCutPassesAtRoot(20); deba@559: } deba@559: deba@559: if (_cbc_model->getNumCols() < 5000) { deba@559: _cbc_model->setNumberStrong(10); deba@559: } deba@559: deba@559: _cbc_model->solver()->setIntParam(OsiMaxNumIterationHotStart, 100); deba@559: _cbc_model->branchAndBound(); deba@559: } deba@559: deba@559: if (_cbc_model->isAbandoned()) { deba@559: return UNSOLVED; deba@559: } else { deba@559: return SOLVED; deba@559: } deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getSol(int i) const { deba@559: return _cbc_model->getColSolution()[i]; deba@559: } deba@559: deba@559: CbcMip::Value CbcMip::_getSolValue() const { deba@559: return _cbc_model->getObjValue(); deba@559: } deba@559: deba@559: CbcMip::ProblemType CbcMip::_getType() const { deba@559: if (_cbc_model->isProvenOptimal()) { deba@559: return OPTIMAL; deba@559: } else if (_cbc_model->isContinuousUnbounded()) { deba@559: return UNBOUNDED; deba@559: } deba@559: return FEASIBLE; deba@559: } deba@559: deba@559: void CbcMip::_setSense(Sense sense) { deba@559: switch (sense) { deba@559: case MIN: deba@559: _prob->setOptimizationDirection(1.0); deba@559: break; deba@559: case MAX: deba@559: _prob->setOptimizationDirection(- 1.0); deba@559: break; deba@559: } deba@559: } deba@559: deba@559: CbcMip::Sense CbcMip::_getSense() const { deba@559: if (_prob->optimizationDirection() > 0.0) { deba@559: return MIN; deba@559: } else if (_prob->optimizationDirection() < 0.0) { deba@559: return MAX; deba@559: } else { deba@559: LEMON_ASSERT(false, "Wrong sense"); deba@559: return CbcMip::Sense(); deba@559: } deba@559: } deba@559: deba@559: void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) { deba@559: switch (col_type){ deba@559: case INTEGER: deba@559: _prob->setInteger(i); deba@559: break; deba@559: case REAL: deba@559: _prob->setContinuous(i); deba@559: break; deba@559: default:; deba@559: LEMON_ASSERT(false, "Wrong sense"); deba@559: } deba@559: } deba@559: deba@559: CbcMip::ColTypes CbcMip::_getColType(int i) const { deba@559: return _prob->getColumnIsInteger(i) ? INTEGER : REAL; deba@559: } deba@559: deba@559: void CbcMip::_clear() { deba@559: delete _prob; deba@559: if (_osi_solver) { deba@559: delete _osi_solver; deba@559: _osi_solver = 0; deba@559: } deba@559: if (_cbc_model) { deba@559: delete _cbc_model; deba@559: _cbc_model = 0; deba@559: } deba@559: deba@559: _prob = new CoinModel(); deba@559: rows.clear(); deba@559: cols.clear(); deba@559: } deba@559: deba@568: void CbcMip::_messageLevel(MessageLevel level) { deba@568: switch (level) { deba@568: case MESSAGE_NOTHING: deba@568: _message_level = 0; deba@568: break; deba@568: case MESSAGE_ERROR: deba@568: _message_level = 1; deba@568: break; deba@568: case MESSAGE_WARNING: deba@568: _message_level = 1; deba@568: break; deba@568: case MESSAGE_NORMAL: deba@568: _message_level = 2; deba@568: break; deba@568: case MESSAGE_VERBOSE: deba@568: _message_level = 3; deba@568: break; deba@568: } deba@559: } deba@559: deba@559: } //END OF NAMESPACE LEMON