lemon/cbc.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 894 bb70ad62c95f
parent 567 3314f58e7b25
child 746 e4554cd6b2bf
child 951 ee581a0ecfbf
permissions -rw-r--r--
Fix critical bug in preflow (#372)

The wrong transition between the bound decrease and highest active
heuristics caused the bug. The last node chosen in bound decrease mode
is used in the first iteration in highest active mode.
deba@567
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@567
     2
 *
deba@567
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@567
     4
 *
deba@567
     5
 * Copyright (C) 2003-2009
deba@567
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@567
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@567
     8
 *
deba@567
     9
 * Permission to use, modify and distribute this software is granted
deba@567
    10
 * provided that this copyright notice appears in all copies. For
deba@567
    11
 * precise terms see the accompanying LICENSE file.
deba@567
    12
 *
deba@567
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@567
    14
 * express or implied, and with no claim as to its suitability for any
deba@567
    15
 * purpose.
deba@567
    16
 *
deba@567
    17
 */
deba@567
    18
deba@567
    19
///\file
deba@567
    20
///\brief Implementation of the CBC MIP solver interface.
deba@567
    21
deba@567
    22
#include "cbc.h"
deba@567
    23
deba@567
    24
#include <coin/CoinModel.hpp>
deba@567
    25
#include <coin/CbcModel.hpp>
deba@567
    26
#include <coin/OsiSolverInterface.hpp>
deba@567
    27
deba@567
    28
#ifdef COIN_HAS_CLP
deba@567
    29
#include "coin/OsiClpSolverInterface.hpp"
deba@567
    30
#endif
deba@567
    31
#ifdef COIN_HAS_OSL
deba@567
    32
#include "coin/OsiOslSolverInterface.hpp"
deba@567
    33
#endif
deba@567
    34
deba@567
    35
#include "coin/CbcCutGenerator.hpp"
deba@567
    36
#include "coin/CbcHeuristicLocal.hpp"
deba@567
    37
#include "coin/CbcHeuristicGreedy.hpp"
deba@567
    38
#include "coin/CbcHeuristicFPump.hpp"
deba@567
    39
#include "coin/CbcHeuristicRINS.hpp"
deba@567
    40
deba@567
    41
#include "coin/CglGomory.hpp"
deba@567
    42
#include "coin/CglProbing.hpp"
deba@567
    43
#include "coin/CglKnapsackCover.hpp"
deba@567
    44
#include "coin/CglOddHole.hpp"
deba@567
    45
#include "coin/CglClique.hpp"
deba@567
    46
#include "coin/CglFlowCover.hpp"
deba@567
    47
#include "coin/CglMixedIntegerRounding.hpp"
deba@567
    48
deba@567
    49
#include "coin/CbcHeuristic.hpp"
deba@567
    50
deba@567
    51
namespace lemon {
deba@567
    52
deba@567
    53
  CbcMip::CbcMip() {
deba@567
    54
    _prob = new CoinModel();
deba@567
    55
    _prob->setProblemName("LEMON");
deba@567
    56
    _osi_solver = 0;
deba@567
    57
    _cbc_model = 0;
deba@576
    58
    messageLevel(MESSAGE_NOTHING);
deba@567
    59
  }
deba@567
    60
deba@567
    61
  CbcMip::CbcMip(const CbcMip& other) {
deba@567
    62
    _prob = new CoinModel(*other._prob);
deba@576
    63
    _prob->setProblemName("LEMON");
deba@567
    64
    _osi_solver = 0;
deba@567
    65
    _cbc_model = 0;
deba@576
    66
    messageLevel(MESSAGE_NOTHING);
deba@567
    67
  }
deba@567
    68
deba@567
    69
  CbcMip::~CbcMip() {
deba@567
    70
    delete _prob;
deba@567
    71
    if (_osi_solver) delete _osi_solver;
deba@567
    72
    if (_cbc_model) delete _cbc_model;
deba@567
    73
  }
deba@567
    74
deba@567
    75
  const char* CbcMip::_solverName() const { return "CbcMip"; }
deba@567
    76
deba@567
    77
  int CbcMip::_addCol() {
deba@567
    78
    _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false);
deba@567
    79
    return _prob->numberColumns() - 1;
deba@567
    80
  }
deba@567
    81
deba@567
    82
  CbcMip* CbcMip::newSolver() const {
deba@567
    83
    CbcMip* newlp = new CbcMip;
deba@567
    84
    return newlp;
deba@567
    85
  }
deba@567
    86
deba@567
    87
  CbcMip* CbcMip::cloneSolver() const {
deba@567
    88
    CbcMip* copylp = new CbcMip(*this);
deba@567
    89
    return copylp;
deba@567
    90
  }
deba@567
    91
deba@567
    92
  int CbcMip::_addRow() {
deba@567
    93
    _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
deba@567
    94
    return _prob->numberRows() - 1;
deba@567
    95
  }
deba@567
    96
deba@567
    97
deba@567
    98
  void CbcMip::_eraseCol(int i) {
deba@567
    99
    _prob->deleteColumn(i);
deba@567
   100
  }
deba@567
   101
deba@567
   102
  void CbcMip::_eraseRow(int i) {
deba@567
   103
    _prob->deleteRow(i);
deba@567
   104
  }
deba@567
   105
deba@567
   106
  void CbcMip::_eraseColId(int i) {
deba@567
   107
    cols.eraseIndex(i);
deba@567
   108
  }
deba@567
   109
deba@567
   110
  void CbcMip::_eraseRowId(int i) {
deba@567
   111
    rows.eraseIndex(i);
deba@567
   112
  }
deba@567
   113
deba@567
   114
  void CbcMip::_getColName(int c, std::string& name) const {
deba@567
   115
    name = _prob->getColumnName(c);
deba@567
   116
  }
deba@567
   117
deba@567
   118
  void CbcMip::_setColName(int c, const std::string& name) {
deba@567
   119
    _prob->setColumnName(c, name.c_str());
deba@567
   120
  }
deba@567
   121
deba@567
   122
  int CbcMip::_colByName(const std::string& name) const {
deba@567
   123
    return _prob->column(name.c_str());
deba@567
   124
  }
deba@567
   125
deba@567
   126
  void CbcMip::_getRowName(int r, std::string& name) const {
deba@567
   127
    name = _prob->getRowName(r);
deba@567
   128
  }
deba@567
   129
deba@567
   130
  void CbcMip::_setRowName(int r, const std::string& name) {
deba@567
   131
    _prob->setRowName(r, name.c_str());
deba@567
   132
  }
deba@567
   133
deba@567
   134
  int CbcMip::_rowByName(const std::string& name) const {
deba@567
   135
    return _prob->row(name.c_str());
deba@567
   136
  }
deba@567
   137
deba@567
   138
  void CbcMip::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
deba@567
   139
    for (ExprIterator it = b; it != e; ++it) {
deba@567
   140
      _prob->setElement(i, it->first, it->second);
deba@567
   141
    }
deba@567
   142
  }
