22 #include "absl/memory/memory.h"
23 #include "absl/strings/match.h"
24 #include "absl/strings/str_format.h"
32 #if defined(USE_CLP) || defined(USE_CBC)
36 #include "ClpConfig.h"
37 #include "ClpMessage.hpp"
38 #include "ClpSimplex.hpp"
39 #include "CoinBuild.hpp"
58 void Reset()
override;
71 const MPVariable*
const variable,
double new_value,
72 double old_value)
override;
88 int64_t
nodes()
const override;
98 bool IsLP()
const override {
return true; }
99 bool IsMIP()
const override {
return false; }
108 return reinterpret_cast<void*
>(clp_.get());
113 void CreateDummyVariableForEmptyConstraints();
120 void ResetParameters();
122 void SetRelativeMipGap(
double value)
override;
123 void SetPrimalTolerance(
double value)
override;
124 void SetDualTolerance(
double value)
override;
125 void SetPresolveMode(
int value)
override;
126 void SetScalingMode(
int value)
override;
127 void SetLpAlgorithm(
int value)
override;
131 ClpSimplex::Status clp_basis_status)
const;
133 std::unique_ptr<ClpSimplex> clp_;
134 std::unique_ptr<ClpSolve> options_;
142 clp_->setStrParam(ClpProbName,
solver_->name_);
143 clp_->setOptimizationDirection(1);
149 clp_ = absl::make_unique<ClpSimplex>();
150 clp_->setOptimizationDirection(
maximize_ ? -1 : 1);
159 int MPSolverVarIndexToClpVarIndex(
int var_index) {
return var_index + 1; }
165 clp_->setOptimizationDirection(maximize ? -1 : 1);
173 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(var_index), lb, ub);
187 clp_->setRowBounds(
index, lb, ub);
195 double new_value,
double old_value) {
203 clp_->modifyCoefficient(constraint->
index(),
204 MPSolverVarIndexToClpVarIndex(variable->
index()),
218 for (
const auto& entry : constraint->coefficients_) {
220 clp_->modifyCoefficient(constraint->
index(),
221 MPSolverVarIndexToClpVarIndex(entry.first->index()),
231 clp_->setObjectiveCoefficient(
243 clp_->setObjectiveOffset(-offset);
250 for (
const auto& entry :
solver_->objective_->coefficients_) {
251 const int mpsolver_var_index = entry.first->index();
256 clp_->setObjectiveCoefficient(
257 MPSolverVarIndexToClpVarIndex(mpsolver_var_index), 0.0);
261 clp_->setObjectiveOffset(0.0);
272 void CLPInterface::CreateDummyVariableForEmptyConstraints() {
278 std::string dummy =
"dummy";
285 int total_num_vars =
solver_->variables_.size();
289 clp_->resize(0, total_num_vars + 1);
290 CreateDummyVariableForEmptyConstraints();
291 for (
int i = 0; i < total_num_vars; ++i) {
294 if (!
var->name().empty()) {
295 std::string
name =
var->name();
296 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(i),
name);
298 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(i),
var->lb(),
312 double tmp_obj_coef = 0.0;
313 clp_->addColumn(0,
nullptr,
nullptr,
var->lb(),
var->ub(),
315 if (!
var->name().empty()) {
316 std::string
name =
var->name();
317 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(j),
name);
323 const int ct_index =
ct->index();
324 for (
const auto& entry :
ct->coefficients_) {
325 const int mpsolver_var_index = entry.first->index();
328 clp_->modifyCoefficient(
329 ct_index, MPSolverVarIndexToClpVarIndex(mpsolver_var_index),
340 int total_num_rows =
solver_->constraints_.size();
343 int max_row_length = 0;
348 if (
ct->coefficients_.size() > max_row_length) {
349 max_row_length =
ct->coefficients_.size();
353 max_row_length =
std::max(1, max_row_length);
354 std::unique_ptr<int[]> indices(
new int[max_row_length]);
355 std::unique_ptr<double[]> coefs(
new double[max_row_length]);
356 CoinBuild build_object;
361 int size =
ct->coefficients_.size();
369 for (
const auto& entry :
ct->coefficients_) {
370 const int mpsolver_var_index = entry.first->index();
372 indices[j] = MPSolverVarIndexToClpVarIndex(mpsolver_var_index);
373 coefs[j] = entry.second;
376 build_object.addRow(size, indices.get(), coefs.get(),
ct->lb(),
ct->ub());
379 clp_->addRows(build_object);
382 if (!
ct->name().empty()) {
383 std::string
name =
ct->name();
384 clp_->setRowName(
ct->index(),
name);
393 for (
const auto& entry :
solver_->objective_->coefficients_) {
394 clp_->setObjectiveCoefficient(
395 MPSolverVarIndexToClpVarIndex(entry.first->index()), entry.second);
415 CoinMessageHandler message_handler;
416 clp_->passInMessageHandler(&message_handler);
418 message_handler.setLogLevel(1, 0);
419 clp_->setLogLevel(0);
421 message_handler.setLogLevel(1, 1);
422 clp_->setLogLevel(1);
427 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
435 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
442 clp_->setMaximumSeconds(-1.0);
447 options_ = absl::make_unique<ClpSolve>();
448 SetParameters(param);
452 clp_->initialSolve(*options_);
453 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
456 int tmp_status = clp_->status();
457 VLOG(1) <<
"clp result status: " << tmp_status;
458 switch (tmp_status) {
459 case CLP_SIMPLEX_FINISHED:
462 case CLP_SIMPLEX_INFEASIBLE:
465 case CLP_SIMPLEX_UNBOUNDED:
468 case CLP_SIMPLEX_STOPPED:
481 const double*
const values = clp_->getColSolution();
482 const double*
const reduced_costs = clp_->getReducedCost();
483 for (
int i = 0; i <
solver_->variables_.size(); ++i) {
485 const int clp_var_index = MPSolverVarIndexToClpVarIndex(
var->index());
486 const double val = values[clp_var_index];
487 var->set_solution_value(val);
488 VLOG(3) <<
var->name() <<
": value = " << val;
489 double reduced_cost = reduced_costs[clp_var_index];
490 var->set_reduced_cost(reduced_cost);
491 VLOG(4) <<
var->name() <<
": reduced cost = " << reduced_cost;
493 const double*
const dual_values = clp_->getRowPrice();
494 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
496 const int constraint_index =
ct->index();
497 const double dual_value = dual_values[constraint_index];
498 ct->set_dual_value(dual_value);
499 VLOG(4) <<
"row " <<
ct->index() <<
" dual value = " << dual_value;
506 }
catch (CoinError& e) {
507 LOG(
WARNING) <<
"Caught exception in Coin LP: " << e.message();
514 ClpSimplex::Status clp_basis_status)
const {
515 switch (clp_basis_status) {
516 case ClpSimplex::isFree:
518 case ClpSimplex::basic:
520 case ClpSimplex::atUpperBound:
522 case ClpSimplex::atLowerBound:
524 case ClpSimplex::superBasic:
526 case ClpSimplex::isFixed:
529 LOG(
FATAL) <<
"Unknown CLP basis status";
538 return clp_->getIterationCount();
542 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
549 const ClpSimplex::Status clp_basis_status =
550 clp_->getRowStatus(constraint_index);
551 return TransformCLPBasisStatus(clp_basis_status);
557 const ClpSimplex::Status clp_basis_status =
558 clp_->getColumnStatus(MPSolverVarIndexToClpVarIndex(variable_index));
559 return TransformCLPBasisStatus(clp_basis_status);
568 void CLPInterface::ResetParameters() {
573 void CLPInterface::SetRelativeMipGap(
double value) {
574 LOG(
WARNING) <<
"The relative MIP gap is only available "
575 <<
"for discrete problems.";
578 void CLPInterface::SetPrimalTolerance(
double value) {
579 clp_->setPrimalTolerance(
value);
582 void CLPInterface::SetDualTolerance(
double value) {
583 clp_->setDualTolerance(
value);
586 void CLPInterface::SetPresolveMode(
int value) {
589 options_->setPresolveType(ClpSolve::presolveOff);
593 options_->setPresolveType(ClpSolve::presolveOn);
602 void CLPInterface::SetScalingMode(
int value) {
606 void CLPInterface::SetLpAlgorithm(
int value) {
609 options_->setSolveType(ClpSolve::useDual);
613 options_->setSolveType(ClpSolve::usePrimal);
617 options_->setSolveType(ClpSolve::useBarrier);
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
void AddRowConstraint(MPConstraint *const ct) override
void * underlying_solver() override
void ExtractObjective() override
bool IsContinuous() const override
void SetConstraintBounds(int row_index, double lb, double ub) override
MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override
void ClearConstraint(MPConstraint *const constraint) override
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
MPSolver::BasisStatus row_status(int constraint_index) const override
CLPInterface(MPSolver *const solver)
void SetVariableInteger(int var_index, bool integer) override
void ExtractNewConstraints() override
void SetObjectiveOffset(double offset) override
std::string SolverVersion() const override
void AddVariable(MPVariable *const var) override
void ExtractNewVariables() override
int64_t nodes() const override
void SetVariableBounds(int var_index, double lb, double ub) override
bool IsLP() const override
bool IsMIP() const override
int64_t iterations() const override
void SetOptimizationDirection(bool maximize) override
MPSolver::BasisStatus column_status(int variable_index) const override
void ClearObjective() override
The class for constraints of a Mathematical Programming (MP) model.
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
double offset() const
Gets the constant term in the objective.
This mathematical programming (MP) solver class is the main class though which users build and solve ...
const MPObjective & Objective() const
Returns the objective object.
ResultStatus
The status of solving the problem.
@ FEASIBLE
feasible, or stopped by limit.
@ INFEASIBLE
proven infeasible.
@ UNBOUNDED
proven unbounded.
@ ABNORMAL
abnormal, i.e., error of some kind.
int64_t time_limit() const
double time_limit_in_secs() const
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
void set_constraint_as_extracted(int ct_index, bool extracted)
MPSolver::ResultStatus result_status_
static const int kDummyVariableIndex
void InvalidateSolutionSynchronization()
int last_constraint_index_
bool constraint_is_extracted(int ct_index) const
static constexpr int64_t kUnknownNumberOfNodes
bool CheckSolutionIsSynchronized() const
void ResetExtractionInformation()
bool variable_is_extracted(int var_index) const
static constexpr int64_t kUnknownNumberOfIterations
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
void set_variable_as_extracted(int var_index, bool extracted)
void SetCommonParameters(const MPSolverParameters ¶m)
SynchronizationStatus sync_status_
This class stores parameter settings for LP and MIP solvers.
@ INCREMENTALITY_OFF
Start solve from scratch.
static const double kDefaultDualTolerance
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
@ PRESOLVE
Advanced usage: presolve mode.
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
@ BARRIER
Barrier algorithm.
@ PRESOLVE_ON
Presolve is on.
@ PRESOLVE_OFF
Presolve is off.
static const double kDefaultPrimalTolerance
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
The class for variables of a Mathematical Programming (MP) model.
int index() const
Returns the index of the variable in the MPSolver::variables_.
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
Collection of objects used to extend the Constraint Solver library.
MPSolverInterface * BuildCLPInterface(MPSolver *const solver)