OR-Tools  9.6
pdlp_interface.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 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 <optional>
17 #include <string>
18 #include <utility>
19 #include <vector>
20 
21 #include "absl/base/attributes.h"
22 #include "absl/status/status.h"
23 #include "absl/status/statusor.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/types/optional.h"
26 #include "google/protobuf/text_format.h"
27 #include "ortools/base/logging.h"
29 #include "ortools/linear_solver/linear_solver.pb.h"
31 #include "ortools/pdlp/solve_log.pb.h"
32 #include "ortools/pdlp/solvers.pb.h"
34 
35 namespace operations_research {
36 
38  public:
39  explicit PdlpInterface(MPSolver* const solver);
40  ~PdlpInterface() override;
41 
42  // ----- Solve -----
43  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
44  std::optional<MPSolutionResponse> DirectlySolveProto(
45  const MPModelRequest& request, std::atomic<bool>* interrupt) override;
46 
47  // ----- Model modifications and extraction -----
48  void Reset() override;
49  void SetOptimizationDirection(bool maximize) override;
50  void SetVariableBounds(int index, double lb, double ub) override;
51  void SetVariableInteger(int index, bool integer) override;
52  void SetConstraintBounds(int index, double lb, double ub) override;
53  void AddRowConstraint(MPConstraint* const ct) override;
54  void AddVariable(MPVariable* const var) override;
55  void SetCoefficient(MPConstraint* const constraint,
56  const MPVariable* const variable, double new_value,
57  double old_value) override;
58  void ClearConstraint(MPConstraint* const constraint) override;
59  void SetObjectiveCoefficient(const MPVariable* const variable,
60  double coefficient) override;
61  void SetObjectiveOffset(double value) override;
62  void ClearObjective() override;
63 
64  // ------ Query statistics on the solution and the solve ------
65  int64_t iterations() const override;
66  int64_t nodes() const override;
67  MPSolver::BasisStatus row_status(int constraint_index) const override;
68  MPSolver::BasisStatus column_status(int variable_index) const override;
69 
70  // ----- Misc -----
71  bool IsContinuous() const override;
72  bool IsLP() const override;
73  bool IsMIP() const override;
74 
75  std::string SolverVersion() const override;
76  void* underlying_solver() override;
77 
78  void ExtractNewVariables() override;
79  void ExtractNewConstraints() override;
80  void ExtractObjective() override;
81 
82  void SetParameters(const MPSolverParameters& param) override;
83  void SetRelativeMipGap(double value) override;
84  void SetPrimalTolerance(double value) override;
85  void SetDualTolerance(double value) override;
86  void SetPresolveMode(int value) override;
87  void SetScalingMode(int value) override;
88  void SetLpAlgorithm(int value) override;
90  const std::string& parameters) override;
91  absl::Status SetNumThreads(int num_threads) override;
92 
93  private:
94  void NonIncrementalChange();
95 
96  pdlp::PrimalDualHybridGradientParams parameters_;
97  pdlp::SolveLog solve_log_;
98 };
99 
101  : MPSolverInterface(solver) {}
102 
104 
106  // Reset extraction as this interface is not incremental yet.
107  Reset();
108  ExtractModel();
109 
110  SetParameters(param);
111  if (quiet_) {
112  parameters_.set_verbosity_level(0);
113  } else {
114  parameters_.set_verbosity_level(3);
115  }
116 
118  solver_->solver_specific_parameter_string_);
119 
120  // Time limit.
121  if (solver_->time_limit()) {
122  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
123  parameters_.mutable_termination_criteria()->set_time_sec_limit(
124  static_cast<double>(solver_->time_limit()) / 1000.0);
125  }
126 
127  // Mark variables and constraints as extracted.
128  for (int i = 0; i < solver_->variables_.size(); ++i) {
129  set_variable_as_extracted(i, true);
130  }
131  for (int i = 0; i < solver_->constraints_.size(); ++i) {
133  }
134 
135  MPModelProto model_proto;
137  MPModelRequest request;
138  *request.mutable_model() = std::move(model_proto);
139  if (!google::protobuf::TextFormat::PrintToString(
140  parameters_, request.mutable_solver_specific_parameters())) {
141  LOG(QFATAL) << "Error converting parameters to text format: "
142  << parameters_.DebugString();
143  }
144  absl::StatusOr<MPSolutionResponse> response =
145  PdlpSolveProto(request, /*relax_integer_variables=*/true);
146 
147  if (!response.ok()) {
148  LOG(ERROR) << "Unexpected error solving with PDLP: " << response.status();
149  return MPSolver::ABNORMAL;
150  }
151 
152  // The solution must be marked as synchronized even when no solution exists.
154  result_status_ = static_cast<MPSolver::ResultStatus>(response->status());
155  LOG_IF(DFATAL, !response->has_solver_specific_info()) << *response;
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 
171 std::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 
193 void PdlpInterface::SetVariableBounds(int index, double lb, double ub) {
194  NonIncrementalChange();
195 }
196 
197 void PdlpInterface::SetVariableInteger(int index, bool integer) {
198  NonIncrementalChange();
199 }
200 
201 void 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 
228 void PdlpInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
229 
230 void PdlpInterface::ClearObjective() { NonIncrementalChange(); }
231 
232 int64_t PdlpInterface::iterations() const {
233  return solve_log_.iteration_count();
234 }
235 
236 int64_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 
253 bool PdlpInterface::IsContinuous() const { return true; }
254 
255 bool PdlpInterface::IsLP() const { return true; }
256 
257 bool PdlpInterface::IsMIP() const { return false; }
258 
259 std::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.
263 void* PdlpInterface::underlying_solver() { return nullptr; }
264 
265 void PdlpInterface::ExtractNewVariables() { NonIncrementalChange(); }
266 
267 void PdlpInterface::ExtractNewConstraints() { NonIncrementalChange(); }
268 
269 void PdlpInterface::ExtractObjective() { NonIncrementalChange(); }
270 
272  SetCommonParameters(param);
273 }
274 
275 absl::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 
297 void 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
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
std::optional< MPSolutionResponse > DirectlySolveProto(const MPModelRequest &request, std::atomic< bool > *interrupt) 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
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
Collection of objects used to extend the Constraint Solver library.
MPSolverInterface * BuildPdlpInterface(MPSolver *const solver)
absl::StatusOr< MPSolutionResponse > PdlpSolveProto(const MPModelRequest &request, const bool relax_integer_variables, const std::atomic< bool > *interrupt_solve)
bool ProtobufTextFormatMergeFromString(absl::string_view proto_text_string, ProtoType *proto)
int64_t coefficient
#define VLOG(verboselevel)
Definition: vlog.h:39