deba@567
   143
deba@567
   144
  void CbcMip::_getRowCoeffs(int ix, InsertIterator b) const {
deba@567
   145
    int length = _prob->numberRows();
deba@567
   146
deba@567
   147
    std::vector<int> indices(length);
deba@567
   148
    std::vector<Value> values(length);
deba@567
   149
deba@567
   150
    length = _prob->getRow(ix, &indices[0], &values[0]);
deba@567
   151
deba@567
   152
    for (int i = 0; i < length; ++i) {
deba@567
   153
      *b = std::make_pair(indices[i], values[i]);
deba@567
   154
      ++b;
deba@567
   155
    }
deba@567
   156
  }
deba@567
   157
deba@567
   158
  void CbcMip::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
deba@567
   159
    for (ExprIterator it = b; it != e; ++it) {
deba@567
   160
      _prob->setElement(it->first, ix, it->second);
deba@567
   161
    }
deba@567
   162
  }
deba@567
   163
deba@567
   164
  void CbcMip::_getColCoeffs(int ix, InsertIterator b) const {
deba@567
   165
    int length = _prob->numberColumns();
deba@567
   166
deba@567
   167
    std::vector<int> indices(length);
deba@567
   168
    std::vector<Value> values(length);
deba@567
   169
deba@567
   170
    length = _prob->getColumn(ix, &indices[0], &values[0]);
deba@567
   171
deba@567
   172
    for (int i = 0; i < length; ++i) {
deba@567
   173
      *b = std::make_pair(indices[i], values[i]);
deba@567
   174
      ++b;
deba@567
   175
    }
deba@567
   176
  }
