OR-Tools  9.6
glop_interface.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 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 <memory>
17 #include <string>
18 #include <vector>
19 
20 #include "absl/base/attributes.h"
22 #include "ortools/base/logging.h"
23 #include "ortools/glop/lp_solver.h"
24 #include "ortools/glop/parameters.pb.h"
31 namespace operations_research {
32 
33 namespace {} // Anonymous namespace
34 
36  public:
37  explicit GLOPInterface(MPSolver* const solver);
38  ~GLOPInterface() override;
39 
40  // ----- Solve -----
41  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
42  bool InterruptSolve() override;
43 
44  // ----- Model modifications and extraction -----
45  void Reset() override;
46  void SetOptimizationDirection(bool maximize) override;
47  void SetVariableBounds(int index, double lb, double ub) override;
48  void SetVariableInteger(int index, bool integer) override;
49  void SetConstraintBounds(int index, double lb, double ub) override;
50  void AddRowConstraint(MPConstraint* const ct) override;
51  void AddVariable(MPVariable* const var) override;
52  void SetCoefficient(MPConstraint* const constraint,
53  const MPVariable* const variable, double new_value,
54  double old_value) override;
55  void ClearConstraint(MPConstraint* const constraint) override;
56  void SetObjectiveCoefficient(const MPVariable* const variable,
57  double coefficient) override;
58  void SetObjectiveOffset(double value) override;
59  void ClearObjective() override;
60 
61  // ------ Query statistics on the solution and the solve ------
62  int64_t iterations() const override;
63  int64_t nodes() const override;
64  MPSolver::BasisStatus row_status(int constraint_index) const override;
65  MPSolver::BasisStatus column_status(int variable_index) const override;
66 
67  // ----- Misc -----
68  bool IsContinuous() const override;
69  bool IsLP() const override;
70  bool IsMIP() const override;
71 
72  std::string SolverVersion() const override;
73  void* underlying_solver() override;
74 
75  void ExtractNewVariables() override;
76  void ExtractNewConstraints() override;
77  void ExtractObjective() override;
78 
79  void SetStartingLpBasis(
80  const std::vector<MPSolver::BasisStatus>& variable_statuses,
81  const std::vector<MPSolver::BasisStatus>& constraint_statuses) override;
82 
83  void SetParameters(const MPSolverParameters& param) override;
84  void SetRelativeMipGap(double value) override;
85  void SetPrimalTolerance(double value) override;
86  void SetDualTolerance(double value) override;
87  void SetPresolveMode(int value) override;
88  void SetScalingMode(int value) override;
89  void SetLpAlgorithm(int value) override;
91  const std::string& parameters) override;
92 
93  private:
94  void NonIncrementalChange();
95 
96  glop::LinearProgram linear_program_;
97  glop::LPSolver lp_solver_;
98  std::vector<MPSolver::BasisStatus> column_status_;
99  std::vector<MPSolver::BasisStatus> row_status_;
100  glop::GlopParameters parameters_;
101  std::atomic<bool> interrupt_solver_;
102 };
103 
105  : MPSolverInterface(solver),
106  linear_program_(),
107  lp_solver_(),
108  column_status_(),
109  row_status_(),
110  parameters_(),
111  interrupt_solver_(false) {}
112 
114 
116  // Re-extract the problem from scratch. We don't support modifying the
117  // LinearProgram in sync with changes done in the MPSolver.
119  linear_program_.Clear();
120  interrupt_solver_ = false;
121  ExtractModel();
122  SetParameters(param);
123 
124  linear_program_.SetMaximizationProblem(maximize_);
125  linear_program_.CleanUp();
126 
127  // Time limit.
128  if (solver_->time_limit()) {
129  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
130  parameters_.set_max_time_in_seconds(
131  static_cast<double>(solver_->time_limit()) / 1000.0);
132  }
133 
135  solver_->solver_specific_parameter_string_);
136  lp_solver_.SetParameters(parameters_);
137  std::unique_ptr<TimeLimit> time_limit =
139  time_limit->RegisterExternalBooleanAsLimit(&interrupt_solver_);
141  lp_solver_.SolveWithTimeLimit(linear_program_, time_limit.get());
142 
143  // The solution must be marked as synchronized even when no solution exists.
146  objective_value_ = lp_solver_.GetObjectiveValue();
147 
148  const size_t num_vars = solver_->variables_.size();
149  column_status_.resize(num_vars, MPSolver::FREE);
150  for (int var_id = 0; var_id < num_vars; ++var_id) {
151  MPVariable* const var = solver_->variables_[var_id];
152  const glop::ColIndex lp_solver_var_id(var->index());
153 
154  const glop::Fractional solution_value =
155  lp_solver_.variable_values()[lp_solver_var_id];
156  var->set_solution_value(static_cast<double>(solution_value));
157 
158  const glop::Fractional reduced_cost =
159  lp_solver_.reduced_costs()[lp_solver_var_id];
160  var->set_reduced_cost(static_cast<double>(reduced_cost));
161 
162  const glop::VariableStatus variable_status =
163  lp_solver_.variable_statuses()[lp_solver_var_id];
164  column_status_.at(var_id) = GlopToMPSolverVariableStatus(variable_status);
165  }
166 
167  const size_t num_constraints = solver_->constraints_.size();
168  row_status_.resize(num_constraints, MPSolver::FREE);
169  for (int ct_id = 0; ct_id < num_constraints; ++ct_id) {
170  MPConstraint* const ct = solver_->constraints_[ct_id];
171  const glop::RowIndex lp_solver_ct_id(ct->index());
172 
173  const glop::Fractional dual_value =
174  lp_solver_.dual_values()[lp_solver_ct_id];
175  ct->set_dual_value(static_cast<double>(dual_value));
176 
177  const glop::ConstraintStatus constraint_status =
178  lp_solver_.constraint_statuses()[lp_solver_ct_id];
179  row_status_.at(ct_id) = GlopToMPSolverConstraintStatus(constraint_status);
180  }
181 
182  return result_status_;
183 }
184 
186  interrupt_solver_ = true;
187  return true;
188 }
189 
191  // Ignore any incremental info for the next solve. Note that the parameters
192  // will not be reset as we re-read them on each Solve().
193  lp_solver_.Clear();
194 }
195 
197  NonIncrementalChange();
198 }
199 
200 void GLOPInterface::SetVariableBounds(int index, double lb, double ub) {
201  NonIncrementalChange();
202 }
203 
204 void GLOPInterface::SetVariableInteger(int index, bool integer) {
205  LOG(WARNING) << "Glop doesn't deal with integer variables.";
206 }
207 
208 void GLOPInterface::SetConstraintBounds(int index, double lb, double ub) {
209  NonIncrementalChange();
210 }
211 
213  NonIncrementalChange();
214 }
215 
217  NonIncrementalChange();
218 }
219 
221  const MPVariable* const variable,
222  double new_value, double old_value) {
223  NonIncrementalChange();
224 }
225 
227  NonIncrementalChange();
228 }
229 
231  double coefficient) {
232  NonIncrementalChange();
233 }
234 
235 void GLOPInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
236 
237 void GLOPInterface::ClearObjective() { NonIncrementalChange(); }
238 
239 int64_t GLOPInterface::iterations() const {
240  return lp_solver_.GetNumberOfSimplexIterations();
241 }
242 
243 int64_t GLOPInterface::nodes() const {
244  LOG(DFATAL) << "Number of nodes only available for discrete problems";
245  return kUnknownNumberOfNodes;
246 }
247 
249  return row_status_[constraint_index];
250 }
251 
253  return column_status_[variable_index];
254 }
255 
256 bool GLOPInterface::IsContinuous() const { return true; }
257 
258 bool GLOPInterface::IsLP() const { return true; }
259 
260 bool GLOPInterface::IsMIP() const { return false; }
261 
262 std::string GLOPInterface::SolverVersion() const {
264 }
265 
266 void* GLOPInterface::underlying_solver() { return &lp_solver_; }
267 
269  DCHECK_EQ(0, last_variable_index_);
270  DCHECK_EQ(0, last_constraint_index_);
271 
272  const glop::ColIndex num_cols(solver_->variables_.size());
273  for (glop::ColIndex col(last_variable_index_); col < num_cols; ++col) {
274  MPVariable* const var = solver_->variables_[col.value()];
275  const glop::ColIndex new_col = linear_program_.CreateNewVariable();
276  DCHECK_EQ(new_col, col);
277  set_variable_as_extracted(col.value(), true);
278  linear_program_.SetVariableBounds(col, var->lb(), var->ub());
279  }
280 }
281 
283  DCHECK_EQ(0, last_constraint_index_);
284 
285  const glop::RowIndex num_rows(solver_->constraints_.size());
286  for (glop::RowIndex row(0); row < num_rows; ++row) {
287  MPConstraint* const ct = solver_->constraints_[row.value()];
288  set_constraint_as_extracted(row.value(), true);
289 
290  const double lb = ct->lb();
291  const double ub = ct->ub();
292  const glop::RowIndex new_row = linear_program_.CreateNewConstraint();
293  DCHECK_EQ(new_row, row);
294  linear_program_.SetConstraintBounds(row, lb, ub);
295 
296  for (const auto& entry : ct->coefficients_) {
297  const int var_index = entry.first->index();
298  DCHECK(variable_is_extracted(var_index));
299  const glop::ColIndex col(var_index);
300  const double coeff = entry.second;
301  linear_program_.SetCoefficient(row, col, coeff);
302  }
303  }
304 }
305 
307  linear_program_.SetObjectiveOffset(solver_->Objective().offset());
308  for (const auto& entry : solver_->objective_->coefficients_) {
309  const int var_index = entry.first->index();
310  const glop::ColIndex col(var_index);
311  const double coeff = entry.second;
312  linear_program_.SetObjectiveCoefficient(col, coeff);
313  }
314 }
315 
317  const std::vector<MPSolver::BasisStatus>& variable_statuses,
318  const std::vector<MPSolver::BasisStatus>& constraint_statuses) {
319  glop::VariableStatusRow glop_variable_statuses;
320  glop::ConstraintStatusColumn glop_constraint_statuses;
321  for (const MPSolver::BasisStatus& status : variable_statuses) {
322  glop_variable_statuses.push_back(MPSolverToGlopVariableStatus(status));
323  }
324  for (const MPSolver::BasisStatus& status : constraint_statuses) {
325  glop_constraint_statuses.push_back(MPSolverToGlopConstraintStatus(status));
326  }
327  lp_solver_.SetInitialBasis(glop_variable_statuses, glop_constraint_statuses);
328 }
329 
331  parameters_.Clear();
332  parameters_.set_log_search_progress(!quiet_);
333  SetCommonParameters(param);
335 }
336 
340  value);
341  }
342 }
343 
345  // TODO(user): Modify parameters_ with the correct value.
346  // The problem is that this is set by default by the wrapper to 1e-7 and for
347  // now we want to use higher default tolerances in Glop.
350  value);
351  }
352 }
353 
355  // TODO(user): Modify parameters_ with the correct value.
356  // The problem is that this is set by default by the wrapper to 1e-7 and for
357  // now we want to use higher default tolerances in Glop.
360  }
361 }
362 
364  switch (value) {
366  parameters_.set_use_preprocessing(false);
367  break;
369  parameters_.set_use_preprocessing(true);
370  break;
371  default:
374  }
375  }
376 }
377 
379  switch (value) {
381  parameters_.set_use_scaling(false);
382  break;
384  parameters_.set_use_scaling(true);
385  break;
386  default:
389  }
390  }
391 }
392 
394  switch (value) {
396  parameters_.set_use_dual_simplex(true);
397  break;
399  parameters_.set_use_dual_simplex(false);
400  break;
401  default:
404  value);
405  }
406  }
407 }
408 
410  const std::string& parameters) {
411  // NOTE(user): Android build uses protocol buffers in lite mode, and
412  // parsing data from text format is not supported there. To allow solver
413  // specific parameters from string on Android, we first need to switch to
414  // non-lite version of protocol buffers.
415  if (ProtobufTextFormatMergeFromString(parameters, &parameters_)) {
416  lp_solver_.SetParameters(parameters_);
417  return true;
418  }
419  return false;
420 }
421 
422 void GLOPInterface::NonIncrementalChange() {
423  // The current implementation is not incremental.
425 }
426 
427 // Register GLOP in the global linear solver factory.
429  return new GLOPInterface(solver);
430 }
431 
432 } // namespace operations_research
void push_back(const value_type &x)
void SetScalingMode(int value) override
void SetDualTolerance(double value) override
void AddRowConstraint(MPConstraint *const ct) override
void SetLpAlgorithm(int value) override
bool IsContinuous() const override
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
void SetPrimalTolerance(double value) override
void ClearConstraint(MPConstraint *const constraint) override
bool SetSolverSpecificParametersAsString(const std::string &parameters) 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
void SetObjectiveOffset(double value) override
void SetVariableInteger(int index, bool integer) override
void SetParameters(const MPSolverParameters &param) override
std::string SolverVersion() const override
void SetRelativeMipGap(double value) override
void SetConstraintBounds(int index, double lb, double ub) override
void SetPresolveMode(int value) override
void SetVariableBounds(int index, double lb, double ub) override
void AddVariable(MPVariable *const var) override
int64_t nodes() const override
int64_t iterations() const override
GLOPInterface(MPSolver *const solver)
void SetOptimizationDirection(bool maximize) override
MPSolver::BasisStatus column_status(int variable_index) const override
void SetStartingLpBasis(const std::vector< MPSolver::BasisStatus > &variable_statuses, const std::vector< MPSolver::BasisStatus > &constraint_statuses) override
The class for constraints of a Mathematical Programming (MP) model.
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 ...
const MPObjective & Objective() const
Returns the objective object.
ResultStatus
The status of solving the problem.
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
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)
static constexpr int64_t kUnknownNumberOfNodes
bool variable_is_extracted(int var_index) const
void SetDoubleParamToUnsupportedValue(MPSolverParameters::DoubleParam param, double value)
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.
@ DUAL_TOLERANCE
Advanced usage: tolerance for dual feasibility of basic solutions.
@ PRIMAL_TOLERANCE
Advanced usage: tolerance for primal feasibility of basic solutions.
@ RELATIVE_MIP_GAP
Limit for relative MIP gap.
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
@ PRESOLVE
Advanced usage: presolve mode.
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
The class for variables of a Mathematical Programming (MP) model.
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:159
const GlopParameters & GetParameters() const
Definition: lp_solver.cc:130
static std::string GlopVersion()
Definition: lp_solver.cc:114
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
Definition: lp_solver.cc:261
const ConstraintStatusColumn & constraint_statuses() const
Definition: lp_solver.h:121
const VariableStatusRow & variable_statuses() const
Definition: lp_solver.h:107
const DenseColumn & dual_values() const
Definition: lp_solver.h:117
const DenseRow & variable_values() const
Definition: lp_solver.h:105
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:508
const DenseRow & reduced_costs() const
Definition: lp_solver.h:106
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
Definition: lp_solver.cc:142
void SetParameters(const GlopParameters &parameters)
Definition: lp_solver.cc:118
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:250
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:332
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:318
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:310
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:327
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:344
SatParameters parameters
ModelSharedTimeLimit * time_limit
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
absl::Status status
Definition: g_gurobi.cc:41
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
int index
ColIndex col
Definition: markowitz.cc:186
RowIndex row
Definition: markowitz.cc:185
Collection of objects used to extend the Constraint Solver library.
MPSolver::BasisStatus GlopToMPSolverVariableStatus(glop::VariableStatus s)
Definition: glop_utils.cc:57
MPSolver::BasisStatus GlopToMPSolverConstraintStatus(glop::ConstraintStatus s)
Definition: glop_utils.cc:91
MPSolver::ResultStatus GlopToMPSolverResultStatus(glop::ProblemStatus s)
Definition: glop_utils.cc:18
glop::VariableStatus MPSolverToGlopVariableStatus(MPSolver::BasisStatus s)
Definition: glop_utils.cc:74
MPSolverInterface * BuildGLOPInterface(MPSolver *const solver)
glop::ConstraintStatus MPSolverToGlopConstraintStatus(MPSolver::BasisStatus s)
Definition: glop_utils.cc:108
bool ProtobufTextFormatMergeFromString(absl::string_view proto_text_string, ProtoType *proto)
int64_t coefficient
#define VLOG(verboselevel)
Definition: vlog.h:39