OR-Tools  9.2
glop_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 #include <atomic>
15 #include <cstdint>
16 #include <string>
17 #include <vector>
18 
19 #include "absl/base/attributes.h"
20 #include "ortools/base/hash.h"
22 #include "ortools/base/logging.h"
23 #include "ortools/glop/lp_solver.h"
31 
32 namespace operations_research {
33 
34 namespace {} // Anonymous namespace
35 
37  public:
38  explicit GLOPInterface(MPSolver* const solver);
39  ~GLOPInterface() override;
40 
41  // ----- Solve -----
42  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
43  bool InterruptSolve() override;
44 
45  // ----- Model modifications and extraction -----
46  void Reset() override;
47  void SetOptimizationDirection(bool maximize) override;
48  void SetVariableBounds(int index, double lb, double ub) override;
49  void SetVariableInteger(int index, bool integer) override;
50  void SetConstraintBounds(int index, double lb, double ub) override;
51  void AddRowConstraint(MPConstraint* const ct) override;
52  void AddVariable(MPVariable* const var) override;
53  void SetCoefficient(MPConstraint* const constraint,
54  const MPVariable* const variable, double new_value,
55  double old_value) override;
56  void ClearConstraint(MPConstraint* const constraint) override;
57  void SetObjectiveCoefficient(const MPVariable* const variable,
58  double coefficient) override;
59  void SetObjectiveOffset(double value) override;
60  void ClearObjective() override;
61 
62  // ------ Query statistics on the solution and the solve ------
63  int64_t iterations() const override;
64  int64_t nodes() const override;
65  MPSolver::BasisStatus row_status(int constraint_index) const override;
66  MPSolver::BasisStatus column_status(int variable_index) const override;
67 
68  // ----- Misc -----
69  bool IsContinuous() const override;
70  bool IsLP() const override;
71  bool IsMIP() const override;
72 
73  std::string SolverVersion() const override;
74  void* underlying_solver() override;
75 
76  void ExtractNewVariables() override;
77  void ExtractNewConstraints() override;
78  void ExtractObjective() override;
79 
80  void SetStartingLpBasis(
81  const std::vector<MPSolver::BasisStatus>& variable_statuses,
82  const std::vector<MPSolver::BasisStatus>& constraint_statuses) override;
83 
84  void SetParameters(const MPSolverParameters& param) override;
85  void SetRelativeMipGap(double value) override;
86  void SetPrimalTolerance(double value) override;
87  void SetDualTolerance(double value) override;
88  void SetPresolveMode(int value) override;
89  void SetScalingMode(int value) override;
90  void SetLpAlgorithm(int value) override;
92  const std::string& parameters) override;
93 
94  private:
95  void NonIncrementalChange();
96 
97  glop::LinearProgram linear_program_;
98  glop::LPSolver lp_solver_;
99  std::vector<MPSolver::BasisStatus> column_status_;
100  std::vector<MPSolver::BasisStatus> row_status_;
101  glop::GlopParameters parameters_;
102  std::atomic<bool> interrupt_solver_;
103 };
104 
106  : MPSolverInterface(solver),
107  linear_program_(),
108  lp_solver_(),
109  column_status_(),
110  row_status_(),
111  parameters_(),
112  interrupt_solver_(false) {}
113 
115 
117  // Re-extract the problem from scratch. We don't support modifying the
118  // LinearProgram in sync with changes done in the MPSolver.
120  linear_program_.Clear();
121  interrupt_solver_ = false;
122  ExtractModel();
123  SetParameters(param);
124 
125  linear_program_.SetMaximizationProblem(maximize_);
126  linear_program_.CleanUp();
127 
128  // Time limit.
129  if (solver_->time_limit()) {
130  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
131  parameters_.set_max_time_in_seconds(
132  static_cast<double>(solver_->time_limit()) / 1000.0);
133  }
134 
136  solver_->solver_specific_parameter_string_);
137  lp_solver_.SetParameters(parameters_);
138  std::unique_ptr<TimeLimit> time_limit =
140  time_limit->RegisterExternalBooleanAsLimit(&interrupt_solver_);
141  const glop::ProblemStatus status =
142  lp_solver_.SolveWithTimeLimit(linear_program_, time_limit.get());
143 
144  // The solution must be marked as synchronized even when no solution exists.
147  objective_value_ = lp_solver_.GetObjectiveValue();
148 
149  const size_t num_vars = solver_->variables_.size();
150  column_status_.resize(num_vars, MPSolver::FREE);
151  for (int var_id = 0; var_id < num_vars; ++var_id) {
152  MPVariable* const var = solver_->variables_[var_id];
153  const glop::ColIndex lp_solver_var_id(var->index());
154 
155  const glop::Fractional solution_value =
156  lp_solver_.variable_values()[lp_solver_var_id];
157  var->set_solution_value(static_cast<double>(solution_value));
158 
159  const glop::Fractional reduced_cost =
160  lp_solver_.reduced_costs()[lp_solver_var_id];
161  var->set_reduced_cost(static_cast<double>(reduced_cost));
162 
163  const glop::VariableStatus variable_status =
164  lp_solver_.variable_statuses()[lp_solver_var_id];
165  column_status_.at(var_id) = GlopToMPSolverVariableStatus(variable_status);
166  }
167 
168  const size_t num_constraints = solver_->constraints_.size();
169  row_status_.resize(num_constraints, MPSolver::FREE);
170  for (int ct_id = 0; ct_id < num_constraints; ++ct_id) {
171  MPConstraint* const ct = solver_->constraints_[ct_id];
172  const glop::RowIndex lp_solver_ct_id(ct->index());
173 
174  const glop::Fractional dual_value =
175  lp_solver_.dual_values()[lp_solver_ct_id];
176  ct->set_dual_value(static_cast<double>(dual_value));
177 
178  const glop::ConstraintStatus constraint_status =
179  lp_solver_.constraint_statuses()[lp_solver_ct_id];
180  row_status_.at(ct_id) = GlopToMPSolverConstraintStatus(constraint_status);
181  }
182 
183  return result_status_;
184 }
185 
187  interrupt_solver_ = true;
188  return true;
189 }
190 
192  // Ignore any incremental info for the next solve. Note that the parameters
193  // will not be reset as we re-read them on each Solve().
194  lp_solver_.Clear();
195 }
196 
198  NonIncrementalChange();
199 }
200 
201 void GLOPInterface::SetVariableBounds(int index, double lb, double ub) {
202  NonIncrementalChange();
203 }
204 
205 void GLOPInterface::SetVariableInteger(int index, bool integer) {
206  LOG(WARNING) << "Glop doesn't deal with integer variables.";
207 }
208 
209 void GLOPInterface::SetConstraintBounds(int index, double lb, double ub) {
210  NonIncrementalChange();
211 }
212 
214  NonIncrementalChange();
215 }
216 
218  NonIncrementalChange();
219 }
220 
222  const MPVariable* const variable,
223  double new_value, double old_value) {
224  NonIncrementalChange();
225 }
226 
228  NonIncrementalChange();
229 }
230 
232  double coefficient) {
233  NonIncrementalChange();
234 }
235 
236 void GLOPInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
237 
238 void GLOPInterface::ClearObjective() { NonIncrementalChange(); }
239 
240 int64_t GLOPInterface::iterations() const {
241  return lp_solver_.GetNumberOfSimplexIterations();
242 }
243 
244 int64_t GLOPInterface::nodes() const {
245  LOG(DFATAL) << "Number of nodes only available for discrete problems";
246  return kUnknownNumberOfNodes;
247 }
248 
250  return row_status_[constraint_index];
251 }
252 
254  return column_status_[variable_index];
255 }
256 
257 bool GLOPInterface::IsContinuous() const { return true; }
258 
259 bool GLOPInterface::IsLP() const { return true; }
260 
261 bool GLOPInterface::IsMIP() const { return false; }
262 
263 std::string GLOPInterface::SolverVersion() const {
264  // TODO(user): Decide how to version glop. Add a GetVersion() to LPSolver.
265  return "Glop-0.0";
266 }
267 
268 void* GLOPInterface::underlying_solver() { return &lp_solver_; }
269 
273 
274  const glop::ColIndex num_cols(solver_->variables_.size());
275  for (glop::ColIndex col(last_variable_index_); col < num_cols; ++col) {
276  MPVariable* const var = solver_->variables_[col.value()];
277  const glop::ColIndex new_col = linear_program_.CreateNewVariable();
278  DCHECK_EQ(new_col, col);
279  set_variable_as_extracted(col.value(), true);
280  linear_program_.SetVariableBounds(col, var->lb(), var->ub());
281  }
282 }
283 
286 
287  const glop::RowIndex num_rows(solver_->constraints_.size());
288  for (glop::RowIndex row(0); row < num_rows; ++row) {
289  MPConstraint* const ct = solver_->constraints_[row.value()];
290  set_constraint_as_extracted(row.value(), true);
291 
292  const double lb = ct->lb();
293  const double ub = ct->ub();
294  const glop::RowIndex new_row = linear_program_.CreateNewConstraint();
295  DCHECK_EQ(new_row, row);
296  linear_program_.SetConstraintBounds(row, lb, ub);
297 
298  for (const auto& entry : ct->coefficients_) {
299  const int var_index = entry.first->index();
300  DCHECK(variable_is_extracted(var_index));
301  const glop::ColIndex col(var_index);
302  const double coeff = entry.second;
303  linear_program_.SetCoefficient(row, col, coeff);
304  }
305  }
306 }
307 
309  linear_program_.SetObjectiveOffset(solver_->Objective().offset());
310  for (const auto& entry : solver_->objective_->coefficients_) {
311  const int var_index = entry.first->index();
312  const glop::ColIndex col(var_index);
313  const double coeff = entry.second;
314  linear_program_.SetObjectiveCoefficient(col, coeff);
315  }
316 }
317 
319  const std::vector<MPSolver::BasisStatus>& variable_statuses,
320  const std::vector<MPSolver::BasisStatus>& constraint_statuses) {
321  glop::VariableStatusRow glop_variable_statuses;
322  glop::ConstraintStatusColumn glop_constraint_statuses;
323  for (const MPSolver::BasisStatus& status : variable_statuses) {
324  glop_variable_statuses.push_back(MPSolverToGlopVariableStatus(status));
325  }
326  for (const MPSolver::BasisStatus& status : constraint_statuses) {
327  glop_constraint_statuses.push_back(MPSolverToGlopConstraintStatus(status));
328  }
329  lp_solver_.SetInitialBasis(glop_variable_statuses, glop_constraint_statuses);
330 }
331 
333  parameters_.Clear();
334  parameters_.set_log_search_progress(!quiet_);
335  SetCommonParameters(param);
337 }
338 
342  value);
343  }
344 }
345 
347  // TODO(user): Modify parameters_ with the correct value.
348  // The problem is that this is set by default by the wrapper to 1e-7 and for
349  // now we want to use higher default tolerances in Glop.
352  value);
353  }
354 }
355 
357  // TODO(user): Modify parameters_ with the correct value.
358  // The problem is that this is set by default by the wrapper to 1e-7 and for
359  // now we want to use higher default tolerances in Glop.
362  }
363 }
364 
366  switch (value) {
368  parameters_.set_use_preprocessing(false);
369  break;
371  parameters_.set_use_preprocessing(true);
372  break;
373  default:
376  }
377  }
378 }
379 
381  switch (value) {
383  parameters_.set_use_scaling(false);
384  break;
386  parameters_.set_use_scaling(true);
387  break;
388  default:
391  }
392  }
393 }
394 
396  switch (value) {
398  parameters_.set_use_dual_simplex(true);
399  break;
401  parameters_.set_use_dual_simplex(false);
402  break;
403  default:
406  value);
407  }
408  }
409 }
410 
412  const std::string& parameters) {
413  // NOTE(user): Android build uses protocol buffers in lite mode, and
414  // parsing data from text format is not supported there. To allow solver
415  // specific parameters from string on Android, we first need to switch to
416  // non-lite version of protocol buffers.
417  if (ProtobufTextFormatMergeFromString(parameters, &parameters_)) {
418  lp_solver_.SetParameters(parameters_);
419  return true;
420  }
421  return false;
422 }
423 
424 void GLOPInterface::NonIncrementalChange() {
425  // The current implementation is not incremental.
427 }
428 
429 // Register GLOP in the global linear solver factory.
431  return new GLOPInterface(solver);
432 }
433 
434 } // namespace operations_research
MPSolver::ResultStatus GlopToMPSolverResultStatus(glop::ProblemStatus s)
Definition: glop_utils.cc:18
MPSolver::BasisStatus column_status(int variable_index) const override
ResultStatus
The status of solving the problem.
void set_variable_as_extracted(int var_index, bool extracted)
void SetScalingMode(int value) override
bool IsContinuous() const override
const GlopParameters & GetParameters() const
Definition: lp_solver.cc:124
int64_t nodes() const override
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:326
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
Definition: lp_solver.cc:238
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
ModelSharedTimeLimit * time_limit
void set_constraint_as_extracted(int ct_index, bool extracted)
#define VLOG(verboselevel)
Definition: base/logging.h:983
const MPObjective & Objective() const
Returns the objective object.
void SetDoubleParamToUnsupportedValue(MPSolverParameters::DoubleParam param, double value)
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:485
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
ColIndex col
Definition: markowitz.cc:183
MPSolver::BasisStatus row_status(int constraint_index) const override
void SetPrimalTolerance(double value) override
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:309
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
Definition: lp_solver.cc:136
void SetRelativeMipGap(double value) override
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:331
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
RowIndex row
Definition: markowitz.cc:182
void SetVariableBounds(int index, double lb, double ub) override
int64_t coefficient
bool ProtobufTextFormatMergeFromString(const std::string &proto_text_string, ProtoType *proto)
std::string SolverVersion() const override
void AddVariable(MPVariable *const var) override
void SetVariableInteger(int index, bool integer) override
void SetObjectiveOffset(double value) override
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
const DenseRow & variable_values() const
Definition: lp_solver.h:101
glop::ConstraintStatus MPSolverToGlopConstraintStatus(MPSolver::BasisStatus s)
Definition: glop_utils.cc:108
void SetParameters(const GlopParameters &parameters)
Definition: lp_solver.cc:112
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
void SetPresolveMode(int value) override
The class for variables of a Mathematical Programming (MP) model.
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
static std::unique_ptr< TimeLimit > FromParameters(const Parameters &parameters)
Creates a time limit object initialized from an object that provides methods max_time_in_seconds() an...
Definition: time_limit.h:160
const int WARNING
Definition: log_severity.h:31
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
void ClearConstraint(MPConstraint *const constraint) override
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final
void SetCommonParameters(const MPSolverParameters &param)
void push_back(const value_type &x)
int index
Definition: pack.cc:509
The class for constraints of a Mathematical Programming (MP) model.
Advanced usage: tolerance for primal feasibility of basic solutions.
#define DCHECK(condition)
Definition: base/logging.h:889
void SetLpAlgorithm(int value) override
Advanced usage: enable or disable matrix scaling.
static constexpr int64_t kUnknownNumberOfNodes
Advanced usage: tolerance for dual feasibility of basic solutions.
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:890
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:249
glop::VariableStatus MPSolverToGlopVariableStatus(MPSolver::BasisStatus s)
Definition: glop_utils.cc:74
const VariableStatusRow & variable_statuses() const
Definition: lp_solver.h:103
GLOPInterface(MPSolver *const solver)
MPSolverInterface * BuildGLOPInterface(MPSolver *const solver)
const ConstraintStatusColumn & constraint_statuses() const
Definition: lp_solver.h:117
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:343
void SetStartingLpBasis(const std::vector< MPSolver::BasisStatus > &variable_statuses, const std::vector< MPSolver::BasisStatus > &constraint_statuses) override
int64_t iterations() const override
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.
MPSolver::BasisStatus GlopToMPSolverConstraintStatus(glop::ConstraintStatus s)
Definition: glop_utils.cc:91
void AddRowConstraint(MPConstraint *const ct) override
SatParameters parameters
This class stores parameter settings for LP and MIP solvers.
IntVar * var
Definition: expr_array.cc:1874
void SetParameters(const MPSolverParameters &param) override
MPSolver::BasisStatus GlopToMPSolverVariableStatus(glop::VariableStatus s)
Definition: glop_utils.cc:57
void SetConstraintBounds(int index, double lb, double ub) override
const DenseColumn & dual_values() const
Definition: lp_solver.h:113
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:317
void SetOptimizationDirection(bool maximize) override
bool SetSolverSpecificParametersAsString(const std::string &parameters) override
double offset() const
Gets the constant term in the objective.
int64_t value
const DenseRow & reduced_costs() const
Definition: lp_solver.h:102
void SetDualTolerance(double value) override
const Constraint * ct
bool variable_is_extracted(int var_index) const