OR-Tools  9.2
clp_interface.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <memory>
19 #include <string>
20 #include <vector>
21 
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"
27 #include "ortools/base/hash.h"
29 #include "ortools/base/logging.h"
30 #include "ortools/base/timer.h"
32 
33 #if defined(USE_CLP) || defined(USE_CBC)
34 
35 #undef PACKAGE
36 #undef VERSION
37 #include "ClpConfig.h"
38 #include "ClpMessage.hpp"
39 #include "ClpSimplex.hpp"
40 #include "CoinBuild.hpp"
41 
42 namespace operations_research {
43 
45  public:
46  // Constructor that takes a name for the underlying CLP solver.
47  explicit CLPInterface(MPSolver* const solver);
48  ~CLPInterface() override;
49 
50  // Sets the optimization direction (min/max).
51  void SetOptimizationDirection(bool maximize) override;
52 
53  // ----- Solve -----
54  // Solve the problem using the parameter values specified.
55  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
56 
57  // ----- Model modifications and extraction -----
58  // Resets extracted model
59  void Reset() override;
60 
61  // Modify bounds.
62  void SetVariableBounds(int var_index, double lb, double ub) override;
63  void SetVariableInteger(int var_index, bool integer) override;
64  void SetConstraintBounds(int row_index, double lb, double ub) override;
65 
66  // Add constraint incrementally.
67  void AddRowConstraint(MPConstraint* const ct) override;
68  // Add variable incrementally.
69  void AddVariable(MPVariable* const var) override;
70  // Change a coefficient in a constraint.
71  void SetCoefficient(MPConstraint* const constraint,
72  const MPVariable* const variable, double new_value,
73  double old_value) override;
74  // Clear a constraint from all its terms.
75  void ClearConstraint(MPConstraint* const constraint) override;
76 
77  // Change a coefficient in the linear objective.
78  void SetObjectiveCoefficient(const MPVariable* const variable,
79  double coefficient) override;
80  // Change the constant term in the linear objective.
81  void SetObjectiveOffset(double offset) override;
82  // Clear the objective from all its terms.
83  void ClearObjective() override;
84 
85  // ------ Query statistics on the solution and the solve ------
86  // Number of simplex iterations
87  int64_t iterations() const override;
88  // Number of branch-and-bound nodes. Only available for discrete problems.
89  int64_t nodes() const override;
90 
91  // Returns the basis status of a row.
92  MPSolver::BasisStatus row_status(int constraint_index) const override;
93  // Returns the basis status of a column.
94  MPSolver::BasisStatus column_status(int variable_index) const override;
95 
96  // ----- Misc -----
97  // Query problem type.
98  bool IsContinuous() const override { return true; }
99  bool IsLP() const override { return true; }
100  bool IsMIP() const override { return false; }
101 
102  void ExtractNewVariables() override;
103  void ExtractNewConstraints() override;
104  void ExtractObjective() override;
105 
106  std::string SolverVersion() const override { return "Clp " CLP_VERSION; }
107 
108  void* underlying_solver() override {
109  return reinterpret_cast<void*>(clp_.get());
110  }
111 
112  private:
113  // Create dummy variable to be able to create empty constraints.
114  void CreateDummyVariableForEmptyConstraints();
115 
116  // Set all parameters in the underlying solver.
117  void SetParameters(const MPSolverParameters& param) override;
118  // Reset to their default value the parameters for which CLP has a
119  // stateful API. To be called after the solve so that the next solve
120  // starts from a clean parameter state.
121  void ResetParameters();
122  // Set each parameter in the underlying solver.
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;
129 
130  // Transforms basis status from CLP enum to MPSolver::BasisStatus.
131  MPSolver::BasisStatus TransformCLPBasisStatus(
132  ClpSimplex::Status clp_basis_status) const;
133 
134  std::unique_ptr<ClpSimplex> clp_; // TODO(user) : remove pointer.
135  std::unique_ptr<ClpSolve> options_; // For parameter setting.
136 };
137 
138 // ----- Solver -----
139 
140 // Creates a LP/MIP instance with the specified name and minimization objective.
142  : MPSolverInterface(solver), clp_(new ClpSimplex), options_(new ClpSolve) {
143  clp_->setStrParam(ClpProbName, solver_->name_);
144  clp_->setOptimizationDirection(1);
145 }
146 
148 
150  clp_ = absl::make_unique<ClpSimplex>();
151  clp_->setOptimizationDirection(maximize_ ? -1 : 1);
153 }
154 
155 // ------ Model modifications and extraction -----
156 
157 namespace {
158 // Variable indices are shifted by 1 internally because of the dummy "objective
159 // offset" variable (with internal index 0).
160 int MPSolverVarIndexToClpVarIndex(int var_index) { return var_index + 1; }
161 } // namespace
162 
163 // Not cached
166  clp_->setOptimizationDirection(maximize ? -1 : 1);
167 }
168 
169 void CLPInterface::SetVariableBounds(int var_index, double lb, double ub) {
171  if (variable_is_extracted(var_index)) {
172  // Not cached if the variable has been extracted
173  DCHECK_LT(var_index, last_variable_index_);
174  clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(var_index), lb, ub);
175  } else {
177  }
178 }
179 
180 // Ignore as CLP does not solve models with integer variables
181 void CLPInterface::SetVariableInteger(int var_index, bool integer) {}
182 
183 void CLPInterface::SetConstraintBounds(int index, double lb, double ub) {
186  // Not cached if the row has been extracted
188  clp_->setRowBounds(index, lb, ub);
189  } else {
191  }
192 }
193 
195  const MPVariable* const variable,
196  double new_value, double old_value) {
198  if (constraint_is_extracted(constraint->index()) &&
199  variable_is_extracted(variable->index())) {
200  // The modification of the coefficient for an extracted row and
201  // variable is not cached.
202  DCHECK_LE(constraint->index(), last_constraint_index_);
203  DCHECK_LE(variable->index(), last_variable_index_);
204  clp_->modifyCoefficient(constraint->index(),
205  MPSolverVarIndexToClpVarIndex(variable->index()),
206  new_value);
207  } else {
208  // The modification of an unextracted row or variable is cached
209  // and handled in ExtractModel.
211  }
212 }
213 
214 // Not cached
217  // Constraint may not have been extracted yet.
218  if (!constraint_is_extracted(constraint->index())) return;
219  for (const auto& entry : constraint->coefficients_) {
220  DCHECK(variable_is_extracted(entry.first->index()));
221  clp_->modifyCoefficient(constraint->index(),
222  MPSolverVarIndexToClpVarIndex(entry.first->index()),
223  0.0);
224  }
225 }
226 
227 // Cached
229  double coefficient) {
231  if (variable_is_extracted(variable->index())) {
232  clp_->setObjectiveCoefficient(
233  MPSolverVarIndexToClpVarIndex(variable->index()), coefficient);
234  } else {
236  }
237 }
238 
239 // Cached
240 void CLPInterface::SetObjectiveOffset(double offset) {
241  // Constant term. Use -offset instead of +offset because CLP does
242  // not follow conventions.
244  clp_->setObjectiveOffset(-offset);
245 }
246 
247 // Clear objective of all its terms.
250  // Clear linear terms
251  for (const auto& entry : solver_->objective_->coefficients_) {
252  const int mpsolver_var_index = entry.first->index();
253  // Variable may have not been extracted yet.
254  if (!variable_is_extracted(mpsolver_var_index)) {
256  } else {
257  clp_->setObjectiveCoefficient(
258  MPSolverVarIndexToClpVarIndex(mpsolver_var_index), 0.0);
259  }
260  }
261  // Clear constant term.
262  clp_->setObjectiveOffset(0.0);
263 }
264 
267 }
268 
271 }
272 
273 void CLPInterface::CreateDummyVariableForEmptyConstraints() {
274  clp_->setColumnBounds(kDummyVariableIndex, 0.0, 0.0);
275  clp_->setObjectiveCoefficient(kDummyVariableIndex, 0.0);
276  // Workaround for peculiar signature of setColumnName. Note that we do need
277  // std::string here, and not 'string', which aren't the same as of 2013-12
278  // (this will change later).
279  std::string dummy = "dummy"; // We do need to create this temporary variable.
280  clp_->setColumnName(kDummyVariableIndex, dummy);
281 }
282 
283 // Define new variables and add them to existing constraints.
285  // Define new variables
286  int total_num_vars = solver_->variables_.size();
287  if (total_num_vars > last_variable_index_) {
288  if (last_variable_index_ == 0 && last_constraint_index_ == 0) {
289  // Faster extraction when nothing has been extracted yet.
290  clp_->resize(0, total_num_vars + 1);
291  CreateDummyVariableForEmptyConstraints();
292  for (int i = 0; i < total_num_vars; ++i) {
293  MPVariable* const var = solver_->variables_[i];
294  set_variable_as_extracted(i, true);
295  if (!var->name().empty()) {
296  std::string name = var->name();
297  clp_->setColumnName(MPSolverVarIndexToClpVarIndex(i), name);
298  }
299  clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(i), var->lb(),
300  var->ub());
301  }
302  } else {
303  // TODO(user): This could perhaps be made slightly faster by
304  // iterating through old constraints, constructing by hand the
305  // column-major representation of the addition to them and call
306  // clp_->addColumns. But this is good enough for now.
307  // Create new variables.
308  for (int j = last_variable_index_; j < total_num_vars; ++j) {
309  MPVariable* const var = solver_->variables_[j];
311  set_variable_as_extracted(j, true);
312  // The true objective coefficient will be set later in ExtractObjective.
313  double tmp_obj_coef = 0.0;
314  clp_->addColumn(0, nullptr, nullptr, var->lb(), var->ub(),
315  tmp_obj_coef);
316  if (!var->name().empty()) {
317  std::string name = var->name();
318  clp_->setColumnName(MPSolverVarIndexToClpVarIndex(j), name);
319  }
320  }
321  // Add new variables to existing constraints.
322  for (int i = 0; i < last_constraint_index_; i++) {
323  MPConstraint* const ct = solver_->constraints_[i];
324  const int ct_index = ct->index();
325  for (const auto& entry : ct->coefficients_) {
326  const int mpsolver_var_index = entry.first->index();
327  DCHECK(variable_is_extracted(mpsolver_var_index));
328  if (mpsolver_var_index >= last_variable_index_) {
329  clp_->modifyCoefficient(
330  ct_index, MPSolverVarIndexToClpVarIndex(mpsolver_var_index),
331  entry.second);
332  }
333  }
334  }
335  }
336  }
337 }
338 
339 // Define new constraints on old and new variables.
341  int total_num_rows = solver_->constraints_.size();
342  if (last_constraint_index_ < total_num_rows) {
343  // Find the length of the longest row.
344  int max_row_length = 0;
345  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
346  MPConstraint* const ct = solver_->constraints_[i];
347  DCHECK(!constraint_is_extracted(ct->index()));
348  set_constraint_as_extracted(ct->index(), true);
349  if (ct->coefficients_.size() > max_row_length) {
350  max_row_length = ct->coefficients_.size();
351  }
352  }
353  // Make space for dummy variable.
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;
358  // Add each new constraint.
359  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
360  MPConstraint* const ct = solver_->constraints_[i];
361  DCHECK(constraint_is_extracted(ct->index()));
362  int size = ct->coefficients_.size();
363  if (size == 0) {
364  // Add dummy variable to be able to build the constraint.
365  indices[0] = kDummyVariableIndex;
366  coefs[0] = 1.0;
367  size = 1;
368  }
369  int j = 0;
370  for (const auto& entry : ct->coefficients_) {
371  const int mpsolver_var_index = entry.first->index();
372  DCHECK(variable_is_extracted(mpsolver_var_index));
373  indices[j] = MPSolverVarIndexToClpVarIndex(mpsolver_var_index);
374  coefs[j] = entry.second;
375  j++;
376  }
377  build_object.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub());
378  }
379  // Add and name the rows.
380  clp_->addRows(build_object);
381  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
382  MPConstraint* const ct = solver_->constraints_[i];
383  if (!ct->name().empty()) {
384  std::string name = ct->name();
385  clp_->setRowName(ct->index(), name);
386  }
387  }
388  }
389 }
390 
392  // Linear objective: set objective coefficients for all variables
393  // (some might have been modified)
394  for (const auto& entry : solver_->objective_->coefficients_) {
395  clp_->setObjectiveCoefficient(
396  MPSolverVarIndexToClpVarIndex(entry.first->index()), entry.second);
397  }
398 
399  // Constant term. Use -offset instead of +offset because CLP does
400  // not follow conventions.
401  clp_->setObjectiveOffset(-solver_->Objective().offset());
402 }
403 
404 // Extracts model and solve the LP/MIP. Returns the status of the search.
406  try {
407  WallTimer timer;
408  timer.Start();
409 
412  Reset();
413  }
414 
415  // Set log level.
416  CoinMessageHandler message_handler;
417  clp_->passInMessageHandler(&message_handler);
418  if (quiet_) {
419  message_handler.setLogLevel(1, 0);
420  clp_->setLogLevel(0);
421  } else {
422  message_handler.setLogLevel(1, 1);
423  clp_->setLogLevel(1);
424  }
425 
426  // Special case if the model is empty since CLP is not able to
427  // handle this special case by itself.
428  if (solver_->variables_.empty() && solver_->constraints_.empty()) {
432  return result_status_;
433  }
434 
435  ExtractModel();
436  VLOG(1) << absl::StrFormat("Model built in %.3f seconds.", timer.Get());
437 
438  // Time limit.
439  if (solver_->time_limit() != 0) {
440  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
441  clp_->setMaximumSeconds(solver_->time_limit_in_secs());
442  } else {
443  clp_->setMaximumSeconds(-1.0);
444  }
445 
446  // Start from a fresh set of default parameters and set them to
447  // specified values.
448  options_ = absl::make_unique<ClpSolve>();
449  SetParameters(param);
450 
451  // Solve
452  timer.Restart();
453  clp_->initialSolve(*options_);
454  VLOG(1) << absl::StrFormat("Solved in %.3f seconds.", timer.Get());
455 
456  // Check the status: optimal, infeasible, etc.
457  int tmp_status = clp_->status();
458  VLOG(1) << "clp result status: " << tmp_status;
459  switch (tmp_status) {
460  case CLP_SIMPLEX_FINISHED:
462  break;
463  case CLP_SIMPLEX_INFEASIBLE:
465  break;
466  case CLP_SIMPLEX_UNBOUNDED:
468  break;
469  case CLP_SIMPLEX_STOPPED:
471  break;
472  default:
474  break;
475  }
476 
479  // Get the results
480  objective_value_ = clp_->objectiveValue();
481  VLOG(1) << "objective=" << objective_value_;
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) {
485  MPVariable* const var = solver_->variables_[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;
493  }
494  const double* const dual_values = clp_->getRowPrice();
495  for (int i = 0; i < solver_->constraints_.size(); ++i) {
496  MPConstraint* const ct = solver_->constraints_[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;
501  }
502  }
503 
504  ResetParameters();
506  return result_status_;
507  } catch (CoinError& e) {
508  LOG(WARNING) << "Caught exception in Coin LP: " << e.message();
510  return result_status_;
511  }
512 }
513 
514 MPSolver::BasisStatus CLPInterface::TransformCLPBasisStatus(
515  ClpSimplex::Status clp_basis_status) const {
516  switch (clp_basis_status) {
517  case ClpSimplex::isFree:
518  return MPSolver::FREE;
519  case ClpSimplex::basic:
520  return MPSolver::BASIC;
521  case ClpSimplex::atUpperBound:
523  case ClpSimplex::atLowerBound:
525  case ClpSimplex::superBasic:
526  return MPSolver::FREE;
527  case ClpSimplex::isFixed:
528  return MPSolver::FIXED_VALUE;
529  default:
530  LOG(FATAL) << "Unknown CLP basis status";
531  return MPSolver::FREE;
532  }
533 }
534 
535 // ------ Query statistics on the solution and the solve ------
536 
537 int64_t CLPInterface::iterations() const {
539  return clp_->getIterationCount();
540 }
541 
542 int64_t CLPInterface::nodes() const {
543  LOG(DFATAL) << "Number of nodes only available for discrete problems";
544  return kUnknownNumberOfNodes;
545 }
546 
547 MPSolver::BasisStatus CLPInterface::row_status(int constraint_index) const {
548  DCHECK_LE(0, constraint_index);
549  DCHECK_GT(last_constraint_index_, constraint_index);
550  const ClpSimplex::Status clp_basis_status =
551  clp_->getRowStatus(constraint_index);
552  return TransformCLPBasisStatus(clp_basis_status);
553 }
554 
556  DCHECK_LE(0, variable_index);
557  DCHECK_GT(last_variable_index_, variable_index);
558  const ClpSimplex::Status clp_basis_status =
559  clp_->getColumnStatus(MPSolverVarIndexToClpVarIndex(variable_index));
560  return TransformCLPBasisStatus(clp_basis_status);
561 }
562 
563 // ------ Parameters ------
564 
565 void CLPInterface::SetParameters(const MPSolverParameters& param) {
566  SetCommonParameters(param);
567 }
568 
569 void CLPInterface::ResetParameters() {
570  clp_->setPrimalTolerance(MPSolverParameters::kDefaultPrimalTolerance);
571  clp_->setDualTolerance(MPSolverParameters::kDefaultDualTolerance);
572 }
573 
574 void CLPInterface::SetRelativeMipGap(double value) {
575  LOG(WARNING) << "The relative MIP gap is only available "
576  << "for discrete problems.";
577 }
578 
579 void CLPInterface::SetPrimalTolerance(double value) {
580  clp_->setPrimalTolerance(value);
581 }
582 
583 void CLPInterface::SetDualTolerance(double value) {
584  clp_->setDualTolerance(value);
585 }
586 
587 void CLPInterface::SetPresolveMode(int value) {
588  switch (value) {
590  options_->setPresolveType(ClpSolve::presolveOff);
591  break;
592  }
594  options_->setPresolveType(ClpSolve::presolveOn);
595  break;
596  }
597  default: {
599  }
600  }
601 }
602 
603 void CLPInterface::SetScalingMode(int value) {
605 }
606 
607 void CLPInterface::SetLpAlgorithm(int value) {
608  switch (value) {
610  options_->setSolveType(ClpSolve::useDual);
611  break;
612  }
614  options_->setSolveType(ClpSolve::usePrimal);
615  break;
616  }
618  options_->setSolveType(ClpSolve::useBarrier);
619  break;
620  }
621  default: {
623  value);
624  }
625  }
626 }
627 
629  return new CLPInterface(solver);
630 }
631 
632 } // namespace operations_research
633 #endif // #if defined(USE_CBC) || defined(USE_CLP)
ResultStatus
The status of solving the problem.
void set_variable_as_extracted(int var_index, bool extracted)
Advanced usage: incrementality from one solve to the next.
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
double Get() const
Definition: timer.h:45
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
void SetOptimizationDirection(bool maximize) override
const int FATAL
Definition: log_severity.h:32
void set_constraint_as_extracted(int ct_index, bool extracted)
void SetVariableInteger(int var_index, bool integer) override
#define VLOG(verboselevel)
Definition: base/logging.h:983
const std::string name
const MPObjective & Objective() const
Returns the objective object.
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
#define LOG(severity)
Definition: base/logging.h:420
void SetVariableBounds(int var_index, double lb, double ub) override
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:895
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
int64_t coefficient
void Start()
Definition: timer.h:31
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
The class for variables of a Mathematical Programming (MP) model.
int64_t max
Definition: alldiff_cst.cc:140
const int WARNING
Definition: log_severity.h:31
std::string SolverVersion() const override
void AddRowConstraint(MPConstraint *const ct) override
CLPInterface(MPSolver *const solver)
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:891
void AddVariable(MPVariable *const var) override
void Restart()
Definition: timer.h:35
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
void SetCommonParameters(const MPSolverParameters &param)
static constexpr int64_t kUnknownNumberOfIterations
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
int index
Definition: pack.cc:509
The class for constraints of a Mathematical Programming (MP) model.
feasible, or stopped by limit.
void ClearConstraint(MPConstraint *const constraint) override
bool constraint_is_extracted(int ct_index) const
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
int64_t iterations() const override
#define DCHECK(condition)
Definition: base/logging.h:889
int index() const
Returns the index of the variable in the MPSolver::variables_.
Advanced usage: enable or disable matrix scaling.
static constexpr int64_t kUnknownNumberOfNodes
int64_t nodes() const override
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:892
This mathematical programming (MP) solver class is the main class though which users build and solve ...
Collection of objects used to extend the Constraint Solver library.
MPSolverInterface * BuildCLPInterface(MPSolver *const solver)
abnormal, i.e., error of some kind.
This class stores parameter settings for LP and MIP solvers.
bool IsContinuous() const override
MPSolver::BasisStatus row_status(int constraint_index) const override
IntVar * var
Definition: expr_array.cc:1874
MPSolver::BasisStatus column_status(int variable_index) const override
double offset() const
Gets the constant term in the objective.
int64_t value
void SetObjectiveOffset(double offset) override
const Constraint * ct
bool variable_is_extracted(int var_index) const
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:893
void SetConstraintBounds(int row_index, double lb, double ub) override