Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
glop_interface.cc
Go to the documentation of this file.
1// Copyright 2010-2025 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 <utility>
19#include <vector>
20
21#include "absl/base/attributes.h"
22#include "absl/log/check.h"
34namespace operations_research {
35
37 public:
38 explicit GLOPInterface(MPSolver* solver);
39 ~GLOPInterface() override;
40
41 // ----- Solve -----
42 MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
43 bool InterruptSolve() override;
44
45 // ----- Directly solve proto is supported ---
46 bool SupportsDirectlySolveProto(std::atomic<bool>* interrupt) const override {
47 return true;
48 }
50 std::atomic<bool>* interrupt) override {
51 return GlopSolveProto(std::move(request), interrupt);
52 }
53
54 // ----- Model modifications and extraction -----
55 void Reset() override;
56 void SetOptimizationDirection(bool maximize) override;
57 void SetVariableBounds(int index, double lb, double ub) override;
58 void SetVariableInteger(int index, bool integer) override;
59 void SetConstraintBounds(int index, double lb, double ub) override;
60 void AddRowConstraint(MPConstraint* ct) override;
61 void AddVariable(MPVariable* var) override;
62 void SetCoefficient(MPConstraint* constraint, const MPVariable* variable,
63 double new_value, double old_value) override;
64 void ClearConstraint(MPConstraint* constraint) override;
65 void SetObjectiveCoefficient(const MPVariable* variable,
66 double coefficient) override;
67 void SetObjectiveOffset(double value) override;
68 void ClearObjective() override;
69
70 // ------ Query statistics on the solution and the solve ------
71 int64_t iterations() const override;
72 int64_t nodes() const override;
73 MPSolver::BasisStatus row_status(int constraint_index) const override;
74 MPSolver::BasisStatus column_status(int variable_index) const override;
75
76 // ----- Misc -----
77 bool IsContinuous() const override;
78 bool IsLP() const override;
79 bool IsMIP() const override;
80
81 std::string SolverVersion() const override;
82 void* underlying_solver() override;
83
84 void ExtractNewVariables() override;
85 void ExtractNewConstraints() override;
86 void ExtractObjective() override;
87
89 const std::vector<MPSolver::BasisStatus>& variable_statuses,
90 const std::vector<MPSolver::BasisStatus>& constraint_statuses) override;
91
92 void SetParameters(const MPSolverParameters& param) override;
93 void SetRelativeMipGap(double value) override;
94 void SetPrimalTolerance(double value) override;
95 void SetDualTolerance(double value) override;
96 void SetPresolveMode(int value) override;
97 void SetScalingMode(int value) override;
98 void SetLpAlgorithm(int value) override;
100 const std::string& parameters) override;
101
102 private:
103 void NonIncrementalChange();
104
105 glop::LinearProgram linear_program_;
106 glop::LPSolver lp_solver_;
107 std::vector<MPSolver::BasisStatus> column_status_;
108 std::vector<MPSolver::BasisStatus> row_status_;
109 glop::GlopParameters parameters_;
110 std::atomic<bool> interrupt_solver_;
111};
112
114 : MPSolverInterface(solver),
115 linear_program_(),
116 lp_solver_(),
117 column_status_(),
118 row_status_(),
119 parameters_(),
120 interrupt_solver_(false) {}
121
123
125 // Re-extract the problem from scratch. We don't support modifying the
126 // LinearProgram in sync with changes done in the MPSolver.
128 linear_program_.Clear();
129 interrupt_solver_ = false;
130 ExtractModel();
131 SetParameters(param);
132
133 linear_program_.SetMaximizationProblem(maximize_);
134 linear_program_.CleanUp();
135
136 // Time limit.
137 if (solver_->time_limit()) {
138 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
139 parameters_.set_max_time_in_seconds(
140 static_cast<double>(solver_->time_limit()) / 1000.0);
141 }
142
143 solver_->SetSolverSpecificParametersAsString(
144 solver_->solver_specific_parameter_string_);
145 lp_solver_.SetParameters(parameters_);
146 std::unique_ptr<TimeLimit> time_limit =
147 TimeLimit::FromParameters(lp_solver_.GetParameters());
148 time_limit->RegisterExternalBooleanAsLimit(&interrupt_solver_);
149 const glop::ProblemStatus status =
150 lp_solver_.SolveWithTimeLimit(linear_program_, time_limit.get());
151
152 // The solution must be marked as synchronized even when no solution exists.
155 objective_value_ = lp_solver_.GetObjectiveValue();
156
157 const int num_vars = solver_->variables_.size();
158 column_status_.resize(num_vars, MPSolver::FREE);
159 for (int var_id = 0; var_id < num_vars; ++var_id) {
160 MPVariable* const var = solver_->variables_[var_id];
161 const glop::ColIndex lp_solver_var_id(var->index());
162
163 const glop::Fractional solution_value =
164 lp_solver_.variable_values()[lp_solver_var_id];
165 var->set_solution_value(static_cast<double>(solution_value));
166
167 const glop::Fractional reduced_cost =
168 lp_solver_.reduced_costs()[lp_solver_var_id];
169 var->set_reduced_cost(static_cast<double>(reduced_cost));
170
171 const glop::VariableStatus variable_status =
172 lp_solver_.variable_statuses()[lp_solver_var_id];
173 column_status_.at(var_id) = GlopToMPSolverVariableStatus(variable_status);
174 }
175
176 const int num_constraints = solver_->constraints_.size();
177 row_status_.resize(num_constraints, MPSolver::FREE);
178 for (int ct_id = 0; ct_id < num_constraints; ++ct_id) {
179 MPConstraint* const ct = solver_->constraints_[ct_id];
180 const glop::RowIndex lp_solver_ct_id(ct->index());
181
182 const glop::Fractional dual_value =
183 lp_solver_.dual_values()[lp_solver_ct_id];
184 ct->set_dual_value(static_cast<double>(dual_value));
185
186 const glop::ConstraintStatus constraint_status =
187 lp_solver_.constraint_statuses()[lp_solver_ct_id];
188 row_status_.at(ct_id) = GlopToMPSolverConstraintStatus(constraint_status);
189 }
190
191 return result_status_;
192}
193
195 interrupt_solver_ = true;
196 return true;
197}
198
200 // Ignore any incremental info for the next solve. Note that the parameters
201 // will not be reset as we re-read them on each Solve().
202 lp_solver_.Clear();
203}
204
206 NonIncrementalChange();
207}
208
209void GLOPInterface::SetVariableBounds(int index, double lb, double ub) {
210 NonIncrementalChange();
211}
212
213void GLOPInterface::SetVariableInteger(int index, bool integer) {
214 LOG(WARNING) << "Glop doesn't deal with integer variables.";
215}
216
217void GLOPInterface::SetConstraintBounds(int index, double lb, double ub) {
218 NonIncrementalChange();
219}
220
222 NonIncrementalChange();
223}
224
226 NonIncrementalChange();
227}
228
230 const MPVariable* const variable,
231 double new_value, double old_value) {
232 NonIncrementalChange();
233}
234
236 NonIncrementalChange();
237}
238
240 double coefficient) {
241 NonIncrementalChange();
242}
243
244void GLOPInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
245
246void GLOPInterface::ClearObjective() { NonIncrementalChange(); }
247
249 return lp_solver_.GetNumberOfSimplexIterations();
250}
251
252int64_t GLOPInterface::nodes() const {
253 LOG(DFATAL) << "Number of nodes only available for discrete problems";
255}
256
258 return row_status_[constraint_index];
259}
260
262 return column_status_[variable_index];
263}
264
265bool GLOPInterface::IsContinuous() const { return true; }
266
267bool GLOPInterface::IsLP() const { return true; }
268
269bool GLOPInterface::IsMIP() const { return false; }
270
271std::string GLOPInterface::SolverVersion() const {
273}
274
275void* GLOPInterface::underlying_solver() { return &lp_solver_; }
276
278 DCHECK_EQ(0, last_variable_index_);
279 DCHECK_EQ(0, last_constraint_index_);
280
281 const glop::ColIndex num_cols(solver_->variables_.size());
282 for (glop::ColIndex col(last_variable_index_); col < num_cols; ++col) {
283 MPVariable* const var = solver_->variables_[col.value()];
284 const glop::ColIndex new_col = linear_program_.CreateNewVariable();
285 DCHECK_EQ(new_col, col);
286 set_variable_as_extracted(col.value(), true);
287 linear_program_.SetVariableBounds(col, var->lb(), var->ub());
288 }
289}
290
292 DCHECK_EQ(0, last_constraint_index_);
293
294 const glop::RowIndex num_rows(solver_->constraints_.size());
295 for (glop::RowIndex row(0); row < num_rows; ++row) {
296 MPConstraint* const ct = solver_->constraints_[row.value()];
297 set_constraint_as_extracted(row.value(), true);
298
299 const double lb = ct->lb();
300 const double ub = ct->ub();
301 const glop::RowIndex new_row = linear_program_.CreateNewConstraint();
302 DCHECK_EQ(new_row, row);
303 linear_program_.SetConstraintBounds(row, lb, ub);
304
305 for (const auto& entry : ct->coefficients_) {
306 const int var_index = entry.first->index();
307 DCHECK(variable_is_extracted(var_index));
308 const glop::ColIndex col(var_index);
309 const double coeff = entry.second;
310 linear_program_.SetCoefficient(row, col, coeff);
311 }
312 }
313}
314
316 linear_program_.SetObjectiveOffset(solver_->Objective().offset());
317 for (const auto& entry : solver_->objective_->coefficients_) {
318 const int var_index = entry.first->index();
319 const glop::ColIndex col(var_index);
320 const double coeff = entry.second;
321 linear_program_.SetObjectiveCoefficient(col, coeff);
322 }
323}
324
326 const std::vector<MPSolver::BasisStatus>& variable_statuses,
327 const std::vector<MPSolver::BasisStatus>& constraint_statuses) {
328 glop::VariableStatusRow glop_variable_statuses;
329 glop::ConstraintStatusColumn glop_constraint_statuses;
330 for (const MPSolver::BasisStatus& status : variable_statuses) {
331 glop_variable_statuses.push_back(MPSolverToGlopVariableStatus(status));
332 }
333 for (const MPSolver::BasisStatus& status : constraint_statuses) {
334 glop_constraint_statuses.push_back(MPSolverToGlopConstraintStatus(status));
335 }
336 lp_solver_.SetInitialBasis(glop_variable_statuses, glop_constraint_statuses);
337}
338
340 parameters_.Clear();
341 parameters_.set_log_search_progress(!quiet_);
342 SetCommonParameters(param);
344}
345
352
354 // TODO(user): Modify parameters_ with the correct value.
355 // The problem is that this is set by default by the wrapper to 1e-7 and for
356 // now we want to use higher default tolerances in Glop.
359 value);
360 }
361}
362
364 // TODO(user): Modify parameters_ with the correct value.
365 // The problem is that this is set by default by the wrapper to 1e-7 and for
366 // now we want to use higher default tolerances in Glop.
369 }
370}
371
373 switch (value) {
375 parameters_.set_use_preprocessing(false);
376 break;
378 parameters_.set_use_preprocessing(true);
379 break;
380 default:
383 }
384 }
385}
386
388 switch (value) {
390 parameters_.set_use_scaling(false);
391 break;
393 parameters_.set_use_scaling(true);
394 break;
395 default:
398 }
399 }
400}
401
403 switch (value) {
405 parameters_.set_use_dual_simplex(true);
406 break;
408 parameters_.set_use_dual_simplex(false);
409 break;
410 default:
413 value);
414 }
415 }
416}
417
419 const std::string& parameters) {
420 // NOTE(user): Android build uses protocol buffers in lite mode, and
421 // parsing data from text format is not supported there. To allow solver
422 // specific parameters from string on Android, we first need to switch to
423 // non-lite version of protocol buffers.
424 if (ProtobufTextFormatMergeFromString(parameters, &parameters_)) {
425 lp_solver_.SetParameters(parameters_);
426 return true;
427 }
428 return false;
429}
430
431void GLOPInterface::NonIncrementalChange() {
432 // The current implementation is not incremental.
434}
435
436namespace {
437
438// See MpSolverInterfaceFactoryRepository for details.
439const void* const kRegisterGlop ABSL_ATTRIBUTE_UNUSED = [] {
441 [](MPSolver* const solver) { return new GLOPInterface(solver); },
443 return nullptr;
444}();
445
446} // namespace
447
448} // namespace operations_research
void SetParameters(const MPSolverParameters &param) override
void SetRelativeMipGap(double value) override
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
void SetVariableInteger(int index, bool integer) override
bool SetSolverSpecificParametersAsString(const std::string &parameters) override
MPSolutionResponse DirectlySolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt) override
void SetObjectiveOffset(double value) override
void ClearConstraint(MPConstraint *constraint) override
void SetPrimalTolerance(double value) override
void AddRowConstraint(MPConstraint *ct) override
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
MPSolver::BasisStatus row_status(int constraint_index) const override
int64_t iterations() const override
MPSolver::BasisStatus column_status(int variable_index) const override
void SetConstraintBounds(int index, double lb, double ub) override
void SetOptimizationDirection(bool maximize) override
void SetDualTolerance(double value) override
void SetStartingLpBasis(const std::vector< MPSolver::BasisStatus > &variable_statuses, const std::vector< MPSolver::BasisStatus > &constraint_statuses) override
void SetVariableBounds(int index, double lb, double ub) override
std::string SolverVersion() const override
void SetPresolveMode(int value) override
void AddVariable(MPVariable *var) override
void SetScalingMode(int value) override
void SetLpAlgorithm(int value) override
bool SupportsDirectlySolveProto(std::atomic< bool > *interrupt) const override
void set_dual_value(double dual_value)
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
static MPSolverInterfaceFactoryRepository * GetInstance()
void Register(MPSolverInterfaceFactory factory, MPSolver::OptimizationProblemType problem_type, std::function< bool()> is_runtime_ready={})
void set_variable_as_extracted(int var_index, bool extracted)
void set_constraint_as_extracted(int ct_index, bool extracted)
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
bool variable_is_extracted(int var_index) const
static constexpr int64_t kUnknownNumberOfNodes
void SetDoubleParamToUnsupportedValue(MPSolverParameters::DoubleParam param, double value)
void SetCommonParameters(const MPSolverParameters &param)
@ DUAL_TOLERANCE
Advanced usage: tolerance for dual feasibility of basic solutions.
@ RELATIVE_MIP_GAP
Limit for relative MIP gap.
@ PRESOLVE
Advanced usage: presolve mode.
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
The class for variables of a Mathematical Programming (MP) model.
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
void set_reduced_cost(double reduced_cost)
void set_solution_value(double value)
int index() const
Returns the index of the variable in the MPSolver::variables_.
static std::unique_ptr< TimeLimit > FromParameters(const Parameters &parameters)
Definition time_limit.h:143
static std::string GlopVersion()
Definition lp_solver.cc:123
void push_back(const value_type &val)
StrictITIVector< RowIndex, ConstraintStatus > ConstraintStatusColumn
Definition lp_types.h:397
StrictITIVector< ColIndex, VariableStatus > VariableStatusRow
Definition lp_types.h:372
OR-Tools root namespace.
MPSolver::ResultStatus GlopToMPSolverResultStatus(glop::ProblemStatus s)
Definition glop_utils.cc:22
glop::VariableStatus MPSolverToGlopVariableStatus(MPSolver::BasisStatus s)
Definition glop_utils.cc:78
glop::ConstraintStatus MPSolverToGlopConstraintStatus(MPSolver::BasisStatus s)
MPSolutionResponse GlopSolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt_solve, std::function< void(const std::string &)> logging_callback)
bool ProtobufTextFormatMergeFromString(absl::string_view proto_text_string, ProtoType *proto)
Definition proto_utils.h:79
MPSolver::BasisStatus GlopToMPSolverConstraintStatus(glop::ConstraintStatus s)
Definition glop_utils.cc:95
MPSolver::BasisStatus GlopToMPSolverVariableStatus(glop::VariableStatus s)
Definition glop_utils.cc:61