OR-Tools  9.1
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/memory/memory.h"
23 #include "absl/strings/match.h"
24 #include "absl/strings/str_format.h"
26 #include "ortools/base/hash.h"
28 #include "ortools/base/logging.h"
29 #include "ortools/base/timer.h"
31 
32 #if defined(USE_CLP) || defined(USE_CBC)
33 
34 #undef PACKAGE
35 #undef VERSION
36 #include "ClpConfig.h"
37 #include "ClpMessage.hpp"
38 #include "ClpSimplex.hpp"
39 #include "CoinBuild.hpp"
40 
41 namespace operations_research {
42 
44  public:
45  // Constructor that takes a name for the underlying CLP solver.
46  explicit CLPInterface(MPSolver* const solver);
47  ~CLPInterface() override;
48 
49  // Sets the optimization direction (min/max).
50  void SetOptimizationDirection(bool maximize) override;
51 
52  // ----- Solve -----
53  // Solve the problem using the parameter values specified.
54  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
55 
56  // ----- Model modifications and extraction -----
57  // Resets extracted model
58  void Reset() override;
59 
60  // Modify bounds.
61  void SetVariableBounds(int var_index, double lb, double ub) override;
62  void SetVariableInteger(int var_index, bool integer) override;
63  void SetConstraintBounds(int row_index, double lb, double ub) override;
64 
65  // Add constraint incrementally.
66  void AddRowConstraint(MPConstraint* const ct) override;
67  // Add variable incrementally.
68  void AddVariable(MPVariable* const var) override;
69  // Change a coefficient in a constraint.
70  void SetCoefficient(MPConstraint* const constraint,
71  const MPVariable* const variable, double new_value,
72  double old_value) override;
73  // Clear a constraint from all its terms.
74  void ClearConstraint(MPConstraint* const constraint) override;
75 
76  // Change a coefficient in the linear objective.
77  void SetObjectiveCoefficient(const MPVariable* const variable,
78  double coefficient) override;
79  // Change the constant term in the linear objective.
80  void SetObjectiveOffset(double offset) override;
81  // Clear the objective from all its terms.
82  void ClearObjective() override;
83 
84  // ------ Query statistics on the solution and the solve ------
85  // Number of simplex iterations
86  int64_t iterations() const override;
87  // Number of branch-and-bound nodes. Only available for discrete problems.
88  int64_t nodes() const override;
89 
90  // Returns the basis status of a row.
91  MPSolver::BasisStatus row_status(int constraint_index) const override;
92  // Returns the basis status of a column.
93  MPSolver::BasisStatus column_status(int variable_index) const override;
94 
95  // ----- Misc -----
96  // Query problem type.
97  bool IsContinuous() const override { return true; }
98  bool IsLP() const override { return true; }
99  bool IsMIP() const override { return false; }
100 
101  void ExtractNewVariables() override;
102  void ExtractNewConstraints() override;
103  void ExtractObjective() override;
104 
105  std::string SolverVersion() const override { return "Clp " CLP_VERSION; }
106 
107  void* underlying_solver() override {
108  return reinterpret_cast<void*>(clp_.get());
109  }
110 
111  private:
112  // Create dummy variable to be able to create empty constraints.
113  void CreateDummyVariableForEmptyConstraints();
114 
115  // Set all parameters in the underlying solver.
116  void SetParameters(const MPSolverParameters& param) override;
117  // Reset to their default value the parameters for which CLP has a
118  // stateful API. To be called after the solve so that the next solve
119  // starts from a clean parameter state.
120  void ResetParameters();
121  // Set each parameter in the underlying solver.
122  void SetRelativeMipGap(double value) override;
123  void SetPrimalTolerance(double value) override;
124  void SetDualTolerance(double value) override;
125  void SetPresolveMode(int value) override;
126  void SetScalingMode(int value) override;
127  void SetLpAlgorithm(int value) override;
128 
129  // Transforms basis status from CLP enum to MPSolver::BasisStatus.
130  MPSolver::BasisStatus TransformCLPBasisStatus(
131  ClpSimplex::Status clp_basis_status) const;
132 
133  std::unique_ptr<ClpSimplex> clp_; // TODO(user) : remove pointer.
134  std::unique_ptr<ClpSolve> options_; // For parameter setting.
135 };
136 
137 // ----- Solver -----
138 
139 // Creates a LP/MIP instance with the specified name and minimization objective.
141  : MPSolverInterface(solver), clp_(new ClpSimplex), options_(new ClpSolve) {
142  clp_->setStrParam(ClpProbName, solver_->name_);
143  clp_->setOptimizationDirection(1);
144 }
145 
147 
149  clp_ = absl::make_unique<ClpSimplex>();
150  clp_->setOptimizationDirection(maximize_ ? -1 : 1);
152 }
153 
154 // ------ Model modifications and extraction -----
155 
156 namespace {
157 // Variable indices are shifted by 1 internally because of the dummy "objective
158 // offset" variable (with internal index 0).
159 int MPSolverVarIndexToClpVarIndex(int var_index) { return var_index + 1; }
160 } // namespace
161 
162 // Not cached
165  clp_->setOptimizationDirection(maximize ? -1 : 1);
166 }
167 
168 void CLPInterface::SetVariableBounds(int var_index, double lb, double ub) {
170  if (variable_is_extracted(var_index)) {
171  // Not cached if the variable has been extracted
172  DCHECK_LT(var_index, last_variable_index_);
173  clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(var_index), lb, ub);
174  } else {
176  }
177 }
178 
179 // Ignore as CLP does not solve models with integer variables
180 void CLPInterface::SetVariableInteger(int var_index, bool integer) {}
181 
182 void CLPInterface::SetConstraintBounds(int index, double lb, double ub) {
185  // Not cached if the row has been extracted
187  clp_->setRowBounds(index, lb, ub);
188  } else {
190  }
191 }
192 
194  const MPVariable* const variable,
195  double new_value, double old_value) {
197  if (constraint_is_extracted(constraint->index()) &&
198  variable_is_extracted(variable->index())) {
199  // The modification of the coefficient for an extracted row and
200  // variable is not cached.
201  DCHECK_LE(constraint->index(), last_constraint_index_);
202  DCHECK_LE(variable->index(), last_variable_index_);
203  clp_->modifyCoefficient(constraint->index(),
204  MPSolverVarIndexToClpVarIndex(variable->index()),
205  new_value);
206  } else {
207  // The modification of an unextracted row or variable is cached
208  // and handled in ExtractModel.
210  }
211 }
212 
213 // Not cached
216  // Constraint may not have been extracted yet.
217  if (!constraint_is_extracted(constraint->index())) return;
218  for (const auto& entry : constraint->coefficients_) {
219  DCHECK(variable_is_extracted(entry.first->index()));
220  clp_->modifyCoefficient(constraint->index(),
221  MPSolverVarIndexToClpVarIndex(entry.first->index()),
222  0.0);
223  }
224 }
225 
226 // Cached
228  double coefficient) {
230  if (variable_is_extracted(variable->index())) {
231  clp_->setObjectiveCoefficient(
232  MPSolverVarIndexToClpVarIndex(variable->index()), coefficient);
233  } else {
235  }
236 }
237 
238 // Cached
239 void CLPInterface::SetObjectiveOffset(double offset) {
240  // Constant term. Use -offset instead of +offset because CLP does
241  // not follow conventions.
243  clp_->setObjectiveOffset(-offset);
244 }
245 
246 // Clear objective of all its terms.
249  // Clear linear terms
250  for (const auto& entry : solver_->objective_->coefficients_) {
251  const int mpsolver_var_index = entry.first->index();
252  // Variable may have not been extracted yet.
253  if (!variable_is_extracted(mpsolver_var_index)) {
255  } else {
256  clp_->setObjectiveCoefficient(
257  MPSolverVarIndexToClpVarIndex(mpsolver_var_index), 0.0);
258  }
259  }
260  // Clear constant term.
261  clp_->setObjectiveOffset(0.0);
262 }
263 
266 }
267 
270 }
271 
272 void CLPInterface::CreateDummyVariableForEmptyConstraints() {
273  clp_->setColumnBounds(kDummyVariableIndex, 0.0, 0.0);
274  clp_->setObjectiveCoefficient(kDummyVariableIndex, 0.0);
275  // Workaround for peculiar signature of setColumnName. Note that we do need
276  // std::string here, and not 'string', which aren't the same as of 2013-12
277  // (this will change later).
278  std::string dummy = "dummy"; // We do need to create this temporary variable.
279  clp_->setColumnName(kDummyVariableIndex, dummy);
280 }
281 
282 // Define new variables and add them to existing constraints.
284  // Define new variables
285  int total_num_vars = solver_->variables_.size();
286  if (total_num_vars > last_variable_index_) {
287  if (last_variable_index_ == 0 && last_constraint_index_ == 0) {
288  // Faster extraction when nothing has been extracted yet.
289  clp_->resize(0, total_num_vars + 1);
290  CreateDummyVariableForEmptyConstraints();
291  for (int i = 0; i < total_num_vars; ++i) {
292  MPVariable* const var = solver_->variables_[i];
293  set_variable_as_extracted(i, true);
294  if (!var->name().empty()) {
295  std::string name = var->name();
296  clp_->setColumnName(MPSolverVarIndexToClpVarIndex(i), name);
297  }
298  clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(i), var->lb(),
299  var->ub());
300  }
301  } else {
302  // TODO(user): This could perhaps be made slightly faster by
303  // iterating through old constraints, constructing by hand the
304  // column-major representation of the addition to them and call
305  // clp_->addColumns. But this is good enough for now.
306  // Create new variables.
307  for (int j = last_variable_index_; j < total_num_vars; ++j) {
308  MPVariable* const var = solver_->variables_[j];
310  set_variable_as_extracted(j, true);
311  // The true objective coefficient will be set later in ExtractObjective.
312  double tmp_obj_coef = 0.0;
313  clp_->addColumn(0, nullptr, nullptr, var->lb(), var->ub(),
314  tmp_obj_coef);
315  if (!var->name().empty()) {
316  std::string name = var->name();
317  clp_->setColumnName(MPSolverVarIndexToClpVarIndex(j), name);
318  }
319  }
320  // Add new variables to existing constraints.
321  for (int i = 0; i < last_constraint_index_; i++) {
322  MPConstraint* const ct = solver_->constraints_[i];
323  const int ct_index = ct->index();
324  for (const auto& entry : ct->coefficients_) {
325  const int mpsolver_var_index = entry.first->index();
326  DCHECK(variable_is_extracted(mpsolver_var_index));
327  if (mpsolver_var_index >= last_variable_index_) {
328  clp_->modifyCoefficient(
329  ct_index, MPSolverVarIndexToClpVarIndex(mpsolver_var_index),
330  entry.second);
331  }
332  }
333  }
334  }
335  }
336 }
337 
338 // Define new constraints on old and new variables.
340  int total_num_rows = solver_->constraints_.size();
341  if (last_constraint_index_ < total_num_rows) {
342  // Find the length of the longest row.
343  int max_row_length = 0;
344  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
345  MPConstraint* const ct = solver_->constraints_[i];
346  DCHECK(!constraint_is_extracted(ct->index()));
347  set_constraint_as_extracted(ct->index(), true);
348  if (ct->coefficients_.size() > max_row_length) {
349  max_row_length = ct->coefficients_.size();
350  }
351  }
352  // Make space for dummy variable.
353  max_row_length = std::max(1, max_row_length);
354  std::unique_ptr<int[]> indices(new int[max_row_length]);
355  std::unique_ptr<double[]> coefs(new double[max_row_length]);
356  CoinBuild build_object;
357  // Add each new constraint.
358  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
359  MPConstraint* const ct = solver_->constraints_[i];
360  DCHECK(constraint_is_extracted(ct->index()));
361  int size = ct->coefficients_.size();
362  if (size == 0) {
363  // Add dummy variable to be able to build the constraint.
364  indices[0] = kDummyVariableIndex;
365  coefs[0] = 1.0;
366  size = 1;
367  }
368  int j = 0;
369  for (const auto& entry : ct->coefficients_) {
370  const int mpsolver_var_index = entry.first->index();
371  DCHECK(variable_is_extracted(mpsolver_var_index));
372  indices[j] = MPSolverVarIndexToClpVarIndex(mpsolver_var_index);
373  coefs[j] = entry.second;
374  j++;
375  }
376  build_object.addRow(size, indices.get(), coefs.get(), ct->lb(), ct->ub());
377  }
378  // Add and name the rows.
379  clp_->addRows(build_object);
380  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
381  MPConstraint* const ct = solver_->constraints_[i];
382  if (!ct->name().empty()) {
383  std::string name = ct->name();
384  clp_->setRowName(ct->index(), name);
385  }
386  }
387  }
388 }
389 
391  // Linear objective: set objective coefficients for all variables
392  // (some might have been modified)
393  for (const auto& entry : solver_->objective_->coefficients_) {
394  clp_->setObjectiveCoefficient(
395  MPSolverVarIndexToClpVarIndex(entry.first->index()), entry.second);
396  }
397 
398  // Constant term. Use -offset instead of +offset because CLP does
399  // not follow conventions.
400  clp_->setObjectiveOffset(-solver_->Objective().offset());
401 }
402 
403 // Extracts model and solve the LP/MIP. Returns the status of the search.
405  try {
406  WallTimer timer;
407  timer.Start();
408 
411  Reset();
412  }
413 
414  // Set log level.
415  CoinMessageHandler message_handler;
416  clp_->passInMessageHandler(&message_handler);
417  if (quiet_) {
418  message_handler.setLogLevel(1, 0);
419  clp_->setLogLevel(0);
420  } else {
421  message_handler.setLogLevel(1, 1);
422  clp_->setLogLevel(1);
423  }
424 
425  // Special case if the model is empty since CLP is not able to
426  // handle this special case by itself.
427  if (solver_->variables_.empty() && solver_->constraints_.empty()) {
431  return result_status_;
432  }
433 
434  ExtractModel();
435  VLOG(1) << absl::StrFormat("Model built in %.3f seconds.", timer.Get());
436 
437  // Time limit.
438  if (solver_->time_limit() != 0) {
439  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
440  clp_->setMaximumSeconds(solver_->time_limit_in_secs());
441  } else {
442  clp_->setMaximumSeconds(-1.0);
443  }
444 
445  // Start from a fresh set of default parameters and set them to
446  // specified values.
447  options_ = absl::make_unique<ClpSolve>();
448  SetParameters(param);
449 
450  // Solve
451  timer.Restart();
452  clp_->initialSolve(*options_);
453  VLOG(1) << absl::StrFormat("Solved in %.3f seconds.", timer.Get());
454 
455  // Check the status: optimal, infeasible, etc.
456  int tmp_status = clp_->status();
457  VLOG(1) << "clp result status: " << tmp_status;
458  switch (tmp_status) {
459  case CLP_SIMPLEX_FINISHED:
461  break;
462  case CLP_SIMPLEX_INFEASIBLE:
464  break;
465  case CLP_SIMPLEX_UNBOUNDED:
467  break;
468  case CLP_SIMPLEX_STOPPED:
470  break;
471  default:
473  break;
474  }
475 
478  // Get the results
479  objective_value_ = clp_->objectiveValue();
480  VLOG(1) << "objective=" << objective_value_;
481  const double* const values = clp_->getColSolution();
482  const double* const reduced_costs = clp_->getReducedCost();
483  for (int i = 0; i < solver_->variables_.size(); ++i) {
484  MPVariable* const var = solver_->variables_[i];
485  const int clp_var_index = MPSolverVarIndexToClpVarIndex(var->index());
486  const double val = values[clp_var_index];
487  var->set_solution_value(val);
488  VLOG(3) << var->name() << ": value = " << val;
489  double reduced_cost = reduced_costs[clp_var_index];
490  var->set_reduced_cost(reduced_cost);
491  VLOG(4) << var->name() << ": reduced cost = " << reduced_cost;
492  }
493  const double* const dual_values = clp_->getRowPrice();
494  for (int i = 0; i < solver_->constraints_.size(); ++i) {
495  MPConstraint* const ct = solver_->constraints_[i];
496  const int constraint_index = ct->index();
497  const double dual_value = dual_values[constraint_index];
498  ct->set_dual_value(dual_value);
499  VLOG(4) << "row " << ct->index() << " dual value = " << dual_value;
500  }
501  }
502 
503  ResetParameters();
505  return result_status_;
506  } catch (CoinError& e) {
507  LOG(WARNING) << "Caught exception in Coin LP: " << e.message();
509  return result_status_;
510  }
511 }
512 
513 MPSolver::BasisStatus CLPInterface::TransformCLPBasisStatus(
514  ClpSimplex::Status clp_basis_status) const {
515  switch (clp_basis_status) {
516  case ClpSimplex::isFree:
517  return MPSolver::FREE;
518  case ClpSimplex::basic:
519  return MPSolver::BASIC;
520  case ClpSimplex::atUpperBound:
522  case ClpSimplex::atLowerBound:
524  case ClpSimplex::superBasic:
525  return MPSolver::FREE;
526  case ClpSimplex::isFixed:
527  return MPSolver::FIXED_VALUE;
528  default:
529  LOG(FATAL) << "Unknown CLP basis status";
530  return MPSolver::FREE;
531  }
532 }
533 
534 // ------ Query statistics on the solution and the solve ------
535 
536 int64_t CLPInterface::iterations() const {
538  return clp_->getIterationCount();
539 }
540 
541 int64_t CLPInterface::nodes() const {
542  LOG(DFATAL) << "Number of nodes only available for discrete problems";
543  return kUnknownNumberOfNodes;
544 }
545 
546 MPSolver::BasisStatus CLPInterface::row_status(int constraint_index) const {
547  DCHECK_LE(0, constraint_index);
548  DCHECK_GT(last_constraint_index_, constraint_index);
549  const ClpSimplex::Status clp_basis_status =
550  clp_->getRowStatus(constraint_index);
551  return TransformCLPBasisStatus(clp_basis_status);
552 }
553 
555  DCHECK_LE(0, variable_index);
556  DCHECK_GT(last_variable_index_, variable_index);
557  const ClpSimplex::Status clp_basis_status =
558  clp_->getColumnStatus(MPSolverVarIndexToClpVarIndex(variable_index));
559  return TransformCLPBasisStatus(clp_basis_status);
560 }
561 
562 // ------ Parameters ------
563 
564 void CLPInterface::SetParameters(const MPSolverParameters& param) {
565  SetCommonParameters(param);
566 }
567 
568 void CLPInterface::ResetParameters() {
569  clp_->setPrimalTolerance(MPSolverParameters::kDefaultPrimalTolerance);
570  clp_->setDualTolerance(MPSolverParameters::kDefaultDualTolerance);
571 }
572 
573 void CLPInterface::SetRelativeMipGap(double value) {
574  LOG(WARNING) << "The relative MIP gap is only available "
575  << "for discrete problems.";
576 }
577 
578 void CLPInterface::SetPrimalTolerance(double value) {
579  clp_->setPrimalTolerance(value);
580 }
581 
582 void CLPInterface::SetDualTolerance(double value) {
583  clp_->setDualTolerance(value);
584 }
585 
586 void CLPInterface::SetPresolveMode(int value) {
587  switch (value) {
589  options_->setPresolveType(ClpSolve::presolveOff);
590  break;
591  }
593  options_->setPresolveType(ClpSolve::presolveOn);
594  break;
595  }
596  default: {
598  }
599  }
600 }
601 
602 void CLPInterface::SetScalingMode(int value) {
604 }
605 
606 void CLPInterface::SetLpAlgorithm(int value) {
607  switch (value) {
609  options_->setSolveType(ClpSolve::useDual);
610  break;
611  }
613  options_->setSolveType(ClpSolve::usePrimal);
614  break;
615  }
617  options_->setSolveType(ClpSolve::useBarrier);
618  break;
619  }
620  default: {
622  value);
623  }
624  }
625 }
626 
628  return new CLPInterface(solver);
629 }
630 
631 } // namespace operations_research
632 #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:979
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:416
void SetVariableBounds(int var_index, double lb, double ub) override
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:891
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:887
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:885
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:888
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:889
void SetConstraintBounds(int row_index, double lb, double ub) override