OR-Tools  9.3
pdlp_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 <utility>
18#include <vector>
19
20#include "absl/base/attributes.h"
21#include "absl/status/status.h"
22#include "absl/status/statusor.h"
23#include "absl/strings/str_cat.h"
24#include "absl/types/optional.h"
25#include "google/protobuf/text_format.h"
28#include "ortools/linear_solver/linear_solver.pb.h"
30#include "ortools/pdlp/solve_log.pb.h"
31#include "ortools/pdlp/solvers.pb.h"
33
34namespace operations_research {
35
37 public:
38 explicit PdlpInterface(MPSolver* const solver);
39 ~PdlpInterface() override;
40
41 // ----- Solve -----
42 MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
43 absl::optional<MPSolutionResponse> DirectlySolveProto(
44 const MPModelRequest& request, std::atomic<bool>* interrupt) override;
45
46 // ----- Model modifications and extraction -----
47 void Reset() override;
48 void SetOptimizationDirection(bool maximize) override;
49 void SetVariableBounds(int index, double lb, double ub) override;
50 void SetVariableInteger(int index, bool integer) override;
51 void SetConstraintBounds(int index, double lb, double ub) override;
52 void AddRowConstraint(MPConstraint* const ct) override;
53 void AddVariable(MPVariable* const var) override;
54 void SetCoefficient(MPConstraint* const constraint,
55 const MPVariable* const variable, double new_value,
56 double old_value) override;
57 void ClearConstraint(MPConstraint* const constraint) override;
58 void SetObjectiveCoefficient(const MPVariable* const variable,
59 double coefficient) override;
60 void SetObjectiveOffset(double value) override;
61 void ClearObjective() override;
62
63 // ------ Query statistics on the solution and the solve ------
64 int64_t iterations() const override;
65 int64_t nodes() const override;
66 MPSolver::BasisStatus row_status(int constraint_index) const override;
67 MPSolver::BasisStatus column_status(int variable_index) const override;
68
69 // ----- Misc -----
70 bool IsContinuous() const override;
71 bool IsLP() const override;
72 bool IsMIP() const override;
73
74 std::string SolverVersion() const override;
75 void* underlying_solver() override;
76
77 void ExtractNewVariables() override;
78 void ExtractNewConstraints() override;
79 void ExtractObjective() override;
80
81 void SetParameters(const MPSolverParameters& param) override;
82 void SetRelativeMipGap(double value) override;
83 void SetPrimalTolerance(double value) override;
84 void SetDualTolerance(double value) override;
85 void SetPresolveMode(int value) override;
86 void SetScalingMode(int value) override;
87 void SetLpAlgorithm(int value) override;
89 const std::string& parameters) override;
90 absl::Status SetNumThreads(int num_threads) override;
91
92 private:
93 void NonIncrementalChange();
94
95 pdlp::PrimalDualHybridGradientParams parameters_;
96 pdlp::SolveLog solve_log_;
97};
98
100 : MPSolverInterface(solver) {}
101
103
105 // Reset extraction as this interface is not incremental yet.
106 Reset();
107 ExtractModel();
108
109 SetParameters(param);
110 if (quiet_) {
111 parameters_.set_verbosity_level(0);
112 } else {
113 parameters_.set_verbosity_level(3);
114 }
115
117 solver_->solver_specific_parameter_string_);
118
119 // Time limit.
120 if (solver_->time_limit()) {
121 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
122 parameters_.mutable_termination_criteria()->set_time_sec_limit(
123 static_cast<double>(solver_->time_limit()) / 1000.0);
124 }
125
126 // Mark variables and constraints as extracted.
127 for (int i = 0; i < solver_->variables_.size(); ++i) {
129 }
130 for (int i = 0; i < solver_->constraints_.size(); ++i) {
132 }
133
134 MPModelProto model_proto;
136 MPModelRequest request;
137 *request.mutable_model() = std::move(model_proto);
138 if (!google::protobuf::TextFormat::PrintToString(
139 parameters_, request.mutable_solver_specific_parameters())) {
140 LOG(QFATAL) << "Error converting parameters to text format: "
141 << parameters_.DebugString();
142 }
143 absl::StatusOr<MPSolutionResponse> response =
144 PdlpSolveProto(request, /*relax_integer_variables=*/true);
145
146 if (!response.ok()) {
147 LOG(ERROR) << "Unexpected error solving with PDLP: " << response.status();
148 return MPSolver::ABNORMAL;
149 }
150
151 // The solution must be marked as synchronized even when no solution exists.
153 result_status_ = static_cast<MPSolver::ResultStatus>(response->status());
154 LOG_IF(DFATAL, !response->has_solver_specific_info())
155 << response->DebugString();
156 if (!solve_log_.ParseFromString(response->solver_specific_info())) {
157 LOG(DFATAL) << "Unable to parse PDLP's SolveLog from solver_specific_info";
158 }
159
160 if (response->status() == MPSOLVER_FEASIBLE ||
161 response->status() == MPSOLVER_OPTIMAL) {
162 const absl::Status result = solver_->LoadSolutionFromProto(*response);
163 if (!result.ok()) {
164 LOG(ERROR) << "LoadSolutionFromProto failed: " << result;
165 }
166 }
167
168 return result_status_;
169}
170
171absl::optional<MPSolutionResponse> PdlpInterface::DirectlySolveProto(
172 const MPModelRequest& request, std::atomic<bool>* interrupt) {
173 absl::StatusOr<MPSolutionResponse> response =
174 PdlpSolveProto(request, /*relax_integer_variables=*/true, interrupt);
175
176 if (!response.ok()) {
177 LOG(ERROR) << "Unexpected error solving with PDLP: " << response.status();
178 MPSolutionResponse error_response;
179 error_response.set_status(MPSolverResponseStatus::MPSOLVER_ABNORMAL);
180 error_response.set_status_str(response.status().ToString());
181 return error_response;
182 }
183
184 return *response;
185}
186
188
190 NonIncrementalChange();
191}
192
193void PdlpInterface::SetVariableBounds(int index, double lb, double ub) {
194 NonIncrementalChange();
195}
196
198 NonIncrementalChange();
199}
200
201void PdlpInterface::SetConstraintBounds(int index, double lb, double ub) {
202 NonIncrementalChange();
203}
204
206 NonIncrementalChange();
207}
208
210 NonIncrementalChange();
211}
212
214 const MPVariable* const variable,
215 double new_value, double old_value) {
216 NonIncrementalChange();
217}
218
220 NonIncrementalChange();
221}
222
224 double coefficient) {
225 NonIncrementalChange();
226}
227
228void PdlpInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
229
230void PdlpInterface::ClearObjective() { NonIncrementalChange(); }
231
233 return solve_log_.iteration_count();
234}
235
236int64_t PdlpInterface::nodes() const {
237 LOG(DFATAL) << "Number of nodes only available for discrete problems";
239}
240
242 // TODO(user): While basis status isn't well defined for PDLP, we could
243 // guess statuses that might be useful.
244 return MPSolver::BasisStatus::FREE;
245}
246
248 // TODO(user): While basis status isn't well defined for PDLP, we could
249 // guess statuses that might be useful.
250 return MPSolver::BasisStatus::FREE;
251}
252
253bool PdlpInterface::IsContinuous() const { return true; }
254
255bool PdlpInterface::IsLP() const { return true; }
256
257bool PdlpInterface::IsMIP() const { return false; }
258
259std::string PdlpInterface::SolverVersion() const { return "PDLP Solver"; }
260
261// TODO(user): Consider returning the SolveLog here, as it could be essential
262// for interpreting the PDLP solution.
263void* PdlpInterface::underlying_solver() { return nullptr; }
264
265void PdlpInterface::ExtractNewVariables() { NonIncrementalChange(); }
266
267void PdlpInterface::ExtractNewConstraints() { NonIncrementalChange(); }
268
269void PdlpInterface::ExtractObjective() { NonIncrementalChange(); }
270
272 SetCommonParameters(param);
273}
274
275absl::Status PdlpInterface::SetNumThreads(int num_threads) {
276 if (num_threads < 1) {
277 return absl::InvalidArgumentError(
278 absl::StrCat("Invalid number of threads: ", num_threads));
279 }
280 parameters_.set_num_threads(num_threads);
281 return absl::OkStatus();
282}
283
284// These have no effect. Use SetSolverSpecificParametersAsString instead.
291
293 const std::string& parameters) {
294 return ProtobufTextFormatMergeFromString(parameters, &parameters_);
295}
296
297void PdlpInterface::NonIncrementalChange() {
298 // The current implementation is not incremental.
300}
301
302// Register PDLP in the global linear solver factory.
304 return new PdlpInterface(solver);
305}
306
307} // namespace operations_research
#define LOG_IF(severity, condition)
Definition: base/logging.h:479
#define LOG(severity)
Definition: base/logging.h:420
#define VLOG(verboselevel)
Definition: base/logging.h:984
The class for constraints of a Mathematical Programming (MP) model.
This mathematical programming (MP) solver class is the main class though which users build and solve ...
ResultStatus
The status of solving the problem.
@ ABNORMAL
abnormal, i.e., error of some kind.
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
absl::Status LoadSolutionFromProto(const MPSolutionResponse &response, double tolerance=std::numeric_limits< double >::infinity())
Load a solution encoded in a protocol buffer onto this solver for easy access via the MPSolver interf...
void ExportModelToProto(MPModelProto *output_model) const
Exports model to protocol buffer.
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
void set_constraint_as_extracted(int ct_index, bool extracted)
static constexpr int64_t kUnknownNumberOfNodes
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.
The class for variables of a Mathematical Programming (MP) model.
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
absl::optional< MPSolutionResponse > DirectlySolveProto(const MPModelRequest &request, std::atomic< bool > *interrupt) override
std::string SolverVersion() const override
void SetRelativeMipGap(double value) override
void SetConstraintBounds(int index, double lb, double ub) override
absl::Status SetNumThreads(int num_threads) 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
PdlpInterface(MPSolver *const solver)
int64_t iterations() const override
void SetOptimizationDirection(bool maximize) override
MPSolver::BasisStatus column_status(int variable_index) const override
SatParameters parameters
CpModelProto const * model_proto
SharedResponseManager * response
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...
int index
const int ERROR
Definition: log_severity.h:32
Collection of objects used to extend the Constraint Solver library.
bool ProtobufTextFormatMergeFromString(const std::string &proto_text_string, ProtoType *proto)
MPSolverInterface * BuildPdlpInterface(MPSolver *const solver)
absl::StatusOr< MPSolutionResponse > PdlpSolveProto(const MPModelRequest &request, const bool relax_integer_variables, const std::atomic< bool > *interrupt_solve)
int64_t coefficient