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"
31
32namespace operations_research {
33
34namespace {} // 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
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
201void GLOPInterface::SetVariableBounds(int index, double lb, double ub) {
202 NonIncrementalChange();
203}
204
206 LOG(WARNING) << "Glop doesn't deal with integer variables.";
207}
208
209void 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
236void GLOPInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
237
238void GLOPInterface::ClearObjective() { NonIncrementalChange(); }
239
241 return lp_solver_.GetNumberOfSimplexIterations();
242}
243
244int64_t GLOPInterface::nodes() const {
245 LOG(DFATAL) << "Number of nodes only available for discrete problems";
247}
248
250 return row_status_[constraint_index];
251}
252
254 return column_status_[variable_index];
255}
256
257bool GLOPInterface::IsContinuous() const { return true; }
258
259bool GLOPInterface::IsLP() const { return true; }
260
261bool GLOPInterface::IsMIP() const { return false; }
262
263std::string GLOPInterface::SolverVersion() const {
264 // TODO(user): Decide how to version glop. Add a GetVersion() to LPSolver.
265 return "Glop-0.0";
266}
267
268void* 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.
418 lp_solver_.SetParameters(parameters_);
419 return true;
420 }
421 return false;
422}
423
424void 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
#define LOG(severity)
Definition: base/logging.h:417
#define DCHECK(condition)
Definition: base/logging.h:886
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:887
#define VLOG(verboselevel)
Definition: base/logging.h:980
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:160
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final
const GlopParameters & GetParameters() const
Definition: lp_solver.cc:124
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
Definition: lp_solver.cc:238
const DenseColumn & dual_values() const
Definition: lp_solver.h:113
const VariableStatusRow & variable_statuses() const
Definition: lp_solver.h:103
const ConstraintStatusColumn & constraint_statuses() const
Definition: lp_solver.h:117
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:485
const DenseRow & variable_values() const
Definition: lp_solver.h:101
const DenseRow & reduced_costs() const
Definition: lp_solver.h:102
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
Definition: lp_solver.cc:136
void SetParameters(const GlopParameters &parameters)
Definition: lp_solver.cc:112
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