22#include "absl/base/attributes.h"
23#include "absl/memory/memory.h"
24#include "absl/strings/match.h"
25#include "absl/strings/str_format.h"
33#if defined(USE_CLP) || defined(USE_CBC)
38#include "ClpMessage.hpp"
39#include "ClpSimplex.hpp"
40#include "CoinBuild.hpp"
59 void Reset()
override;
72 const MPVariable*
const variable,
double new_value,
73 double old_value)
override;
89 int64_t
nodes()
const 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);
160int 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);
273void 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";
550 const ClpSimplex::Status clp_basis_status =
551 clp_->getRowStatus(constraint_index);
552 return TransformCLPBasisStatus(clp_basis_status);
558 const ClpSimplex::Status clp_basis_status =
559 clp_->getColumnStatus(MPSolverVarIndexToClpVarIndex(variable_index));
560 return TransformCLPBasisStatus(clp_basis_status);
569void CLPInterface::ResetParameters() {
574void CLPInterface::SetRelativeMipGap(
double value) {
575 LOG(
WARNING) <<
"The relative MIP gap is only available "
576 <<
"for discrete problems.";
579void CLPInterface::SetPrimalTolerance(
double value) {
580 clp_->setPrimalTolerance(
value);
583void CLPInterface::SetDualTolerance(
double value) {
584 clp_->setDualTolerance(
value);
587void CLPInterface::SetPresolveMode(
int value) {
590 options_->setPresolveType(ClpSolve::presolveOff);
594 options_->setPresolveType(ClpSolve::presolveOn);
603void CLPInterface::SetScalingMode(
int value) {
607void CLPInterface::SetLpAlgorithm(
int value) {
610 options_->setSolveType(ClpSolve::useDual);
614 options_->setSolveType(ClpSolve::usePrimal);
618 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)