24#include "absl/base/attributes.h"
25#include "absl/status/status.h"
26#include "absl/strings/str_format.h"
36#include "CbcMessage.hpp"
37#include "CbcModel.hpp"
38#include "CoinModel.hpp"
39#include "OsiClpSolverInterface.hpp"
52 void Reset()
override;
60 CHECK_GE(num_threads, 1);
61 num_threads_ = num_threads;
62 return absl::OkStatus();
74 bool IsLP()
const override {
return false; }
75 bool IsMIP()
const override {
return true; }
88 const MPVariable*
const variable,
double new_value,
89 double old_value)
override {
99 double coefficient)
override {
110 int64_t
nodes()
const override;
114 LOG(FATAL) <<
"Basis status only available for continuous problems";
119 LOG(FATAL) <<
"Basis status only available for continuous problems";
137 void ResetBestObjectiveBound();
142 void SetRelativeMipGap(
double value)
override;
143 void SetPrimalTolerance(
double value)
override;
144 void SetDualTolerance(
double value)
override;
145 void SetPresolveMode(
int value)
override;
146 void SetScalingMode(
int value)
override;
147 void SetLpAlgorithm(
int value)
override;
149 OsiClpSolverInterface osi_;
154 double relative_mip_gap_;
155 int num_threads_ = 1;
166 osi_.setStrParam(OsiProbName,
solver_->name_);
176 osi_.setStrParam(OsiProbName,
solver_->name_);
180void CBCInterface::ResetBestObjectiveBound() {
191 osi_.setObjSense(maximize ? -1 : 1);
199int MPSolverVarIndexToCbcVarIndex(
int var_index) {
return var_index + 1; }
205 osi_.setColBounds(MPSolverVarIndexToCbcVarIndex(var_index), lb, ub);
216 osi_.setInteger(MPSolverVarIndexToCbcVarIndex(var_index));
218 osi_.setContinuous(MPSolverVarIndexToCbcVarIndex(var_index));
228 osi_.setRowBounds(index, lb, ub);
248 if (!
solver_->variables_.empty()) {
251 if (!
solver_->constraints_.empty()) {
252 solver_->LookupConstraintOrNull(
solver_->constraints_[0]->name());
266 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
281 build.addColumn(0,
nullptr,
nullptr, 1.0, 1.0,
282 solver_->Objective().offset(),
"dummy",
false);
283 const int nb_vars =
solver_->variables_.size();
284 for (
int i = 0; i < nb_vars; ++i) {
287 const double obj_coeff =
solver_->Objective().GetCoefficient(var);
288 if (var->
name().empty()) {
289 build.addColumn(0,
nullptr,
nullptr, var->
lb(), var->
ub(), obj_coeff,
292 build.addColumn(0,
nullptr,
nullptr, var->
lb(), var->
ub(), obj_coeff,
298 int max_row_length = 0;
299 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
302 if (ct->coefficients_.size() > max_row_length) {
303 max_row_length = ct->coefficients_.size();
306 std::unique_ptr<int[]> indices(
new int[max_row_length]);
307 std::unique_ptr<double[]> coefs(
new double[max_row_length]);
309 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
311 const int size = ct->coefficients_.size();
313 for (
const auto& entry : ct->coefficients_) {
314 const int index = MPSolverVarIndexToCbcVarIndex(entry.first->index());
316 coefs[j] = entry.second;
319 if (ct->
name().empty()) {
320 build.addRow(size, indices.get(), coefs.get(), ct->
lb(), ct->
ub());
322 build.addRow(size, indices.get(), coefs.get(), ct->
lb(), ct->
ub(),
326 osi_.loadFromCoinModel(build);
342 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
344 ResetBestObjectiveBound();
347 CbcModel model(osi_);
350 CoinMessageHandler message_handler;
351 model.passInMessageHandler(&message_handler);
353 message_handler.setLogLevel(0, 0);
354 message_handler.setLogLevel(1, 0);
355 message_handler.setLogLevel(2, 0);
356 message_handler.setLogLevel(3, 0);
358 message_handler.setLogLevel(0, 1);
359 message_handler.setLogLevel(1, 1);
360 message_handler.setLogLevel(2, 1);
361 message_handler.setLogLevel(3, 1);
365 if (
solver_->time_limit() != 0) {
366 VLOG(1) <<
"Setting time limit = " <<
solver_->time_limit() <<
" ms.";
367 model.setMaximumSeconds(
solver_->time_limit_in_secs());
376 SetParameters(param);
379 model.setTypePresolve(0);
382 model.setAllowableFractionGap(relative_mip_gap_);
386 ? callCbc(
"-solve ", model)
387 : callCbc(absl::StrCat(
"-threads ", num_threads_,
" -solve "), model);
388 const int kBadReturnStatus = 777;
389 CHECK_NE(kBadReturnStatus, return_status);
392 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
395 int tmp_status = model.status();
397 VLOG(1) <<
"cbc result status: " << tmp_status;
410 switch (tmp_status) {
414 if (model.isProvenOptimal()) {
416 }
else if (model.isContinuousUnbounded()) {
418 }
else if (model.isProvenInfeasible()) {
420 }
else if (model.isAbandoned()) {
427 if (model.bestSolution() !=
nullptr) {
443 const double*
const values = model.bestSolution();
444 if (values !=
nullptr) {
446 for (
int i = 0; i <
solver_->variables_.size(); ++i) {
448 const int var_index = MPSolverVarIndexToCbcVarIndex(var->
index());
449 const double val = values[var_index];
451 VLOG(3) << var->
name() <<
"=" << val;
454 VLOG(1) <<
"No feasible solution found.";
458 iterations_ = model.getIterationCount();
459 nodes_ = model.getNodeCount();
493void CBCInterface::SetRelativeMipGap(
double value) {
494 relative_mip_gap_ = value;
497void CBCInterface::SetPrimalTolerance(
double value) {
505void CBCInterface::SetDualTolerance(
double value) {
513void CBCInterface::SetPresolveMode(
int value) {
525void CBCInterface::SetScalingMode(
int value) {
529void CBCInterface::SetLpAlgorithm(
int value) {
void Start()
When Start() is called multiple times, only the most recent is used.
void SetConstraintBounds(int row_index, double lb, double ub) override
Modify bounds of an extracted variable.
MPSolver::BasisStatus row_status(int constraint_index) const override
Returns the basis status of a row.
void AddRowConstraint(MPConstraint *ct) override
Add constraint incrementally.
void ClearObjective() override
Clear the objective from all its terms.
void ClearConstraint(MPConstraint *const constraint) override
Clear a constraint from all its terms.
CBCInterface(MPSolver *solver)
Constructor that takes a name for the underlying glpk solver.
void ExtractNewConstraints() override
Extracts the constraints that have not been extracted yet.
void SetVariableBounds(int var_index, double lb, double ub) override
Modify bounds.
void ExtractNewVariables() override
Extracts the variables that have not been extracted yet.
absl::Status SetNumThreads(int num_threads) override
--— Parameters --—
int64_t nodes() const override
Number of branch-and-bound nodes. Only available for discrete problems.
void ExtractObjective() override
Extracts the objective.
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
Change a coefficient in the linear objective.
void SetOptimizationDirection(bool maximize) override
Sets the optimization direction (min/max).
MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override
void AddVariable(MPVariable *var) override
Add variable incrementally.
MPSolver::BasisStatus column_status(int variable_index) const override
Returns the basis status of a column.
bool IsLP() const override
Returns true if the problem is continuous and linear.
void Reset() override
--— Reset --—
int64_t iterations() const override
Number of simplex iterations.
bool IsMIP() const override
Returns true if the problem is discrete and linear.
void SetVariableInteger(int var_index, bool integer) override
Modifies integrality of an extracted variable.
std::string SolverVersion() const override
Returns a string describing the underlying solver and its version.
void SetObjectiveOffset(double value) override
Change the constant term in the linear objective.
bool IsContinuous() const override
Query problem type.
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
Change a coefficient in a constraint.
virtual void ExtractModel()
void * underlying_solver() override
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.
void set_variable_as_extracted(int var_index, bool extracted)
bool CheckSolutionIsSynchronized() const
static constexpr int64_t kUnknownNumberOfIterations
friend class MPConstraint
To access the maximize_ bool and the MPSolver.
void InvalidateSolutionSynchronization()
void set_constraint_as_extracted(int ct_index, bool extracted)
void ResetExtractionInformation()
Resets the extraction information.
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
Sets an unsupported integer parameter.
void SetUnsupportedDoubleParam(MPSolverParameters::DoubleParam param)
Sets an unsupported double parameter.
static constexpr int64_t kUnknownNumberOfNodes
double objective_value_
The value of the objective function.
double best_objective_bound_
The value of the best objective bound. Used only for MIP solvers.
bool maximize_
Optimization direction.
void SetMIPParameters(const MPSolverParameters ¶m)
Sets MIP specific parameters in the underlying solver.
MPSolverInterface(MPSolver *solver)
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.
@ DUAL_TOLERANCE
Advanced usage: tolerance for dual feasibility of basic solutions.
@ PRESOLVE_ON
Presolve is on.
@ 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.
@ NOT_SOLVED
not been solved yet.
@ INFEASIBLE
proven infeasible.
@ UNBOUNDED
proven unbounded.
@ ABNORMAL
abnormal, i.e., error of some kind.
The class for variables of a Mathematical Programming (MP) model.
bool integer() const
Returns the integrality requirement of the variable.
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_solution_value(double value)
int index() const
Returns the index of the variable in the MPSolver::variables_.
In SWIG mode, we don't want anything besides these top-level includes.
MPSolverInterface * BuildCBCInterface(MPSolver *const solver)