21#include "absl/base/attributes.h"
22#include "absl/status/status.h"
23#include "absl/strings/str_format.h"
31#include "CbcMessage.hpp"
32#include "CbcModel.hpp"
33#include "CoinModel.hpp"
34#include "OsiClpSolverInterface.hpp"
47 void Reset()
override;
55 CHECK_GE(num_threads, 1);
56 num_threads_ = num_threads;
57 return absl::OkStatus();
69 bool IsLP()
const override {
return false; }
70 bool IsMIP()
const override {
return true; }
83 const MPVariable*
const variable,
double new_value,
84 double old_value)
override {
94 double coefficient)
override {
105 int64_t
nodes()
const override;
109 LOG(FATAL) <<
"Basis status only available for continuous problems";
114 LOG(FATAL) <<
"Basis status only available for continuous problems";
132 void ResetBestObjectiveBound();
137 void SetRelativeMipGap(
double value)
override;
138 void SetPrimalTolerance(
double value)
override;
139 void SetDualTolerance(
double value)
override;
140 void SetPresolveMode(
int value)
override;
141 void SetScalingMode(
int value)
override;
142 void SetLpAlgorithm(
int value)
override;
144 OsiClpSolverInterface osi_;
149 double relative_mip_gap_;
150 int num_threads_ = 1;
161 osi_.setStrParam(OsiProbName,
solver_->name_);
171 osi_.setStrParam(OsiProbName,
solver_->name_);
175void CBCInterface::ResetBestObjectiveBound() {
186 osi_.setObjSense(maximize ? -1 : 1);
194int MPSolverVarIndexToCbcVarIndex(
int var_index) {
return var_index + 1; }
200 osi_.setColBounds(MPSolverVarIndexToCbcVarIndex(var_index), lb, ub);
211 osi_.setInteger(MPSolverVarIndexToCbcVarIndex(var_index));
213 osi_.setContinuous(MPSolverVarIndexToCbcVarIndex(var_index));
223 osi_.setRowBounds(index, lb, ub);
243 if (!
solver_->variables_.empty()) {
246 if (!
solver_->constraints_.empty()) {
247 solver_->LookupConstraintOrNull(
solver_->constraints_[0]->name());
261 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
276 build.addColumn(0,
nullptr,
nullptr, 1.0, 1.0,
277 solver_->Objective().offset(),
"dummy",
false);
278 const int nb_vars =
solver_->variables_.size();
279 for (
int i = 0; i < nb_vars; ++i) {
282 const double obj_coeff =
solver_->Objective().GetCoefficient(var);
283 if (var->
name().empty()) {
284 build.addColumn(0,
nullptr,
nullptr, var->
lb(), var->
ub(), obj_coeff,
287 build.addColumn(0,
nullptr,
nullptr, var->
lb(), var->
ub(), obj_coeff,
293 int max_row_length = 0;
294 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
297 if (ct->coefficients_.size() > max_row_length) {
298 max_row_length = ct->coefficients_.size();
301 std::unique_ptr<int[]> indices(
new int[max_row_length]);
302 std::unique_ptr<double[]> coefs(
new double[max_row_length]);
304 for (
int i = 0; i <
solver_->constraints_.size(); ++i) {
306 const int size = ct->coefficients_.size();
308 for (
const auto& entry : ct->coefficients_) {
309 const int index = MPSolverVarIndexToCbcVarIndex(entry.first->index());
311 coefs[j] = entry.second;
314 if (ct->
name().empty()) {
315 build.addRow(size, indices.get(), coefs.get(), ct->
lb(), ct->
ub());
317 build.addRow(size, indices.get(), coefs.get(), ct->
lb(), ct->
ub(),
321 osi_.loadFromCoinModel(build);
337 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
339 ResetBestObjectiveBound();
342 CbcModel model(osi_);
345 CoinMessageHandler message_handler;
346 model.passInMessageHandler(&message_handler);
348 message_handler.setLogLevel(0, 0);
349 message_handler.setLogLevel(1, 0);
350 message_handler.setLogLevel(2, 0);
351 message_handler.setLogLevel(3, 0);
353 message_handler.setLogLevel(0, 1);
354 message_handler.setLogLevel(1, 1);
355 message_handler.setLogLevel(2, 1);
356 message_handler.setLogLevel(3, 1);
360 if (
solver_->time_limit() != 0) {
361 VLOG(1) <<
"Setting time limit = " <<
solver_->time_limit() <<
" ms.";
362 model.setMaximumSeconds(
solver_->time_limit_in_secs());
371 SetParameters(param);
374 model.setTypePresolve(0);
377 model.setAllowableFractionGap(relative_mip_gap_);
381 ? callCbc(
"-solve ", model)
382 : callCbc(absl::StrCat(
"-threads ", num_threads_,
" -solve "), model);
383 const int kBadReturnStatus = 777;
384 CHECK_NE(kBadReturnStatus, return_status);
387 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
390 int tmp_status = model.status();
392 VLOG(1) <<
"cbc result status: " << tmp_status;
405 switch (tmp_status) {
409 if (model.isProvenOptimal()) {
411 }
else if (model.isContinuousUnbounded()) {
413 }
else if (model.isProvenInfeasible()) {
415 }
else if (model.isAbandoned()) {
422 if (model.bestSolution() !=
nullptr) {
438 const double*
const values = model.bestSolution();
439 if (values !=
nullptr) {
441 for (
int i = 0; i <
solver_->variables_.size(); ++i) {
443 const int var_index = MPSolverVarIndexToCbcVarIndex(var->
index());
444 const double val = values[var_index];
446 VLOG(3) << var->
name() <<
"=" << val;
449 VLOG(1) <<
"No feasible solution found.";
453 iterations_ = model.getIterationCount();
454 nodes_ = model.getNodeCount();
488void CBCInterface::SetRelativeMipGap(
double value) {
489 relative_mip_gap_ = value;
492void CBCInterface::SetPrimalTolerance(
double value) {
500void CBCInterface::SetDualTolerance(
double value) {
508void CBCInterface::SetPresolveMode(
int value) {
520void CBCInterface::SetScalingMode(
int value) {
524void CBCInterface::SetLpAlgorithm(
int value) {
531const void*
const kRegisterCBC ABSL_ATTRIBUTE_UNUSED = [] {
void SetConstraintBounds(int row_index, double lb, double ub) override
MPSolver::BasisStatus row_status(int constraint_index) const override
void AddRowConstraint(MPConstraint *ct) override
void ClearObjective() override
void ClearConstraint(MPConstraint *const constraint) override
CBCInterface(MPSolver *solver)
void ExtractNewConstraints() override
void SetVariableBounds(int var_index, double lb, double ub) override
void ExtractNewVariables() override
absl::Status SetNumThreads(int num_threads) override
int64_t nodes() const override
void ExtractObjective() override
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
void SetOptimizationDirection(bool maximize) override
MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override
void AddVariable(MPVariable *var) override
MPSolver::BasisStatus column_status(int variable_index) const override
bool IsLP() const override
int64_t iterations() const override
bool IsMIP() const override
void SetVariableInteger(int var_index, bool integer) override
std::string SolverVersion() const override
void SetObjectiveOffset(double value) override
bool IsContinuous() const override
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
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.
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 SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
void SetUnsupportedDoubleParam(MPSolverParameters::DoubleParam param)
static constexpr int64_t kUnknownNumberOfNodes
double best_objective_bound_
void SetMIPParameters(const MPSolverParameters ¶m)
MPSolverInterface(MPSolver *solver)
void SetCommonParameters(const MPSolverParameters ¶m)
MPSolver::ResultStatus result_status_
SynchronizationStatus sync_status_
static const double kDefaultDualTolerance
static const double kDefaultPrimalTolerance
@ 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.
@ CBC_MIXED_INTEGER_PROGRAMMING
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_.