deba@567
   177
deba@567
   178
  void CbcMip::_setCoeff(int ix, int jx, Value value) {
deba@567
   179
    _prob->setElement(ix, jx, value);
deba@567
   180
  }
deba@567
   181
deba@567
   182
  CbcMip::Value CbcMip::_getCoeff(int ix, int jx) const {
deba@567
   183
    return _prob->getElement(ix, jx);
deba@567
   184
  }
deba@567
   185
deba@567
   186
deba@567
   187
  void CbcMip::_setColLowerBound(int i, Value lo) {
deba@567
   188
    LEMON_ASSERT(lo != INF, "Invalid bound");
deba@567
   189
    _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
deba@567
   190
  }
deba@567
   191
deba@567
   192
  CbcMip::Value CbcMip::_getColLowerBound(int i) const {
deba@567
   193
    double val = _prob->getColumnLower(i);
deba@567
   194
    return val == - COIN_DBL_MAX ? - INF : val;
deba@567
   195
  }
deba@567
   196
deba@567
   197
  void CbcMip::_setColUpperBound(int i, Value up) {
deba@567
   198
    LEMON_ASSERT(up != -INF, "Invalid bound");
deba@567
   199
    _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
deba@567
   200
  }
deba@567
   201
deba@567
   202
  CbcMip::Value CbcMip::_getColUpperBound(int i) const {
deba@567
   203
    double val = _prob->getColumnUpper(i);
deba@567
   204
    return val == COIN_DBL_MAX ? INF : val;
deba@567
   205
  }
deba@567
   206
deba@567
   207
  void CbcMip::_setRowLowerBound(int i, Value lo) {
deba@567
   208
    LEMON_ASSERT(lo != INF, "Invalid bound");
deba@567
   209
    _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
deba@567
   210
  }
deba@567
   211
deba@567
   212
  CbcMip::Value CbcMip::_getRowLowerBound(int i) const {
deba@567
   213
    double val = _prob->getRowLower(i);
deba@567
   214
    return val == - COIN_DBL_MAX ? - INF : val;
deba@567
   215
  }
deba@567
   216
deba@567
   217
  void CbcMip::_setRowUpperBound(int i, Value up) {
deba@567
   218
    LEMON_ASSERT(up != -INF, "Invalid bound");
deba@567
   219
    _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
deba@567
   220
  }
deba@567
   221
deba@567
   222
  CbcMip::Value CbcMip::_getRowUpperBound(int i) const {
deba@567
   223
    double val = _prob->getRowUpper(i);
deba@567
   224
    return val == COIN_DBL_MAX ? INF : val;
deba@567
   225
  }
deba@567
   226
deba@567
   227
  void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) {
deba@567
   228
    int num = _prob->numberColumns();
deba@567
   229
    for (int i = 0; i < num; ++i) {
deba@567
   230
      _prob->setColumnObjective(i, 0.0);
deba@567
   231
    }
deba@567
   232
    for (ExprIterator it = b; it != e; ++it) {
deba@567
   233
      _prob->setColumnObjective(it->first, it->second);
deba@567
   234
    }
deba@567
   235
  }
