OR-Tools  9.0
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 "ortools/base/hash.h"
21 #include "ortools/base/logging.h"
22 #include "ortools/glop/lp_solver.h"
30 
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_);
140  const glop::ProblemStatus status =
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 {
263  // TODO(user): Decide how to version glop. Add a GetVersion() to LPSolver.
264  return "Glop-0.0";
265 }
266 
267 void* GLOPInterface::underlying_solver() { return &lp_solver_; }
268 
272 
273  const glop::ColIndex num_cols(solver_->variables_.size());
274  for (glop::ColIndex col(last_variable_index_); col < num_cols; ++col) {
275  MPVariable* const var = solver_->variables_[col.value()];
276  const glop::ColIndex new_col = linear_program_.CreateNewVariable();
277  DCHECK_EQ(new_col, col);
278  set_variable_as_extracted(col.value(), true);
279  linear_program_.SetVariableBounds(col, var->lb(), var->ub());
280  }
281 }
282 
285 
286  const glop::RowIndex num_rows(solver_->constraints_.size());
287  for (glop::RowIndex row(0); row < num_rows; ++row) {
288  MPConstraint* const ct = solver_->constraints_[row.value()];
289  set_constraint_as_extracted(row.value(), true);
290 
291  const double lb = ct->lb();
292  const double ub = ct->ub();
293  const glop::RowIndex new_row = linear_program_.CreateNewConstraint();
294  DCHECK_EQ(new_row, row);
295  linear_program_.SetConstraintBounds(row, lb, ub);
296 
297  for (const auto& entry : ct->coefficients_) {
298  const int var_index = entry.first->index();
299  DCHECK(variable_is_extracted(var_index));
300  const glop::ColIndex col(var_index);
301  const double coeff = entry.second;
302  linear_program_.SetCoefficient(row, col, coeff);
303  }
304  }
305 }
306 
308  linear_program_.SetObjectiveOffset(solver_->Objective().offset());
309  for (const auto& entry : solver_->objective_->coefficients_) {
310  const int var_index = entry.first->index();
311  const glop::ColIndex col(var_index);
312  const double coeff = entry.second;
313  linear_program_.SetObjectiveCoefficient(col, coeff);
314  }
315 }
316 
318  const std::vector<MPSolver::BasisStatus>& variable_statuses,
319  const std::vector<MPSolver::BasisStatus>& constraint_statuses) {
320  glop::VariableStatusRow glop_variable_statuses;
321  glop::ConstraintStatusColumn glop_constraint_statuses;
322  for (const MPSolver::BasisStatus& status : variable_statuses) {
323  glop_variable_statuses.push_back(MPSolverToGlopVariableStatus(status));
324  }
325  for (const MPSolver::BasisStatus& status : constraint_statuses) {
326  glop_constraint_statuses.push_back(MPSolverToGlopConstraintStatus(status));
327  }
328  lp_solver_.SetInitialBasis(glop_variable_statuses, glop_constraint_statuses);
329 }
330 
332  parameters_.Clear();
333  parameters_.set_log_search_progress(!quiet_);
334  SetCommonParameters(param);
336 }
337 
341  value);
342  }
343 }
344 
346  // TODO(user): Modify parameters_ with the correct value.
347  // The problem is that this is set by default by the wrapper to 1e-7 and for
348  // now we want to use higher default tolerances in Glop.
351  value);
352  }
353 }
354 
356  // TODO(user): Modify parameters_ with the correct value.
357  // The problem is that this is set by default by the wrapper to 1e-7 and for
358  // now we want to use higher default tolerances in Glop.
361  }
362 }
363 
365  switch (value) {
367  parameters_.set_use_preprocessing(false);
368  break;
370  parameters_.set_use_preprocessing(true);
371  break;
372  default:
375  }
376  }
377 }
378 
380  switch (value) {
382  parameters_.set_use_scaling(false);
383  break;
385  parameters_.set_use_scaling(true);
386  break;
387  default:
390  }
391  }
392 }
393 
395  switch (value) {
397  parameters_.set_use_dual_simplex(true);
398  break;
400  parameters_.set_use_dual_simplex(false);
401  break;
402  default:
405  value);
406  }
407  }
408 }
409 
411  const std::string& parameters) {
412  // NOTE(user): Android build uses protocol buffers in lite mode, and
413  // parsing data from text format is not supported there. To allow solver
414  // specific parameters from string on Android, we first need to switch to
415  // non-lite version of protocol buffers.
416  if (ProtobufTextFormatMergeFromString(parameters, &parameters_)) {
417  lp_solver_.SetParameters(parameters_);
418  return true;
419  }
420  return false;
421 }
422 
423 void GLOPInterface::NonIncrementalChange() {
424  // The current implementation is not incremental.
426 }
427 
428 // Register GLOP in the global linear solver factory.
430  return new GLOPInterface(solver);
431 }
432 
433 } // namespace operations_research
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
#define VLOG(verboselevel)
Definition: base/logging.h:986
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:128
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
Definition: lp_solver.cc:241
const ConstraintStatusColumn & constraint_statuses() const
Definition: lp_solver.h:116
const VariableStatusRow & variable_statuses() const
Definition: lp_solver.h:102
const DenseColumn & dual_values() const
Definition: lp_solver.h:112
const DenseRow & variable_values() const
Definition: lp_solver.h:100
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:487
const DenseRow & reduced_costs() const
Definition: lp_solver.h:101
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
Definition: lp_solver.cc:138
void SetParameters(const GlopParameters &parameters)
Definition: lp_solver.cc:116
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:249
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:331
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:317
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:309
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:326
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:343
SatParameters parameters
SharedTimeLimit * time_limit
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
ColIndex col
Definition: markowitz.cc:183
RowIndex row
Definition: markowitz.cc:182
Collection of objects used to extend the Constraint Solver library.
MPSolver::BasisStatus GlopToMPSolverVariableStatus(glop::VariableStatus s)
Definition: glop_utils.cc:57
bool ProtobufTextFormatMergeFromString(const std::string &proto_text_string, ProtoType *proto)
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
int index
Definition: pack.cc:509
int64_t coefficient