00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <algorithm>
00016 #include "base/hash.h"
00017 #include <string>
00018 #include <vector>
00019
00020 #include "base/commandlineflags.h"
00021 #include "base/integral_types.h"
00022 #include "base/logging.h"
00023 #include "base/scoped_ptr.h"
00024 #include "base/stringprintf.h"
00025 #include "base/timer.h"
00026 #include "base/strutil.h"
00027 #include "base/concise_iterator.h"
00028 #include "base/hash.h"
00029 #include "linear_solver/linear_solver.h"
00030
00031 #if defined(USE_CLP) || defined(USE_CBC)
00032
00033 #undef PACKAGE
00034 #undef VERSION
00035 #include "coin/ClpConfig.h"
00036 #include "coin/ClpMessage.hpp"
00037 #include "coin/ClpSimplex.hpp"
00038 #include "coin/CoinBuild.hpp"
00039
00040 DECLARE_double(solver_timeout_in_seconds);
00041 DECLARE_string(solver_write_model);
00042
00043 namespace operations_research {
00044
00045 class CLPInterface : public MPSolverInterface {
00046 public:
00047
00048 explicit CLPInterface(MPSolver* const solver);
00049 ~CLPInterface();
00050
00051
00052 virtual void SetOptimizationDirection(bool maximize);
00053
00054
00055
00056 virtual MPSolver::ResultStatus Solve(const MPSolverParameters& param);
00057
00058
00059
00060 virtual void Reset();
00061
00062
00063 virtual void SetVariableBounds(int var_index, double lb, double ub);
00064 virtual void SetVariableInteger(int var_index, bool integer);
00065 virtual void SetConstraintBounds(int row_index, double lb, double ub);
00066
00067
00068 void AddRowConstraint(MPConstraint* const ct);
00069
00070 void AddVariable(MPVariable* const var);
00071
00072 virtual void SetCoefficient(MPConstraint* const constraint,
00073 const MPVariable* const variable,
00074 double new_value,
00075 double old_value);
00076
00077 virtual void ClearConstraint(MPConstraint* const constraint);
00078
00079
00080 virtual void SetObjectiveCoefficient(const MPVariable* const variable,
00081 double coefficient);
00082
00083 virtual void SetObjectiveOffset(double value);
00084
00085 virtual void ClearObjective();
00086
00087
00088
00089 virtual int64 iterations() const;
00090
00091 virtual int64 nodes() const;
00092
00093 virtual double best_objective_bound() const;
00094
00095
00096 virtual MPSolver::BasisStatus row_status(int constraint_index) const;
00097
00098 virtual MPSolver::BasisStatus column_status(int variable_index) const;
00099
00100
00101
00102 virtual void WriteModel(const string& filename);
00103
00104
00105 virtual bool IsContinuous() const { return true; }
00106 virtual bool IsLP() const { return true; }
00107 virtual bool IsMIP() const { return false; }
00108
00109 virtual void ExtractNewVariables();
00110 virtual void ExtractNewConstraints();
00111 virtual void ExtractObjective();
00112
00113 virtual string SolverVersion() const {
00114 return "Clp " CLP_VERSION;
00115 }
00116
00117 virtual void* underlying_solver() {
00118 return reinterpret_cast<void*>(clp_.get());
00119 }
00120
00121 virtual double ComputeExactConditionNumber() const {
00122
00123 LOG(FATAL) << "ComputeExactConditionNumber is not implemented in CLP.";
00124 return 0.0;
00125 }
00126
00127 private:
00128
00129 void CreateDummyVariableForEmptyConstraints();
00130
00131
00132 virtual void SetParameters(const MPSolverParameters& param);
00133
00134
00135
00136 void ResetParameters();
00137
00138 virtual void SetRelativeMipGap(double value);
00139 virtual void SetPrimalTolerance(double value);
00140 virtual void SetDualTolerance(double value);
00141 virtual void SetPresolveMode(int value);
00142 virtual void SetLpAlgorithm(int value);
00143
00144
00145 MPSolver::BasisStatus
00146 TransformCLPBasisStatus(ClpSimplex::Status clp_basis_status) const;
00147
00148 scoped_ptr<ClpSimplex> clp_;
00149 scoped_ptr<ClpSolve> options_;
00150 };
00151
00152
00153
00154
00155 CLPInterface::CLPInterface(MPSolver* const solver)
00156 : MPSolverInterface(solver),
00157 clp_(new ClpSimplex), options_(new ClpSolve) {
00158 clp_->setStrParam(ClpProbName, solver_->name_);
00159 clp_->setOptimizationDirection(1);
00160 }
00161
00162 CLPInterface::~CLPInterface() {}
00163
00164 void CLPInterface::Reset() {
00165 clp_.reset(new ClpSimplex);
00166 clp_->setOptimizationDirection(maximize_ ? -1 : 1);
00167 ResetExtractionInformation();
00168 }
00169
00170 void CLPInterface::WriteModel(const string& filename) {
00171
00172
00173
00174 if (HasSuffixString(filename, ".lp")) {
00175 LOG(WARNING) << "CLP does not support the LP format, "
00176 << "writing in MPS format instead.";
00177 }
00178 clp_->writeMps(filename.c_str());
00179 }
00180
00181
00182
00183
00184 void CLPInterface::SetOptimizationDirection(bool maximize) {
00185 InvalidateSolutionSynchronization();
00186 clp_->setOptimizationDirection(maximize ? -1 : 1);
00187 }
00188
00189 void CLPInterface::SetVariableBounds(int var_index, double lb, double ub) {
00190 InvalidateSolutionSynchronization();
00191 if (var_index != kNoIndex) {
00192
00193 DCHECK_LE(var_index, last_variable_index_);
00194 clp_->setColumnBounds(var_index, lb, ub);
00195 } else {
00196 sync_status_ = MUST_RELOAD;
00197 }
00198 }
00199
00200
00201 void CLPInterface::SetVariableInteger(int var_index, bool integer) {}
00202
00203 void CLPInterface::SetConstraintBounds(int index, double lb, double ub) {
00204 InvalidateSolutionSynchronization();
00205 if (index != kNoIndex) {
00206
00207 DCHECK_LE(index, last_constraint_index_);
00208 clp_->setRowBounds(index, lb, ub);
00209 } else {
00210 sync_status_ = MUST_RELOAD;
00211 }
00212 }
00213
00214 void CLPInterface::SetCoefficient(MPConstraint* const constraint,
00215 const MPVariable* const variable,
00216 double new_value,
00217 double old_value) {
00218 InvalidateSolutionSynchronization();
00219 const int constraint_index = constraint->index();
00220 const int variable_index = variable->index();
00221 if (constraint_index != kNoIndex && variable_index != kNoIndex) {
00222
00223
00224 DCHECK_LE(constraint_index, last_constraint_index_);
00225 DCHECK_LE(variable_index, last_variable_index_);
00226 clp_->modifyCoefficient(constraint_index, variable_index, new_value);
00227 } else {
00228
00229
00230 sync_status_ = MUST_RELOAD;
00231 }
00232 }
00233
00234
00235 void CLPInterface::ClearConstraint(MPConstraint* const constraint) {
00236 InvalidateSolutionSynchronization();
00237 const int constraint_index = constraint->index();
00238
00239 if (constraint_index != kNoIndex) {
00240 for (ConstIter<hash_map<const MPVariable*, double> >
00241 it(constraint->coefficients_); !it.at_end(); ++it) {
00242 const int var_index = it->first->index();
00243 DCHECK_NE(kNoIndex, var_index);
00244 clp_->modifyCoefficient(constraint_index, var_index, 0.0);
00245 }
00246 }
00247 }
00248
00249
00250 void CLPInterface::SetObjectiveCoefficient(const MPVariable* const variable,
00251 double coefficient) {
00252 sync_status_ = MUST_RELOAD;
00253 }
00254
00255
00256 void CLPInterface::SetObjectiveOffset(double value) {
00257 sync_status_ = MUST_RELOAD;
00258 }
00259
00260
00261 void CLPInterface::ClearObjective() {
00262 InvalidateSolutionSynchronization();
00263
00264 for (ConstIter<hash_map<const MPVariable*, double> >
00265 it(solver_->objective_->coefficients_);
00266 !it.at_end(); ++it) {
00267 const int var_index = it->first->index();
00268
00269 if (var_index == kNoIndex) {
00270 DCHECK_NE(MODEL_SYNCHRONIZED, sync_status_);
00271 } else {
00272 clp_->setObjectiveCoefficient(var_index, 0.0);
00273 }
00274 }
00275
00276 clp_->setObjectiveOffset(0.0);
00277 }
00278
00279 void CLPInterface::AddRowConstraint(MPConstraint* const ct) {
00280 sync_status_ = MUST_RELOAD;
00281 }
00282
00283 void CLPInterface::AddVariable(MPVariable* const var) {
00284 sync_status_ = MUST_RELOAD;
00285 }
00286
00287 void CLPInterface::CreateDummyVariableForEmptyConstraints() {
00288 clp_->setColumnBounds(kDummyVariableIndex, 0.0, 0.0);
00289 clp_->setObjectiveCoefficient(kDummyVariableIndex, 0.0);
00290
00291 std::string dummy_name = "dummy";
00292 int var_index = kDummyVariableIndex;
00293 clp_->setColumnName(var_index, dummy_name);
00294 }
00295
00296
00297 void CLPInterface::ExtractNewVariables() {
00298
00299 int total_num_vars = solver_->variables_.size();
00300 if (total_num_vars > last_variable_index_) {
00301 if (last_variable_index_ == 0 && last_constraint_index_ == 0) {
00302
00303 clp_->resize(0, total_num_vars + 1);
00304 CreateDummyVariableForEmptyConstraints();
00305 for (int i = 0; i < total_num_vars; ++i) {
00306 MPVariable* const var = solver_->variables_[i];
00307 int var_index = i + 1;
00308 var->set_index(var_index);
00309 if (!var->name().empty()) {
00310 std::string std_name = var->name();
00311 clp_->setColumnName(var_index, std_name);
00312 }
00313 clp_->setColumnBounds(var_index, var->lb(), var->ub());
00314 }
00315 } else {
00316
00317
00318
00319
00320
00321 for (int j = last_variable_index_; j < total_num_vars; ++j) {
00322 MPVariable* const var = solver_->variables_[j];
00323 DCHECK_EQ(kNoIndex, var->index());
00324 int var_index = j + 1;
00325 var->set_index(var_index);
00326
00327 double tmp_obj_coef = 0.0;
00328 clp_->addColumn(0, NULL, NULL, var->lb(), var->ub(), tmp_obj_coef);
00329 if (!var->name().empty()) {
00330 std::string std_name = var->name();
00331 clp_->setColumnName(var_index, std_name);
00332 }
00333 }
00334
00335 for (int i = 0; i < last_constraint_index_; i++) {
00336 MPConstraint* const ct = solver_->constraints_[i];
00337 for (ConstIter<hash_map<const MPVariable*, double> > it(
00338 ct->coefficients_);
00339 !it.at_end(); ++it) {
00340 const int var_index = it->first->index();
00341 DCHECK_NE(kNoIndex, var_index);
00342 if (var_index >= last_variable_index_) {
00343 clp_->modifyCoefficient(i, var_index, it->second);
00344 }
00345 }
00346 }
00347 }
00348 }
00349 }
00350
00351
00352 void CLPInterface::ExtractNewConstraints() {
00353 int total_num_rows = solver_->constraints_.size();
00354 if (last_constraint_index_ < total_num_rows) {
00355
00356 int max_row_length = 0;
00357 for (int i = last_constraint_index_; i < total_num_rows; ++i) {
00358 MPConstraint* const ct = solver_->constraints_[i];
00359 DCHECK_EQ(kNoIndex, ct->index());
00360 ct->set_index(i);
00361 if (ct->coefficients_.size() > max_row_length) {
00362 max_row_length = ct->coefficients_.size();
00363 }
00364 }
00365
00366 max_row_length = std::max(1, max_row_length);
00367 scoped_array<int> indices(new int[max_row_length]);
00368 scoped_array<double> coefs(new double[max_row_length]);
00369 CoinBuild build_object;
00370
00371 for (int i = last_constraint_index_; i < total_num_rows; ++i) {
00372 MPConstraint* const ct = solver_->constraints_[i];
00373 DCHECK_NE(kNoIndex, ct->index());
00374 int size = ct->coefficients_.size();
00375 if (size == 0) {
00376
00377 indices[0] = kDummyVariableIndex;
00378 coefs[0] = 1.0;
00379 size = 1;
00380 }
00381 int j = 0;
00382 for (ConstIter<hash_map<const MPVariable*, double> >
00383 it(ct->coefficients_);
00384 !it.at_end(); ++it) {
00385 const int index = it->first->index();
00386 DCHECK_NE(kNoIndex, index);
00387 indices[j] = index;
00388 coefs[j] = it->second;
00389 j++;
00390 }
00391 build_object.addRow(size,
00392 indices.get(),
00393 coefs.get(),
00394 ct->lb(),
00395 ct->ub());
00396 }
00397
00398 clp_->addRows(build_object);
00399 for (int i = last_constraint_index_; i < total_num_rows; ++i) {
00400 MPConstraint* const ct = solver_->constraints_[i];
00401 if (!ct->name().empty()) {
00402 std::string std_name = ct->name();
00403 clp_->setRowName(ct->index(), std_name);
00404 }
00405 }
00406 }
00407 }
00408
00409 void CLPInterface::ExtractObjective() {
00410
00411
00412 for (ConstIter<hash_map<const MPVariable*, double> >
00413 it(solver_->objective_->coefficients_);
00414 !it.at_end(); ++it) {
00415 clp_->setObjectiveCoefficient(it->first->index(), it->second);
00416 }
00417
00418
00419
00420 clp_->setObjectiveOffset(-solver_->Objective().offset());
00421 }
00422
00423
00424 MPSolver::ResultStatus CLPInterface::Solve(const MPSolverParameters& param) {
00425 WallTimer timer;
00426 timer.Start();
00427
00428 if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) ==
00429 MPSolverParameters::INCREMENTALITY_OFF) {
00430 Reset();
00431 }
00432
00433
00434 CoinMessageHandler message_handler;
00435 clp_->passInMessageHandler(&message_handler);
00436 if (quiet_) {
00437 message_handler.setLogLevel(1, 0);
00438 clp_->setLogLevel(0);
00439 } else {
00440 message_handler.setLogLevel(1, 1);
00441 clp_->setLogLevel(1);
00442 }
00443
00444
00445
00446 if (solver_->variables_.size() == 0 && solver_->constraints_.size() == 0) {
00447 sync_status_ = SOLUTION_SYNCHRONIZED;
00448 result_status_ = MPSolver::OPTIMAL;
00449 objective_value_ = solver_->Objective().offset();
00450 return result_status_;
00451 }
00452
00453 ExtractModel();
00454 VLOG(1) << StringPrintf("Model built in %.3f seconds.", timer.Get());
00455
00456 WriteModelToPredefinedFiles();
00457
00458
00459 if (solver_->time_limit()) {
00460 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
00461 clp_->setMaximumSeconds(solver_->time_limit() / 1000.0);
00462 } else {
00463 clp_->setMaximumSeconds(-1.0);
00464 }
00465
00466
00467
00468 options_.reset(new ClpSolve);
00469 SetParameters(param);
00470
00471
00472 timer.Restart();
00473 clp_->initialSolve(*options_);
00474 VLOG(1) << StringPrintf("Solved in %.3f seconds.", timer.Get());
00475
00476
00477 objective_value_ = clp_->objectiveValue();
00478 VLOG(1) << "objective=" << objective_value_;
00479 const double* const values = clp_->getColSolution();
00480 const double* const reduced_costs = clp_->getReducedCost();
00481 for (int i = 0; i < solver_->variables_.size(); ++i) {
00482 MPVariable* const var = solver_->variables_[i];
00483 const int var_index = var->index();
00484 double val = values[var_index];
00485 var->set_solution_value(val);
00486 VLOG(3) << var->name() << ": value = " << val;
00487 double reduced_cost = reduced_costs[var_index];
00488 var->set_reduced_cost(reduced_cost);
00489 VLOG(4) << var->name() << ": reduced cost = " << reduced_cost;
00490 }
00491 const double* const dual_values = clp_->getRowPrice();
00492 const double* const row_activities = clp_->getRowActivity();
00493 for (int i = 0; i < solver_->constraints_.size(); ++i) {
00494 MPConstraint* const ct = solver_->constraints_[i];
00495 const int constraint_index = ct->index();
00496 const double row_activity = row_activities[constraint_index];
00497 ct->set_activity(row_activity);
00498 const double dual_value = dual_values[constraint_index];
00499 ct->set_dual_value(dual_value);
00500 VLOG(4) << "row " << ct->index()
00501 << ": activity = " << row_activity
00502 << " dual value = " << dual_value;
00503 }
00504
00505
00506 int tmp_status = clp_->status();
00507 VLOG(1) << "clp result status: " << tmp_status;
00508 switch (tmp_status) {
00509 case CLP_SIMPLEX_FINISHED:
00510 result_status_ = MPSolver::OPTIMAL;
00511 break;
00512 case CLP_SIMPLEX_INFEASIBLE:
00513 result_status_ = MPSolver::INFEASIBLE;
00514 break;
00515 case CLP_SIMPLEX_UNBOUNDED:
00516 result_status_ = MPSolver::UNBOUNDED;
00517 break;
00518 case CLP_SIMPLEX_STOPPED:
00519 result_status_ = MPSolver::FEASIBLE;
00520 break;
00521 default:
00522 result_status_ = MPSolver::ABNORMAL;
00523 break;
00524 }
00525
00526 ResetParameters();
00527 sync_status_ = SOLUTION_SYNCHRONIZED;
00528 return result_status_;
00529 }
00530
00531 MPSolver::BasisStatus CLPInterface::TransformCLPBasisStatus(
00532 ClpSimplex::Status clp_basis_status) const {
00533 switch (clp_basis_status) {
00534 case ClpSimplex::isFree:
00535 return MPSolver::FREE;
00536 case ClpSimplex::basic:
00537 return MPSolver::BASIC;
00538 case ClpSimplex::atUpperBound:
00539 return MPSolver::AT_UPPER_BOUND;
00540 case ClpSimplex::atLowerBound:
00541 return MPSolver::AT_LOWER_BOUND;
00542 case ClpSimplex::superBasic:
00543 return MPSolver::FREE;
00544 case ClpSimplex::isFixed:
00545 return MPSolver::FIXED_VALUE;
00546 default:
00547 LOG(FATAL) << "Unknown CLP basis status";
00548 return MPSolver::FREE;
00549 }
00550 }
00551
00552 MPSolverInterface* BuildCLPInterface(MPSolver* const solver) {
00553 return new CLPInterface(solver);
00554 }
00555
00556
00557
00558 int64 CLPInterface::iterations() const {
00559 CheckSolutionIsSynchronized();
00560 return clp_->getIterationCount();
00561 }
00562
00563 int64 CLPInterface::nodes() const {
00564 LOG(FATAL) << "Number of nodes only available for discrete problems";
00565 return kUnknownNumberOfNodes;
00566 }
00567
00568 double CLPInterface::best_objective_bound() const {
00569 LOG(FATAL) << "Best objective bound only available for discrete problems";
00570 return 0.0;
00571 }
00572
00573 MPSolver::BasisStatus CLPInterface::row_status(int constraint_index) const {
00574 DCHECK_LE(0, constraint_index);
00575 DCHECK_GT(last_constraint_index_, constraint_index);
00576 const ClpSimplex::Status clp_basis_status =
00577 clp_->getRowStatus(constraint_index);
00578 return TransformCLPBasisStatus(clp_basis_status);
00579 }
00580
00581 MPSolver::BasisStatus CLPInterface::column_status(int variable_index) const {
00582 DCHECK_LE(0, variable_index);
00583
00584 DCHECK_GT(last_variable_index_ + 1, variable_index);
00585 const ClpSimplex::Status clp_basis_status =
00586 clp_->getColumnStatus(variable_index);
00587 return TransformCLPBasisStatus(clp_basis_status);
00588 }
00589
00590
00591
00592 void CLPInterface::SetParameters(const MPSolverParameters& param) {
00593 SetCommonParameters(param);
00594 }
00595
00596 void CLPInterface::ResetParameters() {
00597 clp_->setPrimalTolerance(MPSolverParameters::kDefaultPrimalTolerance);
00598 clp_->setDualTolerance(MPSolverParameters::kDefaultDualTolerance);
00599 }
00600
00601 void CLPInterface::SetRelativeMipGap(double value) {
00602 LOG(WARNING) << "The relative MIP gap is only available "
00603 << "for discrete problems.";
00604 }
00605
00606 void CLPInterface::SetPrimalTolerance(double value) {
00607 clp_->setPrimalTolerance(value);
00608 }
00609
00610 void CLPInterface::SetDualTolerance(double value) {
00611 clp_->setDualTolerance(value);
00612 }
00613
00614 void CLPInterface::SetPresolveMode(int value) {
00615 switch (value) {
00616 case MPSolverParameters::PRESOLVE_OFF: {
00617 options_->setPresolveType(ClpSolve::presolveOff);
00618 break;
00619 }
00620 case MPSolverParameters::PRESOLVE_ON: {
00621 options_->setPresolveType(ClpSolve::presolveOn);
00622 break;
00623 }
00624 default: {
00625 SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value);
00626 }
00627 }
00628 }
00629
00630 void CLPInterface::SetLpAlgorithm(int value) {
00631 switch (value) {
00632 case MPSolverParameters::DUAL: {
00633 options_->setSolveType(ClpSolve::useDual);
00634 break;
00635 }
00636 case MPSolverParameters::PRIMAL: {
00637 options_->setSolveType(ClpSolve::usePrimal);
00638 break;
00639 }
00640 case MPSolverParameters::BARRIER: {
00641 options_->setSolveType(ClpSolve::useBarrier);
00642 break;
00643 }
00644 default: {
00645 SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
00646 value);
00647 }
00648 }
00649 }
00650
00651 }
00652 #endif // #if defined(USE_CBC) || defined(USE_CLP)