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