deba@567
   236
deba@567
   237
  void CbcMip::_getObjCoeffs(InsertIterator b) const {
deba@567
   238
    int num = _prob->numberColumns();
deba@567
   239
    for (int i = 0; i < num; ++i) {
deba@567
   240
      Value coef = _prob->getColumnObjective(i);
deba@567
   241
      if (coef != 0.0) {
deba@567
   242
        *b = std::make_pair(i, coef);
deba@567
   243
        ++b;
deba@567
   244
      }
deba@567
   245
    }
deba@567
   246
  }
deba@567
   247
deba@567
   248
  void CbcMip::_setObjCoeff(int i, Value obj_coef) {
deba@567
   249
    _prob->setColumnObjective(i, obj_coef);
deba@567
   250
  }
deba@567
   251
deba@567
   252
  CbcMip::Value CbcMip::_getObjCoeff(int i) const {
deba@567
   253
    return _prob->getColumnObjective(i);
deba@567
   254
  }
deba@567
   255
deba@567
   256
  CbcMip::SolveExitStatus CbcMip::_solve() {
deba@567
   257
deba@567
   258
    if (_osi_solver) {
deba@567
   259
      delete _osi_solver;
deba@567
   260
    }
deba@567
   261
#ifdef COIN_HAS_CLP
deba@567
   262
    _osi_solver = new OsiClpSolverInterface();
deba@567
   263
#elif COIN_HAS_OSL
deba@567
   264
    _osi_solver = new OsiOslSolverInterface();
deba@567
   265
#else
deba@567
   266
#error Cannot instantiate Osi solver
deba@567
   267
#endif
deba@567
   268
deba@567
   269
    _osi_solver->loadFromCoinModel(*_prob);
deba@567
   270
deba@567
   271
    if (_cbc_model) {
deba@567
   272
      delete _cbc_model;
deba@567
   273
    }
deba@567
   274
    _cbc_model= new CbcModel(*_osi_solver);
deba@567
   275
deba@576
   276
    _osi_solver->messageHandler()->setLogLevel(_message_level);
deba@576
   277
    _cbc_model->setLogLevel(_message_level);
deba@567
   278
deba@567
   279
    _cbc_model->initialSolve();
deba@567
   280
    _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
deba@567
   281
deba@567
   282
    if (!_cbc_model->isInitialSolveAbandoned() &&
deba@567
   283
        _cbc_model->isInitialSolveProvenOptimal() &&
deba@567
   284
        !_cbc_model->isInitialSolveProvenPrimalInfeasible() &&
deba@567
   285
        !_cbc_model->isInitialSolveProvenDualInfeasible()) {
deba@567
   286
deba@567
   287
      CglProbing generator1;
deba@567
   288
      generator1.setUsingObjective(true);
deba@567
   289
      generator1.setMaxPass(3);
deba@567
   290
      generator1.setMaxProbe(100);
deba@567
   291
      generator1.setMaxLook(50);
deba@567
   292
      generator1.setRowCuts(3);
deba@567
   293
      _cbc_model->addCutGenerator(&generator1, -1, "Probing");
deba@567
   294
deba@567
   295
      CglGomory generator2;
deba@567
   296
      generator2.setLimit(300);
deba@567
   297
      _cbc_model->addCutGenerator(&generator2, -1, "Gomory");
deba@567
   298
deba@567
   299
      CglKnapsackCover generator3;
deba@567
   300
      _cbc_model->addCutGenerator(&generator3, -1, "Knapsack");
deba@567
   301
deba@567
   302
      CglOddHole generator4;
deba@567
   303
      generator4.setMinimumViolation(0.005);
deba@567
   304
      generator4.setMinimumViolationPer(0.00002);
deba@567
   305
      generator4.setMaximumEntries(200);
deba@567
   306
      _cbc_model->addCutGenerator(&generator4, -1, "OddHole");
deba@567
   307
deba@567
   308
      CglClique generator5;
deba@567
   309
      generator5.setStarCliqueReport(false);
deba@567
   310
      generator5.setRowCliqueReport(false);
deba@567
   311
      _cbc_model->addCutGenerator(&generator5, -1, "Clique");
deba@567
   312
deba@567
   313
      CglMixedIntegerRounding mixedGen;
deba@567
   314
      _cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding");
deba@567
   315
deba@567
   316
      CglFlowCover flowGen;
deba@567
   317
      _cbc_model->addCutGenerator(&flowGen, -1, "FlowCover");
deba@567
   318
deba@567
   319
#ifdef COIN_HAS_CLP
deba@567
   320
      OsiClpSolverInterface* osiclp =
deba@567
   321
        dynamic_cast<OsiClpSolverInterface*>(_cbc_model->solver());
deba@567
   322
      if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) {
deba@567
   323
        osiclp->setupForRepeatedUse(2, 0);
deba@567
   324
      }
deba@567
   325
#endif
deba@567
   326
deba@567
   327
      CbcRounding heuristic1(*_cbc_model);
deba@567
   328
      heuristic1.setWhen(3);
deba@567
   329
      _cbc_model->addHeuristic(&heuristic1);
deba@567
   330
deba@567
   331
      CbcHeuristicLocal heuristic2(*_cbc_model);
deba@567
   332
      heuristic2.setWhen(3);
deba@567
   333
      _cbc_model->addHeuristic(&heuristic2);
deba@567
   334
deba@567
   335
      CbcHeuristicGreedyCover heuristic3(*_cbc_model);
deba@567
   336
      heuristic3.setAlgorithm(11);
deba@567
   337
      heuristic3.setWhen(3);
deba@567
   338
      _cbc_model->addHeuristic(&heuristic3);
deba@567
   339
deba@567
   340
      CbcHeuristicFPump heuristic4(*_cbc_model);
deba@567
   341
      heuristic4.setWhen(3);
deba@567
   342
      _cbc_model->addHeuristic(&heuristic4);
deba@567
   343
deba@567
   344
      CbcHeuristicRINS heuristic5(*_cbc_model);
deba@567
   345
      heuristic5.setWhen(3);
deba@567
   346
      _cbc_model->addHeuristic(&heuristic5);
deba@567
   347
deba@567
   348
      if (_cbc_model->getNumCols() < 500) {
deba@567
   349
        _cbc_model->setMaximumCutPassesAtRoot(-100);
deba@567
   350
      } else if (_cbc_model->getNumCols() < 5000) {
deba@567
   351
        _cbc_model->setMaximumCutPassesAtRoot(100);
deba@567
   352
      } else {
deba@567
   353
        _cbc_model->setMaximumCutPassesAtRoot(20);
deba@567
   354
      }
deba@567
   355
deba@567
   356
      if (_cbc_model->getNumCols() < 5000) {
deba@567
   357
        _cbc_model->setNumberStrong(10);
deba@567
   358
      }
deba@567
   359
deba@567
   360
      _cbc_model->solver()->setIntParam(OsiMaxNumIterationHotStart, 100);
deba@567
   361
      _cbc_model->branchAndBound();
deba@567
   362
    }
