OR-Tools  9.1
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"
30
31namespace operations_research {
32
33namespace {} // 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
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
200void GLOPInterface::SetVariableBounds(int index, double lb, double ub) {
201 NonIncrementalChange();
202}
203
205 LOG(WARNING) << "Glop doesn't deal with integer variables.";
206}
207
208void 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
235void GLOPInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
236
237void GLOPInterface::ClearObjective() { NonIncrementalChange(); }
238
240 return lp_solver_.GetNumberOfSimplexIterations();
241}
242
243int64_t GLOPInterface::nodes() const {
244 LOG(DFATAL) << "Number of nodes only available for discrete problems";
246}
247
249 return row_status_[constraint_index];
250}
251
253 return column_status_[variable_index];
254}
255
256bool GLOPInterface::IsContinuous() const { return true; }
257
258bool GLOPInterface::IsLP() const { return true; }
259
260bool GLOPInterface::IsMIP() const { return false; }
261
262std::string GLOPInterface::SolverVersion() const {
263 // TODO(user): Decide how to version glop. Add a GetVersion() to LPSolver.
264 return "Glop-0.0";
265}
266
267void* 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.
417 lp_solver_.SetParameters(parameters_);
418 return true;
419 }
420 return false;
421}
422
423void 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:416
#define DCHECK(condition)
Definition: base/logging.h:885
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:886
#define VLOG(verboselevel)
Definition: base/logging.h:979
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 ...
ResultStatus
The status of solving the problem.
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
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)
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
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final
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 DenseColumn & dual_values() const
Definition: lp_solver.h:112
const VariableStatusRow & variable_statuses() const
Definition: lp_solver.h:102
const ConstraintStatusColumn & constraint_statuses() const
Definition: lp_solver.h:116
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:487
const DenseRow & variable_values() const
Definition: lp_solver.h:100
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
ModelSharedTimeLimit * 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