20#include "absl/base/attributes.h"
21#include "absl/strings/str_format.h"
29#include "ClpMessage.hpp"
30#include "ClpSimplex.hpp"
31#include "CoinBuild.hpp"
50 void Reset()
override;
63 double new_value,
double old_value)
override;
69 double coefficient)
override;
79 int64_t
nodes()
const override;
89 bool IsLP()
const override {
return true; }
90 bool IsMIP()
const override {
return false; }
96 std::string
SolverVersion()
const override {
return "Clp " CLP_VERSION; }
99 return reinterpret_cast<void*
>(clp_.get());
104 void CreateDummyVariableForEmptyConstraints();
111 void ResetParameters();
113 void SetRelativeMipGap(
double value)
override;
114 void SetPrimalTolerance(
double value)
override;
115 void SetDualTolerance(
double value)
override;
116 void SetPresolveMode(
int value)
override;
117 void SetScalingMode(
int value)
override;
118 void SetLpAlgorithm(
int value)
override;
122 ClpSimplex::Status clp_basis_status)
const;
124 std::unique_ptr<ClpSimplex> clp_;
125 std::unique_ptr<ClpSolve> options_;
133 clp_->setStrParam(ClpProbName,
solver_->name_);
134 clp_->setOptimizationDirection(1);
140 clp_ = std::make_unique<ClpSimplex>();
141 clp_->setOptimizationDirection(
maximize_ ? -1 : 1);
150int MPSolverVarIndexToClpVarIndex(
int var_index) {
return var_index + 1; }
156 clp_->setOptimizationDirection(maximize ? -1 : 1);
164 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(var_index), lb, ub);
178 clp_->setRowBounds(index, lb, ub);
186 double new_value,
double old_value) {
194 clp_->modifyCoefficient(constraint->
index(),
195 MPSolverVarIndexToClpVarIndex(variable->
index()),
209 for (
const auto& entry : constraint->coefficients_) {
211 clp_->modifyCoefficient(constraint->
index(),
212 MPSolverVarIndexToClpVarIndex(entry.first->index()),
219 double coefficient) {
222 clp_->setObjectiveCoefficient(
223 MPSolverVarIndexToClpVarIndex(variable->
index()), coefficient);
234 clp_->setObjectiveOffset(-offset);
241 for (
const auto& entry :
solver_->objective_->coefficients_) {
242 const int mpsolver_var_index = entry.first->index();
247 clp_->setObjectiveCoefficient(
248 MPSolverVarIndexToClpVarIndex(mpsolver_var_index), 0.0);
252 clp_->setObjectiveOffset(0.0);
263void CLPInterface::CreateDummyVariableForEmptyConstraints() {
269 std::string dummy =
"dummy";
276 int total_num_vars =
solver_->variables_.size();
280 clp_->resize(0, total_num_vars + 1);
281 CreateDummyVariableForEmptyConstraints();
282 for (
int i = 0; i < total_num_vars; ++i) {
285 if (!var->
name().empty()) {
286 std::string name = var->
name();
287 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(i), name);
289 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(i), var->
lb(),
303 double tmp_obj_coef = 0.0;
304 clp_->addColumn(0,
nullptr,
nullptr, var->
lb(), var->
ub(),
306 if (!var->
name().empty()) {
307 std::string name = var->
name();
308 clp_->setColumnName(MPSolverVarIndexToClpVarIndex(j), name);
314 const int ct_index = ct->
index();
315 for (
const auto& entry : ct->coefficients_) {
316 const int mpsolver_var_index = entry.first->index();
319 clp_->modifyCoefficient(
320 ct_index, MPSolverVarIndexToClpVarIndex(mpsolver_var_index),
331 int total_num_rows =
solver_->constraints_.size();
334 int max_row_length = 0;
339 if (ct->coefficients_.size() > max_row_length) {
340 max_row_length = ct->coefficients_.size();
344 max_row_length = std::max(1, max_row_length);
345 std::unique_ptr<int[]> indices(
new int[max_row_length]);
346 std::unique_ptr<double[]> coefs(
new double[max_row_length]);
347 CoinBuild build_object;
352 int size = ct->coefficients_.size();
360 for (
const auto& entry : ct->coefficients_) {
361 const int mpsolver_var_index = entry.first->index();
363 indices[j] = MPSolverVarIndexToClpVarIndex(mpsolver_var_index);
364 coefs[j] = entry.second;
367 build_object.addRow(size, indices.get(), coefs.get(), ct->
lb(), ct->
ub());
370 clp_->addRows(build_object);
373 if (!ct->
name().empty()) {
374 std::string name = ct->
name();
375 clp_->setRowName(ct->
index(), name);
384 for (
const auto& entry :
solver_->objective_->coefficients_) {
385 clp_->setObjectiveCoefficient(
386 MPSolverVarIndexToClpVarIndex(entry.first->index()), entry.second);
391 clp_->setObjectiveOffset(-
solver_->Objective().offset());
406 CoinMessageHandler message_handler;
407 clp_->passInMessageHandler(&message_handler);
409 message_handler.setLogLevel(1, 0);
410 clp_->setLogLevel(0);
412 message_handler.setLogLevel(1, 1);
413 clp_->setLogLevel(1);
418 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
426 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
429 if (
solver_->time_limit() != 0) {
430 VLOG(1) <<
"Setting time limit = " <<
solver_->time_limit() <<
" ms.";
431 clp_->setMaximumSeconds(
solver_->time_limit_in_secs());
433 clp_->setMaximumSeconds(-1.0);
438 options_ = std::make_unique<ClpSolve>();
439 SetParameters(param);
443 clp_->initialSolve(*options_);
444 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
447 int tmp_status = clp_->status();
448 VLOG(1) <<
"clp result status: " << tmp_status;
449 switch (tmp_status) {
450 case CLP_SIMPLEX_FINISHED:
453 case CLP_SIMPLEX_INFEASIBLE:
456 case CLP_SIMPLEX_UNBOUNDED:
459 case CLP_SIMPLEX_STOPPED:
472 const double*
const values = clp_->getColSolution();
473 const double*
const reduced_costs = clp_->getReducedCost();
474 for (
int i = 0; i <
solver_->variables_.size(); ++i) {
476 const int clp_var_index = MPSolverVarIndexToClpVarIndex(var->
index());
477 const double val = values[clp_var_index];
479 VLOG(3) << var->
name() <<
": value = " << val;
480 double reduced_cost = reduced_costs[clp_var_index];
482 VLOG(4) << var->
name() <<
": reduced cost = " << reduced_cost;
484 const double*
const dual_values = clp_->getRowPrice();
485 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
487 const int constraint_index = ct->
index();
488 const double dual_value = dual_values[constraint_index];
490 VLOG(4) <<
"row " << ct->
index() <<
" dual value = " << dual_value;
497 }
catch (CoinError& e) {
498 LOG(WARNING) <<
"Caught exception in Coin LP: " << e.message();
505 ClpSimplex::Status clp_basis_status)
const {
506 switch (clp_basis_status) {
507 case ClpSimplex::isFree:
509 case ClpSimplex::basic:
511 case ClpSimplex::atUpperBound:
513 case ClpSimplex::atLowerBound:
515 case ClpSimplex::superBasic:
517 case ClpSimplex::isFixed:
520 LOG(FATAL) <<
"Unknown CLP basis status";
529 return clp_->getIterationCount();
533 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
538 DCHECK_LE(0, constraint_index);
540 const ClpSimplex::Status clp_basis_status =
541 clp_->getRowStatus(constraint_index);
542 return TransformCLPBasisStatus(clp_basis_status);
546 DCHECK_LE(0, variable_index);
548 const ClpSimplex::Status clp_basis_status =
549 clp_->getColumnStatus(MPSolverVarIndexToClpVarIndex(variable_index));
550 return TransformCLPBasisStatus(clp_basis_status);
559void CLPInterface::ResetParameters() {
564void CLPInterface::SetRelativeMipGap(
double value) {
565 LOG(WARNING) <<
"The relative MIP gap is only available "
566 <<
"for discrete problems.";
569void CLPInterface::SetPrimalTolerance(
double value) {
570 clp_->setPrimalTolerance(value);
573void CLPInterface::SetDualTolerance(
double value) {
574 clp_->setDualTolerance(value);
577void CLPInterface::SetPresolveMode(
int value) {
580 options_->setPresolveType(ClpSolve::presolveOff);
584 options_->setPresolveType(ClpSolve::presolveOn);
593void CLPInterface::SetScalingMode(
int value) {
597void CLPInterface::SetLpAlgorithm(
int value) {
600 options_->setSolveType(ClpSolve::useDual);
604 options_->setSolveType(ClpSolve::usePrimal);
608 options_->setSolveType(ClpSolve::useBarrier);
621const void*
const kRegisterCLP ABSL_ATTRIBUTE_UNUSED = [] {
int64_t iterations() const override
int64_t nodes() const override
MPSolver::BasisStatus row_status(int constraint_index) const override
CLPInterface(MPSolver *solver)
void ClearConstraint(MPConstraint *constraint) override
void ExtractNewConstraints() override
void SetVariableBounds(int var_index, double lb, double ub) override
void ClearObjective() override
MPSolver::BasisStatus column_status(int variable_index) const override
void AddRowConstraint(MPConstraint *ct) override
void SetObjectiveOffset(double offset) override
void * underlying_solver() override
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
void AddVariable(MPVariable *var) override
bool IsContinuous() const override
bool IsMIP() const override
bool IsLP() const override
std::string SolverVersion() const override
void SetConstraintBounds(int row_index, double lb, double ub) override
void SetOptimizationDirection(bool maximize) override
void SetVariableInteger(int var_index, bool integer) override
void ExtractNewVariables() override
void ExtractObjective() override
MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
void set_dual_value(double dual_value)
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
const std::string & name() const
Returns the name of the constraint.
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
static MPSolverInterfaceFactoryRepository * GetInstance()
void Register(MPSolverInterfaceFactory factory, MPSolver::OptimizationProblemType problem_type, std::function< bool()> is_runtime_ready={})
void set_variable_as_extracted(int var_index, bool extracted)
bool CheckSolutionIsSynchronized() const
static constexpr int64_t kUnknownNumberOfIterations
friend class MPConstraint
void InvalidateSolutionSynchronization()
void set_constraint_as_extracted(int ct_index, bool extracted)
void ResetExtractionInformation()
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
int last_constraint_index_
static const int kDummyVariableIndex
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
bool variable_is_extracted(int var_index) const
bool constraint_is_extracted(int ct_index) const
static constexpr int64_t kUnknownNumberOfNodes
MPSolverInterface(MPSolver *solver)
void SetCommonParameters(const MPSolverParameters ¶m)
MPSolver::ResultStatus result_status_
SynchronizationStatus sync_status_
static const double kDefaultDualTolerance
static const double kDefaultPrimalTolerance
@ 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.
@ FEASIBLE
feasible, or stopped by limit.
@ INFEASIBLE
proven infeasible.
@ UNBOUNDED
proven unbounded.
@ ABNORMAL
abnormal, i.e., error of some kind.
The class for variables of a Mathematical Programming (MP) model.
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
const std::string & name() const
Returns the name of the variable.
void set_reduced_cost(double reduced_cost)
void set_solution_value(double value)
int index() const
Returns the index of the variable in the MPSolver::variables_.