15#if defined(USE_CLP) || defined(USE_CBC)
23#include "absl/base/attributes.h"
24#include "absl/memory/memory.h"
25#include "absl/strings/match.h"
26#include "absl/strings/str_format.h"
36#include "ClpMessage.hpp"
37#include "ClpSimplex.hpp"
38#include "CoinBuild.hpp"
57 void Reset()
override;
70 double new_value,
double old_value)
override;
86 int64_t
nodes()
const override;
96 bool IsLP()
const override {
return true; }
97 bool IsMIP()
const override {
return false; }
106 return reinterpret_cast<void*
>(clp_.get());
111 void CreateDummyVariableForEmptyConstraints();
118 void ResetParameters();
120 void SetRelativeMipGap(
double value)
override;
121 void SetPrimalTolerance(
double value)
override;
122 void SetDualTolerance(
double value)
override;
123 void SetPresolveMode(
int value)
override;
124 void SetScalingMode(
int value)
override;
125 void SetLpAlgorithm(
int value)
override;
129 ClpSimplex::Status clp_basis_status)
const;
131 std::unique_ptr<ClpSimplex> clp_;
132 std::unique_ptr<ClpSolve> options_;
140 clp_->setStrParam(ClpProbName,
solver_->name_);
141 clp_->setOptimizationDirection(1);
147 clp_ = std::make_unique<ClpSimplex>();
148 clp_->setOptimizationDirection(
maximize_ ? -1 : 1);
163 clp_->setOptimizationDirection(maximize ? -1 : 1);
171 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(
var_index), lb, ub);
185 clp_->setRowBounds(
index, lb, ub);
193 double new_value,
double old_value) {
201 clp_->modifyCoefficient(constraint->
index(),
202 MPSolverVarIndexToClpVarIndex(variable->
index()),
216 for (
const auto& entry : constraint->coefficients_) {
218 clp_->modifyCoefficient(constraint->
index(),
219 MPSolverVarIndexToClpVarIndex(entry.first->index()),
229 clp_->setObjectiveCoefficient(
241 clp_->setObjectiveOffset(-offset);
248 for (
const auto& entry :
solver_->objective_->coefficients_) {
249 const int mpsolver_var_index = entry.first->index();
254 clp_->setObjectiveCoefficient(
255 MPSolverVarIndexToClpVarIndex(mpsolver_var_index), 0.0);
259 clp_->setObjectiveOffset(0.0);
270void CLPInterface::CreateDummyVariableForEmptyConstraints() {
276 std::string dummy =
"dummy";
283 int total_num_vars =
solver_->variables_.size();
287 clp_->resize(0, total_num_vars + 1);
288 CreateDummyVariableForEmptyConstraints();
289 for (
int i = 0; i < total_num_vars; ++i) {
292 if (!
var->name().empty()) {
293 std::string
name =
var->name();
294 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(i),
name);
296 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(i),
var->lb(),
310 double tmp_obj_coef = 0.0;
311 clp_->addColumn(0,
nullptr,
nullptr,
var->lb(),
var->ub(),
313 if (!
var->name().empty()) {
314 std::string
name =
var->name();
315 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(j),
name);
322 for (
const auto& entry :
ct->coefficients_) {
323 const int mpsolver_var_index = entry.first->index();
326 clp_->modifyCoefficient(
327 ct_index, MPSolverVarIndexToClpVarIndex(mpsolver_var_index),
338 int total_num_rows =
solver_->constraints_.size();
341 int max_row_length = 0;
346 if (
ct->coefficients_.size() > max_row_length) {
347 max_row_length =
ct->coefficients_.size();
351 max_row_length = std::max(1, max_row_length);
352 std::unique_ptr<int[]> indices(
new int[max_row_length]);
353 std::unique_ptr<double[]> coefs(
new double[max_row_length]);
354 CoinBuild build_object;
359 int size =
ct->coefficients_.size();
367 for (
const auto& entry :
ct->coefficients_) {
368 const int mpsolver_var_index = entry.first->index();
370 indices[j] = MPSolverVarIndexToClpVarIndex(mpsolver_var_index);
371 coefs[j] = entry.second;
374 build_object.addRow(
size, indices.get(), coefs.get(),
ct->lb(),
ct->ub());
377 clp_->addRows(build_object);
380 if (!
ct->name().empty()) {
381 std::string
name =
ct->name();
382 clp_->setRowName(
ct->index(),
name);
391 for (
const auto& entry :
solver_->objective_->coefficients_) {
392 clp_->setObjectiveCoefficient(
393 MPSolverVarIndexToClpVarIndex(entry.first->index()), entry.second);
413 CoinMessageHandler message_handler;
414 clp_->passInMessageHandler(&message_handler);
416 message_handler.setLogLevel(1, 0);
417 clp_->setLogLevel(0);
419 message_handler.setLogLevel(1, 1);
420 clp_->setLogLevel(1);
425 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
433 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
440 clp_->setMaximumSeconds(-1.0);
445 options_ = std::make_unique<ClpSolve>();
446 SetParameters(param);
450 clp_->initialSolve(*options_);
451 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
454 int tmp_status = clp_->status();
455 VLOG(1) <<
"clp result status: " << tmp_status;
456 switch (tmp_status) {
457 case CLP_SIMPLEX_FINISHED:
460 case CLP_SIMPLEX_INFEASIBLE:
463 case CLP_SIMPLEX_UNBOUNDED:
466 case CLP_SIMPLEX_STOPPED:
479 const double*
const values = clp_->getColSolution();
480 const double*
const reduced_costs = clp_->getReducedCost();
481 for (
int i = 0; i <
solver_->variables_.size(); ++i) {
483 const int clp_var_index = MPSolverVarIndexToClpVarIndex(
var->index());
484 const double val = values[clp_var_index];
485 var->set_solution_value(val);
486 VLOG(3) <<
var->name() <<
": value = " << val;
487 double reduced_cost = reduced_costs[clp_var_index];
488 var->set_reduced_cost(reduced_cost);
489 VLOG(4) <<
var->name() <<
": reduced cost = " << reduced_cost;
491 const double*
const dual_values = clp_->getRowPrice();
492 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
496 ct->set_dual_value(dual_value);
497 VLOG(4) <<
"row " <<
ct->index() <<
" dual value = " << dual_value;
504 }
catch (CoinError& e) {
505 LOG(WARNING) <<
"Caught exception in Coin LP: " << e.message();
512 ClpSimplex::Status clp_basis_status)
const {
513 switch (clp_basis_status) {
514 case ClpSimplex::isFree:
516 case ClpSimplex::basic:
518 case ClpSimplex::atUpperBound:
520 case ClpSimplex::atLowerBound:
522 case ClpSimplex::superBasic:
524 case ClpSimplex::isFixed:
527 LOG(FATAL) <<
"Unknown CLP basis status";
536 return clp_->getIterationCount();
540 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
547 const ClpSimplex::Status clp_basis_status =
549 return TransformCLPBasisStatus(clp_basis_status);
553 DCHECK_LE(0, variable_index);
555 const ClpSimplex::Status clp_basis_status =
556 clp_->getColumnStatus(MPSolverVarIndexToClpVarIndex(variable_index));
557 return TransformCLPBasisStatus(clp_basis_status);
566void CLPInterface::ResetParameters() {
571void CLPInterface::SetRelativeMipGap(
double value) {
572 LOG(WARNING) <<
"The relative MIP gap is only available "
573 <<
"for discrete problems.";
576void CLPInterface::SetPrimalTolerance(
double value) {
577 clp_->setPrimalTolerance(
value);
580void CLPInterface::SetDualTolerance(
double value) {
581 clp_->setDualTolerance(
value);
584void CLPInterface::SetPresolveMode(
int value) {
587 options_->setPresolveType(ClpSolve::presolveOff);
591 options_->setPresolveType(ClpSolve::presolveOn);
600void CLPInterface::SetScalingMode(
int value) {
604void CLPInterface::SetLpAlgorithm(
int value) {
607 options_->setSolveType(ClpSolve::useDual);
611 options_->setSolveType(ClpSolve::usePrimal);
615 options_->setSolveType(ClpSolve::useBarrier);
void Start()
When Start() is called multiple times, only the most recent is used.
int64_t iterations() const override
---— Query statistics on the solution and the solve ---—
int64_t nodes() const override
Number of branch-and-bound nodes. Only available for discrete problems.
MPSolver::BasisStatus row_status(int constraint_index) const override
Returns the basis status of a row.
CLPInterface(MPSolver *solver)
Constructor that takes a name for the underlying CLP solver.
void ClearConstraint(MPConstraint *constraint) override
Clear a constraint from all its terms.
void ExtractNewConstraints() override
Define new constraints on old and new variables.
void SetVariableBounds(int var_index, double lb, double ub) override
Modify bounds.
void ClearObjective() override
Clear the objective from all its terms.
MPSolver::BasisStatus column_status(int variable_index) const override
Returns the basis status of a column.
void AddRowConstraint(MPConstraint *ct) override
Add constraint incrementally.
void SetObjectiveOffset(double offset) override
Change the constant term in the linear objective.
void * underlying_solver() override
Returns the underlying solver.
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
Change a coefficient in a constraint.
void AddVariable(MPVariable *var) override
Add variable incrementally.
bool IsContinuous() const override
bool IsMIP() const override
Returns true if the problem is discrete and linear.
bool IsLP() const override
Returns true if the problem is continuous and linear.
std::string SolverVersion() const override
Returns a string describing the underlying solver and its version.
void SetConstraintBounds(int row_index, double lb, double ub) override
Modify bounds of an extracted variable.
void SetOptimizationDirection(bool maximize) override
Sets the optimization direction (min/max).
void SetVariableInteger(int var_index, bool integer) override
Ignore as CLP does not solve models with integer variables.
void ExtractNewVariables() override
Define new variables and add them to existing constraints.
void ExtractObjective() override
Extracts the objective.
MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override
Extracts model and solve the LP/MIP. Returns the status of the search.
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
Change a coefficient in the linear objective.
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
double offset() const
Gets the constant term in the objective.
void set_variable_as_extracted(int var_index, bool extracted)
bool CheckSolutionIsSynchronized() const
static constexpr int64_t kUnknownNumberOfIterations
void InvalidateSolutionSynchronization()
void set_constraint_as_extracted(int ct_index, bool extracted)
void ResetExtractionInformation()
Resets the extraction information.
int last_variable_index_
Index in MPSolver::constraints_ of last variable extracted.
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
Sets a supported integer parameter to an unsupported value.
int last_constraint_index_
Index in MPSolver::variables_ of last constraint extracted.
static const int kDummyVariableIndex
-------— MPSolverInterface -------—
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
Sets an unsupported integer parameter.
bool variable_is_extracted(int var_index) const
bool constraint_is_extracted(int ct_index) const
static constexpr int64_t kUnknownNumberOfNodes
void ExtractModel()
Extracts model stored in MPSolver.
double objective_value_
The value of the objective function.
bool maximize_
Optimization direction.
bool quiet_
Boolean indicator for the verbosity of the solver output.
void SetCommonParameters(const MPSolverParameters ¶m)
Sets parameters common to LP and MIP in the underlying solver.
MPSolver::ResultStatus result_status_
SynchronizationStatus sync_status_
Indicates whether the model and the solution are synchronized.
static const double kDefaultDualTolerance
static const double kDefaultPrimalTolerance
For the primal and dual tolerances, choose the same default as CLP and GLPK.
@ PRESOLVE_OFF
Presolve is off.
@ PRESOLVE_ON
Presolve is on.
@ BARRIER
Barrier algorithm.
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
@ PRESOLVE
Advanced usage: presolve mode.
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
@ INCREMENTALITY_OFF
Start solve from scratch.
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
int64_t time_limit() const
double time_limit_in_secs() const
@ FEASIBLE
feasible, or stopped by limit.
@ INFEASIBLE
proven infeasible.
@ UNBOUNDED
proven unbounded.
@ ABNORMAL
abnormal, i.e., error of some kind.
const MPObjective & Objective() const
The class for variables of a Mathematical Programming (MP) model.
int index() const
Returns the index of the variable in the MPSolver::variables_.
const std::string name
A name for logging purposes.
In SWIG mode, we don't want anything besides these top-level includes.
MPSolverInterface * BuildCLPInterface(MPSolver *const solver)