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