Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
highs_interface.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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#if defined(USE_HIGHS)
15
16#include <atomic>
17#include <cstdint>
18#include <optional>
19#include <string>
20#include <utility>
21#include <vector>
22
23#include "absl/base/attributes.h"
24#include "absl/log/check.h"
25#include "absl/status/status.h"
26#include "absl/status/statusor.h"
27#include "absl/strings/str_cat.h"
28#include "absl/types/optional.h"
29#include "google/protobuf/text_format.h"
32#include "ortools/linear_solver/linear_solver.pb.h"
37
38namespace operations_research {
39
41 public:
42 explicit HighsInterface(MPSolver* solver, bool solve_as_a_mip);
43 ~HighsInterface() override;
44
45 // ----- Solve -----
46 MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
47
48 // ----- Directly solve proto is supported without interrupt ---
49 bool SupportsDirectlySolveProto(std::atomic<bool>* interrupt) const override {
50 return interrupt == nullptr;
51 }
53 std::atomic<bool>* interrupt) override {
54 DCHECK_EQ(interrupt, nullptr);
55 const bool log_error = request->enable_internal_solver_output();
57 log_error, HighsSolveProto(std::move(request)));
58 }
59
60 // ----- Model modifications and extraction -----
61 void Reset() override;
62 void SetOptimizationDirection(bool maximize) override;
63 void SetVariableBounds(int index, double lb, double ub) override;
64 void SetVariableInteger(int index, bool integer) override;
65 void SetConstraintBounds(int index, double lb, double ub) override;
66 void AddRowConstraint(MPConstraint* ct) override;
67 void AddVariable(MPVariable* var) override;
68 void SetCoefficient(MPConstraint* constraint, const MPVariable* variable,
69 double new_value, double old_value) override;
70 void ClearConstraint(MPConstraint* constraint) override;
71 void SetObjectiveCoefficient(const MPVariable* variable,
72 double coefficient) override;
73 void SetObjectiveOffset(double value) override;
74 void ClearObjective() override;
75
76 // ------ Query statistics on the solution and the solve ------
77 int64_t iterations() const override;
78 int64_t nodes() const override;
80 MPSolver::BasisStatus column_status(int variable_index) const override;
81
82 // ----- Misc -----
83 bool IsContinuous() const override;
84 bool IsLP() const override;
85 bool IsMIP() const override;
86
87 std::string SolverVersion() const override;
88 void* underlying_solver() override;
89
90 void ExtractNewVariables() override;
91 void ExtractNewConstraints() override;
92 void ExtractObjective() override;
93
94 void SetParameters(const MPSolverParameters& param) override;
95 void SetRelativeMipGap(double value) override;
96 void SetPrimalTolerance(double value) override;
97 void SetDualTolerance(double value) override;
98 void SetPresolveMode(int value) override;
99 void SetScalingMode(int value) override;
100 void SetLpAlgorithm(int value) override;
102 const std::string& parameters) override;
103 absl::Status SetNumThreads(int num_threads) override;
104
105 private:
106 void NonIncrementalChange();
107
108 const bool solve_as_a_mip_;
109};
110
111HighsInterface::HighsInterface(MPSolver* const solver, bool solve_as_a_mip)
112 : MPSolverInterface(solver), solve_as_a_mip_(solve_as_a_mip) {}
113
115
117 // Reset extraction as this interface is not incremental yet.
118 Reset();
119 ExtractModel();
120
121 SetParameters(param);
122 if (quiet_) {
123 // parameters_.set_verbosity_level(0);
124 } else {
125 // parameters_.set_verbosity_level(3);
126 }
127
129 solver_->solver_specific_parameter_string_);
130
131 // Time limit.
132 if (solver_->time_limit()) {
133 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
134 // parameters_.mutable_termination_criteria()->set_time_sec_limit(
135 // static_cast<double>(solver_->time_limit()) / 1000.0);
136 }
137
138 // Mark variables and constraints as extracted.
139 for (int i = 0; i < solver_->variables_.size(); ++i) {
141 }
142 for (int i = 0; i < solver_->constraints_.size(); ++i) {
144 }
145
146 MPModelProto model_proto;
147 solver_->ExportModelToProto(&model_proto);
148 MPModelRequest request;
149 *request.mutable_model() = std::move(model_proto);
150 request.set_solver_type(solve_as_a_mip_
151 ? MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING
152 : MPModelRequest::HIGHS_LINEAR_PROGRAMMING);
153
154 // Set parameters.
155 absl::StatusOr<MPSolutionResponse> response =
156 HighsSolveProto(std::move(request));
157
158 if (!response.ok()) {
159 LOG(ERROR) << "Unexpected error solving with Highs: " << response.status();
160 return MPSolver::ABNORMAL;
161 }
162
163 // The solution must be marked as synchronized even when no solution exists.
165 result_status_ = static_cast<MPSolver::ResultStatus>(response->status());
166 LOG_IF(DFATAL, !response->has_solver_specific_info()) << *response;
167
168 if (response->status() == MPSOLVER_FEASIBLE ||
169 response->status() == MPSOLVER_OPTIMAL) {
170 const absl::Status result = solver_->LoadSolutionFromProto(*response);
171 if (!result.ok()) {
172 LOG(ERROR) << "LoadSolutionFromProto failed: " << result;
173 }
174 }
175
176 return result_status_;
177}
178
180
182 NonIncrementalChange();
183}
184
185void HighsInterface::SetVariableBounds(int index, double lb, double ub) {
186 NonIncrementalChange();
187}
188
190 NonIncrementalChange();
191}
192
193void HighsInterface::SetConstraintBounds(int index, double lb, double ub) {
194 NonIncrementalChange();
195}
196
198 NonIncrementalChange();
199}
200
202 NonIncrementalChange();
203}
204
206 const MPVariable* const variable,
207 double new_value, double old_value) {
208 NonIncrementalChange();
209}
210
212 NonIncrementalChange();
213}
214
216 double coefficient) {
217 NonIncrementalChange();
218}
219
221 NonIncrementalChange();
222}
223
224void HighsInterface::ClearObjective() { NonIncrementalChange(); }
225
227 return 0; // FIXME.
228}
229
230int64_t HighsInterface::nodes() const {
231 LOG(DFATAL) << "Number of nodes only available for discrete problems";
233}
234
236 // TODO(user): While basis status isn't well defined for PDLP, we could
237 // guess statuses that might be useful.
239}
240
242 // TODO(user): While basis status isn't well defined for PDLP, we could
243 // guess statuses that might be useful.
245}
246
247bool HighsInterface::IsContinuous() const { return true; }
248
249bool HighsInterface::IsLP() const { return true; }
250
251bool HighsInterface::IsMIP() const { return solve_as_a_mip_; }
252
253std::string HighsInterface::SolverVersion() const { return "PDLP Solver"; }
254
255// TODO(user): Consider returning the SolveLog here, as it could be essential
256// for interpreting the PDLP solution.
257void* HighsInterface::underlying_solver() { return nullptr; }
258
259void HighsInterface::ExtractNewVariables() { NonIncrementalChange(); }
260
261void HighsInterface::ExtractNewConstraints() { NonIncrementalChange(); }
262
263void HighsInterface::ExtractObjective() { NonIncrementalChange(); }
264
268
269absl::Status HighsInterface::SetNumThreads(int num_threads) {
270 if (num_threads < 1) {
271 return absl::InvalidArgumentError(
272 absl::StrCat("Invalid number of threads: ", num_threads));
273 }
274 // parameters_.set_num_threads(num_threads);
275 return absl::OkStatus();
276}
277
278// These have no effect. Use SetSolverSpecificParametersAsString instead.
285
287 const std::string& parameters) {
288 // return ProtobufTextFormatMergeFromString(parameters, &parameters_);
289 return false;
290}
291
292void HighsInterface::NonIncrementalChange() {
293 // The current implementation is not incremental.
295}
296
297// Register PDLP in the global linear solver factory.
299 return new HighsInterface(solver, mip);
300}
301
302} // namespace operations_research
303#endif // #if defined(USE_HIGHS)
MPSolver::BasisStatus row_status(int constraint_index) const override
Returns the basis status of a row.
void SetConstraintBounds(int index, double lb, double ub) override
Modify bounds of an extracted variable.
absl::Status SetNumThreads(int num_threads) override
Sets the number of threads to be used by the solver.
bool IsContinuous() const override
--— Misc --—
void AddVariable(MPVariable *var) override
Add a variable.
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
Changes a coefficient in the linear objective.
bool IsMIP() const override
Returns true if the problem is discrete and linear.
bool SupportsDirectlySolveProto(std::atomic< bool > *interrupt) const override
--— Directly solve proto is supported without interrupt —
bool IsLP() const override
Returns true if the problem is continuous and linear.
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
--— Solve --—
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
Changes a coefficient in a constraint.
MPSolutionResponse DirectlySolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt) override
bool SetSolverSpecificParametersAsString(const std::string &parameters) override
int64_t iterations() const override
---— Query statistics on the solution and the solve ---—
void SetPresolveMode(int value) override
void SetVariableInteger(int index, bool integer) override
Modifies integrality of an extracted variable.
void SetScalingMode(int value) override
Sets the scaling mode.
void SetVariableBounds(int index, double lb, double ub) override
Modifies bounds of an extracted variable.
std::string SolverVersion() const override
Returns a string describing the underlying solver and its version.
MPSolver::BasisStatus column_status(int variable_index) const override
Returns the basis status of a constraint.
void SetDualTolerance(double value) override
void SetRelativeMipGap(double value) override
Sets each parameter in the underlying solver.
void ClearObjective() override
Clears the objective from all its terms.
HighsInterface(MPSolver *solver, bool solve_as_a_mip)
void SetParameters(const MPSolverParameters &param) override
Sets all parameters in the underlying solver.
void Reset() override
--— Model modifications and extraction --—
void ExtractNewVariables() override
Extracts the variables that have not been extracted yet.
void AddRowConstraint(MPConstraint *ct) override
Adds a linear constraint.
void SetOptimizationDirection(bool maximize) override
Sets the optimization direction (min/max).
void SetPrimalTolerance(double value) override
These have no effect. Use SetSolverSpecificParametersAsString instead.
void ClearConstraint(MPConstraint *constraint) override
Clears a constraint from all its terms.
void ExtractObjective() override
Extracts the objective.
void ExtractNewConstraints() override
Extracts the constraints that have not been extracted yet.
void SetLpAlgorithm(int value) override
void SetObjectiveOffset(double value) override
Changes the constant term in the linear objective.
void set_variable_as_extracted(int var_index, bool extracted)
void set_constraint_as_extracted(int ct_index, bool extracted)
void ResetExtractionInformation()
Resets the extraction information.
static constexpr int64_t kUnknownNumberOfNodes
void ExtractModel()
Extracts model stored in MPSolver.
bool quiet_
Boolean indicator for the verbosity of the solver output.
void SetCommonParameters(const MPSolverParameters &param)
Sets parameters common to LP and MIP in the underlying solver.
SynchronizationStatus sync_status_
Indicates whether the model and the solution are synchronized.
@ ABNORMAL
abnormal, i.e., error of some kind.
bool SetSolverSpecificParametersAsString(const std::string &parameters)
void ExportModelToProto(MPModelProto *output_model) const
Exports model to protocol buffer.
absl::Status LoadSolutionFromProto(const MPSolutionResponse &response, double tolerance=std::numeric_limits< double >::infinity())
The class for variables of a Mathematical Programming (MP) model.
SatParameters parameters
const Constraint * ct
int64_t value
IntVar * var
int constraint_index
int index
In SWIG mode, we don't want anything besides these top-level includes.
MPSolverInterface * BuildHighsInterface(bool mip, MPSolver *const solver)
Register PDLP in the global linear solver factory.
absl::StatusOr< MPSolutionResponse > HighsSolveProto(LazyMutableCopy< MPModelRequest > request)
Solve the input MIP model with the HIGHS solver.
MPSolutionResponse ConvertStatusOrMPSolutionResponse(bool log_error, absl::StatusOr< MPSolutionResponse > response)
Definition proto_utils.h:41
int64_t coefficient