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"
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
41namespace 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
156namespace {
157// Variable indices are shifted by 1 internally because of the dummy "objective
158// offset" variable (with internal index 0).
159int MPSolverVarIndexToClpVarIndex(int var_index) { return var_index + 1; }
160} // namespace
161
162// Not cached
165 clp_->setOptimizationDirection(maximize ? -1 : 1);
166}
167
168void 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
173 clp_->setColumnBounds(MPSolverVarIndexToClpVarIndex(var_index), lb, ub);
174 } else {
176 }
177}
178
179// Ignore as CLP does not solve models with integer variables
180void CLPInterface::SetVariableInteger(int var_index, bool integer) {}
181
182void 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_);
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
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
272void 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_) {
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];
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];
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];
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];
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
513MPSolver::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:
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
538 return clp_->getIterationCount();
539}
540
541int64_t CLPInterface::nodes() const {
542 LOG(DFATAL) << "Number of nodes only available for discrete problems";
544}
545
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
564void CLPInterface::SetParameters(const MPSolverParameters& param) {
565 SetCommonParameters(param);
566}
567
568void CLPInterface::ResetParameters() {
569 clp_->setPrimalTolerance(MPSolverParameters::kDefaultPrimalTolerance);
570 clp_->setDualTolerance(MPSolverParameters::kDefaultDualTolerance);
571}
572
573void CLPInterface::SetRelativeMipGap(double value) {
574 LOG(WARNING) << "The relative MIP gap is only available "
575 << "for discrete problems.";
576}
577
578void CLPInterface::SetPrimalTolerance(double value) {
579 clp_->setPrimalTolerance(value);
580}
581
582void CLPInterface::SetDualTolerance(double value) {
583 clp_->setDualTolerance(value);
584}
585
586void 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
602void CLPInterface::SetScalingMode(int value) {
604}
605
606void 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)
int64_t max
Definition: alldiff_cst.cc:140
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:888
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:887
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:891
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:889
#define LOG(severity)
Definition: base/logging.h:416
#define DCHECK(condition)
Definition: base/logging.h:885
#define VLOG(verboselevel)
Definition: base/logging.h:979
void Start()
Definition: timer.h:31
void Restart()
Definition: timer.h:35
double Get() const
Definition: timer.h:45
void AddRowConstraint(MPConstraint *const ct) override
bool IsContinuous() const override
void SetConstraintBounds(int row_index, double lb, double ub) override
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
void ClearConstraint(MPConstraint *const constraint) override
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
MPSolver::BasisStatus row_status(int constraint_index) const override
CLPInterface(MPSolver *const solver)
void SetVariableInteger(int var_index, bool integer) override
void SetObjectiveOffset(double offset) override
std::string SolverVersion() const override
void AddVariable(MPVariable *const var) override
int64_t nodes() const override
void SetVariableBounds(int var_index, double lb, double ub) override
int64_t iterations() const override
void SetOptimizationDirection(bool maximize) override
MPSolver::BasisStatus column_status(int variable_index) const override
The class for constraints of a Mathematical Programming (MP) model.
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
double offset() const
Gets the constant term in the objective.
This mathematical programming (MP) solver class is the main class though which users build and solve ...
ResultStatus
The status of solving the problem.
@ FEASIBLE
feasible, or stopped by limit.
@ INFEASIBLE
proven infeasible.
@ UNBOUNDED
proven unbounded.
@ ABNORMAL
abnormal, i.e., error of some kind.
const MPObjective & Objective() const
Returns the objective object.
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
void set_constraint_as_extracted(int ct_index, bool extracted)
bool constraint_is_extracted(int ct_index) const
static constexpr int64_t kUnknownNumberOfNodes
bool variable_is_extracted(int var_index) const
static constexpr int64_t kUnknownNumberOfIterations
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
void set_variable_as_extracted(int var_index, bool extracted)
void SetCommonParameters(const MPSolverParameters &param)
This class stores parameter settings for LP and MIP solvers.
@ INCREMENTALITY_OFF
Start solve from scratch.
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
@ PRESOLVE
Advanced usage: presolve mode.
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
The class for variables of a Mathematical Programming (MP) model.
int index() const
Returns the index of the variable in the MPSolver::variables_.
const std::string name
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
const int WARNING
Definition: log_severity.h:31
const int FATAL
Definition: log_severity.h:32
Collection of objects used to extend the Constraint Solver library.
MPSolverInterface * BuildCLPInterface(MPSolver *const solver)
int index
Definition: pack.cc:509
int64_t coefficient