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)
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);
159int 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);
272void 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);
568void CLPInterface::ResetParameters() {
573void CLPInterface::SetRelativeMipGap(
double value) {
574 LOG(
WARNING) <<
"The relative MIP gap is only available "
575 <<
"for discrete problems.";
578void CLPInterface::SetPrimalTolerance(
double value) {
579 clp_->setPrimalTolerance(
value);
582void CLPInterface::SetDualTolerance(
double value) {
583 clp_->setDualTolerance(
value);
586void CLPInterface::SetPresolveMode(
int value) {
589 options_->setPresolveType(ClpSolve::presolveOff);
593 options_->setPresolveType(ClpSolve::presolveOn);
602void CLPInterface::SetScalingMode(
int value) {
606void 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 ExtractObjective() override
void * underlying_solver() 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 ...
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
const MPObjective & Objective() const
Returns the objective object.
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)