00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "base/hash.h"
00016 #include <limits>
00017 #include <string>
00018 #include <utility>
00019 #include <vector>
00020
00021 #include "base/commandlineflags.h"
00022 #include "base/integral_types.h"
00023 #include "base/logging.h"
00024 #include "base/scoped_ptr.h"
00025 #include "base/stringprintf.h"
00026 #include "base/timer.h"
00027 #include "base/hash.h"
00028 #include "linear_solver/linear_solver.h"
00029
00030 #if defined(USE_CBC)
00031
00032 #undef PACKAGE
00033 #undef VERSION
00034 #include "coin/CbcConfig.h"
00035 #include "coin/CbcMessage.hpp"
00036 #include "coin/CbcModel.hpp"
00037 #include "coin/CoinModel.hpp"
00038 #include "coin/OsiClpSolverInterface.hpp"
00039
00040
00041
00042 DECLARE_double(solver_timeout_in_seconds);
00043 DECLARE_string(solver_write_model);
00044
00045 namespace operations_research {
00046
00047 class CBCInterface : public MPSolverInterface {
00048 public:
00049
00050 explicit CBCInterface(MPSolver* const solver);
00051 virtual ~CBCInterface();
00052
00053
00054 virtual void Reset();
00055
00056
00057 virtual void SetOptimizationDirection(bool maximize);
00058
00059
00060
00061 virtual MPSolver::ResultStatus Solve(const MPSolverParameters& param);
00062
00063
00064 virtual void ExtractModel() {}
00065
00066
00067 virtual void WriteModel(const string& filename);
00068
00069
00070 virtual bool IsContinuous() const { return false; }
00071 virtual bool IsLP() const { return false; }
00072 virtual bool IsMIP() const { return true; }
00073
00074
00075 virtual void SetVariableBounds(int var_index, double lb, double ub);
00076 virtual void SetVariableInteger(int var_index, bool integer);
00077 virtual void SetConstraintBounds(int row_index, double lb, double ub);
00078
00079
00080 void AddRowConstraint(MPConstraint* const ct);
00081
00082 void AddVariable(MPVariable* const var);
00083
00084 virtual void SetCoefficient(MPConstraint* const constraint,
00085 const MPVariable* const variable,
00086 double new_value,
00087 double old_value) {
00088 sync_status_ = MUST_RELOAD;
00089 }
00090
00091 virtual void ClearConstraint(MPConstraint* const constraint) {
00092 sync_status_ = MUST_RELOAD;
00093 }
00094
00095
00096 virtual void SetObjectiveCoefficient(const MPVariable* const variable,
00097 double coefficient) {
00098 sync_status_ = MUST_RELOAD;
00099 }
00100
00101 virtual void SetObjectiveOffset(double value) {
00102 sync_status_ = MUST_RELOAD;
00103 }
00104
00105 virtual void ClearObjective() {
00106 sync_status_ = MUST_RELOAD;
00107 }
00108
00109
00110 virtual int64 iterations() const;
00111
00112 virtual int64 nodes() const;
00113
00114 virtual double best_objective_bound() const;
00115
00116
00117 virtual MPSolver::BasisStatus row_status(int constraint_index) const {
00118 LOG(FATAL) << "Basis status only available for continuous problems";
00119 return MPSolver::FREE;
00120 }
00121
00122 virtual MPSolver::BasisStatus column_status(int variable_index) const {
00123 LOG(FATAL) << "Basis status only available for continuous problems";
00124 return MPSolver::FREE;
00125 }
00126
00127 virtual void ExtractNewVariables() {}
00128 virtual void ExtractNewConstraints() {}
00129 virtual void ExtractObjective() {}
00130
00131 virtual string SolverVersion() const {
00132 return "Cbc " CBC_VERSION;
00133 }
00134
00135
00136
00137
00138 virtual void* underlying_solver() {
00139 return reinterpret_cast<void*>(&osi_);
00140 }
00141
00142 virtual double ComputeExactConditionNumber() const {
00143 LOG(FATAL) << "Condition number only available for continuous problems";
00144 return 0.0;
00145 }
00146
00147 private:
00148
00149
00150 void ResetBestObjectiveBound();
00151
00152
00153 virtual void SetParameters(const MPSolverParameters& param);
00154
00155 virtual void SetRelativeMipGap(double value);
00156 virtual void SetPrimalTolerance(double value);
00157 virtual void SetDualTolerance(double value);
00158 virtual void SetPresolveMode(int value);
00159 virtual void SetLpAlgorithm(int value);
00160
00161 OsiClpSolverInterface osi_;
00162
00163 int64 iterations_;
00164 int64 nodes_;
00165 double best_objective_bound_;
00166
00167 double relative_mip_gap_;
00168 };
00169
00170
00171
00172
00173 CBCInterface::CBCInterface(MPSolver* const solver)
00174 : MPSolverInterface(solver),
00175 iterations_(0), nodes_(0),
00176 best_objective_bound_(-std::numeric_limits<double>::infinity()),
00177 relative_mip_gap_(MPSolverParameters::kDefaultRelativeMipGap) {
00178 osi_.setStrParam(OsiProbName, solver_->name_);
00179 osi_.setObjSense(1);
00180 }
00181
00182 CBCInterface::~CBCInterface() {}
00183
00184
00185 void CBCInterface::Reset() {
00186 osi_.reset();
00187 osi_.setObjSense(maximize_ ? -1 : 1);
00188 osi_.setStrParam(OsiProbName, solver_->name_);
00189 ResetExtractionInformation();
00190 }
00191
00192 void CBCInterface::ResetBestObjectiveBound() {
00193 if (maximize_) {
00194 best_objective_bound_ = std::numeric_limits<double>::infinity();
00195 } else {
00196 best_objective_bound_ = -std::numeric_limits<double>::infinity();
00197 }
00198 }
00199
00200 void CBCInterface::SetOptimizationDirection(bool maximize) {
00201 InvalidateSolutionSynchronization();
00202 if (sync_status_ == MODEL_SYNCHRONIZED) {
00203 osi_.setObjSense(maximize ? -1 : 1);
00204 } else {
00205 sync_status_ = MUST_RELOAD;
00206 }
00207 }
00208
00209 void CBCInterface::WriteModel(const string& filename) {
00210 if (HasSuffixString(filename, ".lp")) {
00211 osi_.writeLp(filename.c_str(), "");
00212 } else {
00213
00214
00215 osi_.writeMps(filename.c_str(), "");
00216 }
00217 }
00218
00219 void CBCInterface::SetVariableBounds(int var_index, double lb, double ub) {
00220 InvalidateSolutionSynchronization();
00221 if (sync_status_ == MODEL_SYNCHRONIZED) {
00222 osi_.setColBounds(var_index, lb, ub);
00223 } else {
00224 sync_status_ = MUST_RELOAD;
00225 }
00226 }
00227
00228 void CBCInterface::SetVariableInteger(int var_index, bool integer) {
00229 InvalidateSolutionSynchronization();
00230
00231 if (sync_status_ == MODEL_SYNCHRONIZED) {
00232 if (integer) {
00233 osi_.setInteger(var_index);
00234 } else {
00235 osi_.setContinuous(var_index);
00236 }
00237 } else {
00238 sync_status_ = MUST_RELOAD;
00239 }
00240 }
00241
00242 void CBCInterface::SetConstraintBounds(int index, double lb, double ub) {
00243 InvalidateSolutionSynchronization();
00244 if (sync_status_ == MODEL_SYNCHRONIZED) {
00245 osi_.setRowBounds(index, lb, ub);
00246 } else {
00247 sync_status_ = MUST_RELOAD;
00248 }
00249 }
00250
00251 void CBCInterface::AddRowConstraint(MPConstraint* const ct) {
00252 sync_status_ = MUST_RELOAD;
00253 }
00254
00255 void CBCInterface::AddVariable(MPVariable* const var) {
00256 sync_status_ = MUST_RELOAD;
00257 }
00258
00259
00260
00261 MPSolver::ResultStatus CBCInterface::Solve(const MPSolverParameters& param) {
00262 WallTimer timer;
00263 timer.Start();
00264
00265
00266 if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) ==
00267 MPSolverParameters::INCREMENTALITY_OFF) {
00268 Reset();
00269 }
00270
00271
00272
00273 if (solver_->variables_.size() == 0 && solver_->constraints_.size() == 0) {
00274 sync_status_ = SOLUTION_SYNCHRONIZED;
00275 result_status_ = MPSolver::OPTIMAL;
00276 objective_value_ = solver_->Objective().offset();
00277 best_objective_bound_ = solver_->Objective().offset();
00278 return result_status_;
00279 }
00280
00281
00282
00283 switch (sync_status_) {
00284 case MUST_RELOAD: {
00285 Reset();
00286 CoinModel build;
00287
00288 build.addColumn(0, NULL, NULL, 1.0, 1.0,
00289 solver_->Objective().offset(), "dummy", false);
00290 const int nb_vars = solver_->variables_.size();
00291 for (int i = 0; i < nb_vars; ++i) {
00292 MPVariable* const var = solver_->variables_[i];
00293 var->set_index(i + 1);
00294 const double obj_coeff = solver_->Objective().GetCoefficient(var);
00295 if (var->name().empty()) {
00296 build.addColumn(0, NULL, NULL, var->lb(), var->ub(), obj_coeff,
00297 NULL, var->integer());
00298 } else {
00299 build.addColumn(0, NULL, NULL, var->lb(), var->ub(), obj_coeff,
00300 var->name().c_str(), var->integer());
00301 }
00302 }
00303
00304
00305 int max_row_length = 0;
00306 int constraint_index = 0;
00307 for (int i = 0; i < solver_->constraints_.size(); ++i) {
00308 MPConstraint* const ct = solver_->constraints_[i];
00309 ct->set_index(constraint_index++);
00310 if (ct->coefficients_.size() > max_row_length) {
00311 max_row_length = ct->coefficients_.size();
00312 }
00313 }
00314 scoped_array<int> indices(new int[max_row_length]);
00315 scoped_array<double> coefs(new double[max_row_length]);
00316
00317 for (int i = 0; i < solver_->constraints_.size(); ++i) {
00318 MPConstraint* const ct = solver_->constraints_[i];
00319 const int size = ct->coefficients_.size();
00320 int j = 0;
00321 for (hash_map<const MPVariable*, double>::const_iterator it =
00322 ct->coefficients_.begin();
00323 it != ct->coefficients_.end();
00324 ++it) {
00325 const int index = it->first->index();
00326 DCHECK_NE(kNoIndex, index);
00327 indices[j] = index;
00328 coefs[j] = it->second;
00329 j++;
00330 }
00331 if (ct->name().empty()) {
00332 build.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub());
00333 } else {
00334 build.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub(),
00335 ct->name().c_str());
00336 }
00337 }
00338 osi_.loadFromCoinModel(build);
00339 break;
00340 }
00341 case MODEL_SYNCHRONIZED: {
00342 break;
00343 }
00344 case SOLUTION_SYNCHRONIZED: {
00345 break;
00346 }
00347 }
00348
00349
00350
00351 osi_.setObjSense(maximize_ ? -1 : 1);
00352
00353 sync_status_ = MODEL_SYNCHRONIZED;
00354 VLOG(1) << StringPrintf("Model built in %.3f seconds.", timer.Get());
00355
00356 WriteModelToPredefinedFiles();
00357
00358 ResetBestObjectiveBound();
00359
00360
00361 CbcModel model(osi_);
00362
00363
00364 CoinMessageHandler message_handler;
00365 model.passInMessageHandler(&message_handler);
00366 if (quiet_) {
00367 message_handler.setLogLevel(0, 0);
00368 message_handler.setLogLevel(1, 0);
00369 message_handler.setLogLevel(2, 0);
00370 message_handler.setLogLevel(3, 0);
00371 } else {
00372 message_handler.setLogLevel(0, 1);
00373 message_handler.setLogLevel(1, 0);
00374 message_handler.setLogLevel(2, 0);
00375 message_handler.setLogLevel(3, 1);
00376 }
00377
00378
00379 if (solver_->time_limit()) {
00380 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
00381 model.setMaximumSeconds(solver_->time_limit() / 1000.0);
00382 }
00383
00384
00385 timer.Restart();
00386
00387
00388
00389
00390 SetParameters(param);
00391
00392
00393 model.setTypePresolve(0);
00394
00395
00396 model.setAllowableFractionGap(relative_mip_gap_);
00397 int return_status = callCbc("-solve", model);
00398 const int kBadReturnStatus = 777;
00399 CHECK_NE(kBadReturnStatus, return_status);
00400
00401
00402 VLOG(1) << StringPrintf("Solved in %.3f seconds.", timer.Get());
00403
00404
00405 objective_value_ = model.getObjValue();
00406 VLOG(1) << "objective=" << objective_value_;
00407 const double* const values = model.bestSolution();
00408 if (values != NULL) {
00409
00410 for (int i = 0; i < solver_->variables_.size(); ++i) {
00411 MPVariable* const var = solver_->variables_[i];
00412 const int var_index = var->index();
00413 const double val = values[var_index];
00414 var->set_solution_value(val);
00415 VLOG(3) << var->name() << "=" << val;
00416 }
00417 } else {
00418 VLOG(1) << "No feasible solution found.";
00419 }
00420
00421 const double* const row_activities = model.getRowActivity();
00422 if (row_activities != NULL) {
00423 for (int i = 0; i < solver_->constraints_.size(); ++i) {
00424 MPConstraint* const ct = solver_->constraints_[i];
00425 const int constraint_index = ct->index();
00426 const double row_activity = row_activities[constraint_index];
00427 ct->set_activity(row_activity);
00428 VLOG(4) << "row " << ct->index()
00429 << ": activity = " << row_activity;
00430 }
00431 }
00432
00433
00434 int tmp_status = model.status();
00435
00436 VLOG(1) << "cbc result status: " << tmp_status;
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449 switch (tmp_status) {
00450 case 0:
00451
00452
00453 if (model.isProvenOptimal()) {
00454 result_status_ = MPSolver::OPTIMAL;
00455 } else if (model.isContinuousUnbounded()) {
00456 result_status_ = MPSolver::UNBOUNDED;
00457 } else if (model.isProvenInfeasible()) {
00458 result_status_ = MPSolver::INFEASIBLE;
00459 } else {
00460 LOG(FATAL)
00461 << "Unknown solver status! Secondary status: "
00462 << model.secondaryStatus();
00463 }
00464 break;
00465 case 1:
00466 result_status_ = MPSolver::FEASIBLE;
00467 break;
00468 default:
00469 result_status_ = MPSolver::ABNORMAL;
00470 break;
00471 }
00472
00473 iterations_ = model.getIterationCount();
00474 nodes_ = model.getNodeCount();
00475 best_objective_bound_ = model.getBestPossibleObjValue();
00476 VLOG(1) << "best objective bound=" << best_objective_bound_;
00477
00478 sync_status_ = SOLUTION_SYNCHRONIZED;
00479
00480 return result_status_;
00481 }
00482
00483 MPSolverInterface* BuildCBCInterface(MPSolver* const solver) {
00484 return new CBCInterface(solver);
00485 }
00486
00487
00488
00489 int64 CBCInterface::iterations() const {
00490 CheckSolutionIsSynchronized();
00491 return iterations_;
00492 }
00493
00494 int64 CBCInterface::nodes() const {
00495 CheckSolutionIsSynchronized();
00496 return nodes_;
00497 }
00498
00499 double CBCInterface::best_objective_bound() const {
00500 CheckSolutionIsSynchronized();
00501 CheckBestObjectiveBoundExists();
00502 return best_objective_bound_;
00503 }
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 void CBCInterface::SetParameters(const MPSolverParameters& param) {
00514 SetCommonParameters(param);
00515 SetMIPParameters(param);
00516 }
00517
00518 void CBCInterface::SetRelativeMipGap(double value) {
00519 relative_mip_gap_ = value;
00520 }
00521
00522 void CBCInterface::SetPrimalTolerance(double value) {
00523
00524
00525 if (value != MPSolverParameters::kDefaultPrimalTolerance) {
00526 SetUnsupportedDoubleParam(MPSolverParameters::PRIMAL_TOLERANCE);
00527 }
00528 }
00529
00530 void CBCInterface::SetDualTolerance(double value) {
00531
00532
00533 if (value != MPSolverParameters::kDefaultDualTolerance) {
00534 SetUnsupportedDoubleParam(MPSolverParameters::DUAL_TOLERANCE);
00535 }
00536 }
00537
00538 void CBCInterface::SetPresolveMode(int value) {
00539 switch (value) {
00540 case MPSolverParameters::PRESOLVE_ON: {
00541
00542 break;
00543 }
00544 default: {
00545 SetUnsupportedIntegerParam(MPSolverParameters::PRESOLVE);
00546 }
00547 }
00548 }
00549
00550 void CBCInterface::SetLpAlgorithm(int value) {
00551 SetUnsupportedIntegerParam(MPSolverParameters::LP_ALGORITHM);
00552 }
00553
00554 }
00555 #endif // #if defined(USE_CBC)