21 #include "absl/memory/memory.h"
22 #include "absl/strings/match.h"
23 #include "absl/strings/str_format.h"
31 #if defined(USE_CLP) || defined(USE_CBC)
35 #include "ClpConfig.h"
36 #include "ClpMessage.hpp"
37 #include "ClpSimplex.hpp"
38 #include "CoinBuild.hpp"
57 void Reset()
override;
70 const MPVariable*
const variable,
double new_value,
71 double old_value)
override;
99 bool IsLP()
const override {
return true; }
100 bool IsMIP()
const override {
return false; }
109 return reinterpret_cast<void*
>(clp_.get());
114 void CreateDummyVariableForEmptyConstraints();
121 void ResetParameters();
123 void SetRelativeMipGap(
double value)
override;
124 void SetPrimalTolerance(
double value)
override;
125 void SetDualTolerance(
double value)
override;
126 void SetPresolveMode(
int value)
override;
127 void SetScalingMode(
int value)
override;
128 void SetLpAlgorithm(
int value)
override;
132 ClpSimplex::Status clp_basis_status)
const;
134 std::unique_ptr<ClpSimplex> clp_;
135 std::unique_ptr<ClpSolve> options_;
143 clp_->setStrParam(ClpProbName,
solver_->name_);
144 clp_->setOptimizationDirection(1);
150 clp_ = absl::make_unique<ClpSimplex>();
151 clp_->setOptimizationDirection(
maximize_ ? -1 : 1);
160 int MPSolverVarIndexToClpVarIndex(
int var_index) {
return var_index + 1; }
166 clp_->setOptimizationDirection(maximize ? -1 : 1);
174 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(var_index), lb, ub);
188 clp_->setRowBounds(
index, lb, ub);
196 double new_value,
double old_value) {
204 clp_->modifyCoefficient(constraint->
index(),
205 MPSolverVarIndexToClpVarIndex(variable->
index()),
219 for (
const auto& entry : constraint->coefficients_) {
221 clp_->modifyCoefficient(constraint->
index(),
222 MPSolverVarIndexToClpVarIndex(entry.first->index()),
232 clp_->setObjectiveCoefficient(
244 clp_->setObjectiveOffset(-offset);
251 for (
const auto& entry :
solver_->objective_->coefficients_) {
252 const int mpsolver_var_index = entry.first->index();
257 clp_->setObjectiveCoefficient(
258 MPSolverVarIndexToClpVarIndex(mpsolver_var_index), 0.0);
262 clp_->setObjectiveOffset(0.0);
273 void CLPInterface::CreateDummyVariableForEmptyConstraints() {
279 std::string dummy =
"dummy";
286 int total_num_vars =
solver_->variables_.size();
290 clp_->resize(0, total_num_vars + 1);
291 CreateDummyVariableForEmptyConstraints();
292 for (
int i = 0; i < total_num_vars; ++i) {
295 if (!
var->name().empty()) {
296 std::string
name =
var->name();
297 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(i),
name);
299 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(i),
var->lb(),
313 double tmp_obj_coef = 0.0;
314 clp_->addColumn(0,
nullptr,
nullptr,
var->lb(),
var->ub(),
316 if (!
var->name().empty()) {
317 std::string
name =
var->name();
318 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(j),
name);
324 const int ct_index =
ct->index();
325 for (
const auto& entry :
ct->coefficients_) {
326 const int mpsolver_var_index = entry.first->index();
329 clp_->modifyCoefficient(
330 ct_index, MPSolverVarIndexToClpVarIndex(mpsolver_var_index),
341 int total_num_rows =
solver_->constraints_.size();
344 int max_row_length = 0;
349 if (
ct->coefficients_.size() > max_row_length) {
350 max_row_length =
ct->coefficients_.size();
354 max_row_length =
std::max(1, max_row_length);
355 std::unique_ptr<int[]> indices(
new int[max_row_length]);
356 std::unique_ptr<double[]> coefs(
new double[max_row_length]);
357 CoinBuild build_object;
362 int size =
ct->coefficients_.size();
370 for (
const auto& entry :
ct->coefficients_) {
371 const int mpsolver_var_index = entry.first->index();
373 indices[j] = MPSolverVarIndexToClpVarIndex(mpsolver_var_index);
374 coefs[j] = entry.second;
377 build_object.addRow(size, indices.get(), coefs.get(),
ct->lb(),
ct->ub());
380 clp_->addRows(build_object);
383 if (!
ct->name().empty()) {
384 std::string
name =
ct->name();
385 clp_->setRowName(
ct->index(),
name);
394 for (
const auto& entry :
solver_->objective_->coefficients_) {
395 clp_->setObjectiveCoefficient(
396 MPSolverVarIndexToClpVarIndex(entry.first->index()), entry.second);
416 CoinMessageHandler message_handler;
417 clp_->passInMessageHandler(&message_handler);
419 message_handler.setLogLevel(1, 0);
420 clp_->setLogLevel(0);
422 message_handler.setLogLevel(1, 1);
423 clp_->setLogLevel(1);
428 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
436 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
443 clp_->setMaximumSeconds(-1.0);
448 options_ = absl::make_unique<ClpSolve>();
449 SetParameters(param);
453 clp_->initialSolve(*options_);
454 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
457 int tmp_status = clp_->status();
458 VLOG(1) <<
"clp result status: " << tmp_status;
459 switch (tmp_status) {
460 case CLP_SIMPLEX_FINISHED:
463 case CLP_SIMPLEX_INFEASIBLE:
466 case CLP_SIMPLEX_UNBOUNDED:
469 case CLP_SIMPLEX_STOPPED:
482 const double*
const values = clp_->getColSolution();
483 const double*
const reduced_costs = clp_->getReducedCost();
484 for (
int i = 0; i <
solver_->variables_.size(); ++i) {
486 const int clp_var_index = MPSolverVarIndexToClpVarIndex(
var->index());
487 const double val = values[clp_var_index];
488 var->set_solution_value(val);
489 VLOG(3) <<
var->name() <<
": value = " << val;
490 double reduced_cost = reduced_costs[clp_var_index];
491 var->set_reduced_cost(reduced_cost);
492 VLOG(4) <<
var->name() <<
": reduced cost = " << reduced_cost;
494 const double*
const dual_values = clp_->getRowPrice();
495 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
497 const int constraint_index =
ct->index();
498 const double dual_value = dual_values[constraint_index];
499 ct->set_dual_value(dual_value);
500 VLOG(4) <<
"row " <<
ct->index() <<
" dual value = " << dual_value;
507 }
catch (CoinError& e) {
508 LOG(WARNING) <<
"Caught exception in Coin LP: " << e.message();
515 ClpSimplex::Status clp_basis_status)
const {
516 switch (clp_basis_status) {
517 case ClpSimplex::isFree:
519 case ClpSimplex::basic:
521 case ClpSimplex::atUpperBound:
523 case ClpSimplex::atLowerBound:
525 case ClpSimplex::superBasic:
527 case ClpSimplex::isFixed:
530 LOG(FATAL) <<
"Unknown CLP basis status";
539 return clp_->getIterationCount();
543 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
548 LOG(DFATAL) <<
"Best objective bound only available for discrete problems";
553 DCHECK_LE(0, constraint_index);
555 const ClpSimplex::Status clp_basis_status =
556 clp_->getRowStatus(constraint_index);
557 return TransformCLPBasisStatus(clp_basis_status);
561 DCHECK_LE(0, variable_index);
563 const ClpSimplex::Status clp_basis_status =
564 clp_->getColumnStatus(MPSolverVarIndexToClpVarIndex(variable_index));
565 return TransformCLPBasisStatus(clp_basis_status);
574 void CLPInterface::ResetParameters() {
579 void CLPInterface::SetRelativeMipGap(
double value) {
580 LOG(WARNING) <<
"The relative MIP gap is only available "
581 <<
"for discrete problems.";
584 void CLPInterface::SetPrimalTolerance(
double value) {
585 clp_->setPrimalTolerance(
value);
588 void CLPInterface::SetDualTolerance(
double value) {
589 clp_->setDualTolerance(
value);
592 void CLPInterface::SetPresolveMode(
int value) {
595 options_->setPresolveType(ClpSolve::presolveOff);
599 options_->setPresolveType(ClpSolve::presolveOn);
608 void CLPInterface::SetScalingMode(
int value) {
612 void CLPInterface::SetLpAlgorithm(
int value) {
615 options_->setSolveType(ClpSolve::useDual);
619 options_->setSolveType(ClpSolve::usePrimal);
623 options_->setSolveType(ClpSolve::useBarrier);
638 #endif // #if defined(USE_CBC) || defined(USE_CLP)