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