deba@567
   363
deba@567
   364
    if (_cbc_model->isAbandoned()) {
deba@567
   365
      return UNSOLVED;
deba@567
   366
    } else {
deba@567
   367
      return SOLVED;
deba@567
   368
    }
deba@567
   369
  }
deba@567
   370
deba@567
   371
  CbcMip::Value CbcMip::_getSol(int i) const {
deba@567
   372
    return _cbc_model->getColSolution()[i];
deba@567
   373
  }
deba@567
   374
deba@567
   375
  CbcMip::Value CbcMip::_getSolValue() const {
deba@567
   376
    return _cbc_model->getObjValue();
deba@567
   377
  }
deba@567
   378
deba@567
   379
  CbcMip::ProblemType CbcMip::_getType() const {
deba@567
   380
    if (_cbc_model->isProvenOptimal()) {
deba@567
   381
      return OPTIMAL;
deba@567
   382
    } else if (_cbc_model->isContinuousUnbounded()) {
deba@567
   383
      return UNBOUNDED;
deba@567
   384
    }
deba@567
   385
    return FEASIBLE;
deba@567
   386
  }
deba@567
   387
deba@567
   388
  void CbcMip::_setSense(Sense sense) {
deba@567
   389
    switch (sense) {
deba@567
   390
    case MIN:
deba@567
   391
      _prob->setOptimizationDirection(1.0);
deba@567
   392
      break;
deba@567
   393
    case MAX:
deba@567
   394
      _prob->setOptimizationDirection(- 1.0);
deba@567
   395
      break;
deba@567
   396
    }
deba@567
   397
  }
