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 {
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);
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()) {
266 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
281 build.addColumn(0,
nullptr,
nullptr, 1.0, 1.0,
283 const int nb_vars =
solver_->variables_.size();
284 for (
int i = 0; i < nb_vars; ++i) {
288 if (
var->name().empty()) {
289 build.addColumn(0,
nullptr,
nullptr,
var->lb(),
var->ub(), obj_coeff,
290 nullptr,
var->integer());
292 build.addColumn(0,
nullptr,
nullptr,
var->lb(),
var->ub(), obj_coeff,
293 var->name().c_str(),
var->integer());
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);
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());
450 var->set_solution_value(val);
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 GetCoefficient(const MPVariable *var) const
--— MPObjective --—
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.
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.
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.
int64_t time_limit() const
double time_limit_in_secs() const
@ 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.
const MPObjective & Objective() const
MPConstraint * LookupConstraintOrNull(const std::string &constraint_name) const
MPVariable * LookupVariableOrNull(const std::string &var_name) const
The class for variables of a Mathematical Programming (MP) model.
In SWIG mode, we don't want anything besides these top-level includes.
MPSolverInterface * BuildCBCInterface(MPSolver *const solver)