deba@567
   398
deba@567
   399
  CbcMip::Sense CbcMip::_getSense() const {
deba@567
   400
    if (_prob->optimizationDirection() > 0.0) {
deba@567
   401
      return MIN;
deba@567
   402
    } else if (_prob->optimizationDirection() < 0.0) {
deba@567
   403
      return MAX;
deba@567
   404
    } else {
deba@567
   405
      LEMON_ASSERT(false, "Wrong sense");
deba@567
   406
      return CbcMip::Sense();
deba@567
   407
    }
deba@567
   408
  }
deba@567
   409
deba@567
   410
  void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) {
deba@567
   411
    switch (col_type){
deba@567
   412
    case INTEGER:
deba@567
   413
      _prob->setInteger(i);
deba@567
   414
      break;
deba@567
   415
    case REAL:
deba@567
   416
      _prob->setContinuous(i);
deba@567
   417
      break;
deba@567
   418
    default:;
deba@567
   419
      LEMON_ASSERT(false, "Wrong sense");
deba@567
   420
    }
deba@567
   421
  }
deba@567
   422
deba@567
   423
  CbcMip::ColTypes CbcMip::_getColType(int i) const {
deba@567
   424
    return _prob->getColumnIsInteger(i) ? INTEGER : REAL;
deba@567
   425
  }
deba@567
   426
deba@567
   427
  void CbcMip::_clear() {
deba@567
   428
    delete _prob;
deba@567
   429
    if (_osi_solver) {
deba@567
   430
      delete _osi_solver;
deba@567
   431
      _osi_solver = 0;
deba@567
   432
    }
deba@567
   433
    if (_cbc_model) {
deba@567
   434
      delete _cbc_model;
deba@567
   435
      _cbc_model = 0;
deba@567
   436
    }
deba@567
   437
deba@567
   438
    _prob = new CoinModel();
deba@567
   439
    rows.clear();
deba@567
   440
    cols.clear();
deba@567
   441
  }
deba@567
   442
deba@576
   443
  void CbcMip::_messageLevel(MessageLevel level) {
deba@576
   444
    switch (level) {
deba@576
   445
    case MESSAGE_NOTHING:
deba@576
   446
      _message_level = 0;
deba@576
   447
      break;
deba@576
   448
    case MESSAGE_ERROR:
deba@576
   449
      _message_level = 1;
deba@576
   450
      break;
deba@576
   451
    case MESSAGE_WARNING:
deba@576
   452
      _message_level = 1;
deba@576
   453
      break;
deba@576
   454
    case MESSAGE_NORMAL:
deba@576
   455
      _message_level = 2;
deba@576
   456
      break;
deba@576
   457
    case MESSAGE_VERBOSE:
deba@576
   458
      _message_level = 3;
deba@576
   459
      break;
deba@576
   460
    }
deba@567
   461
  }
deba@567
   462
deba@567
   463
} //END OF NAMESPACE LEMON