Google OR-Tools v9.15
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-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 <optional>
17#include <string>
18#include <utility>
19#include <vector>
20
21#include "absl/base/attributes.h"
22#include "absl/log/check.h"
23#include "absl/status/status.h"
24#include "absl/status/statusor.h"
25#include "absl/strings/str_cat.h"
32
33namespace operations_research {
34
36 public:
37 explicit HighsInterface(MPSolver* solver, bool solve_as_a_mip);
38 ~HighsInterface() override;
39
40 // ----- Solve -----
41 MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
42
43 // ----- Directly solve proto is supported without interrupt ---
44 bool SupportsDirectlySolveProto(std::atomic<bool>* interrupt) const override {
45 return interrupt == nullptr;
46 }
48 std::atomic<bool>* interrupt) override {
49 DCHECK_EQ(interrupt, nullptr);
50 const bool log_error = request->enable_internal_solver_output();
52 log_error, HighsSolveProto(std::move(request)));
53 }
54
55 // ----- Model modifications and extraction -----
56 void Reset() override;
57 void SetOptimizationDirection(bool maximize) override;
58 void SetVariableBounds(int index, double lb, double ub) override;
59 void SetVariableInteger(int index, bool integer) override;
60 void SetConstraintBounds(int index, double lb, double ub) override;
61 void AddRowConstraint(MPConstraint* ct) override;
62 void AddVariable(MPVariable* var) override;
63 void SetCoefficient(MPConstraint* constraint, const MPVariable* variable,
64 double new_value, double old_value) override;
65 void ClearConstraint(MPConstraint* constraint) override;
66 void SetObjectiveCoefficient(const MPVariable* variable,
67 double coefficient) override;
68 void SetObjectiveOffset(double value) override;
69 void ClearObjective() override;
70
71 // ------ Query statistics on the solution and the solve ------
72 int64_t iterations() const override;
73 int64_t nodes() const override;
74 MPSolver::BasisStatus row_status(int constraint_index) const override;
75 MPSolver::BasisStatus column_status(int variable_index) const override;
76
77 // ----- Misc -----
78 bool IsContinuous() const override;
79 bool IsLP() const override;
80 bool IsMIP() const override;
81
82 std::string SolverVersion() const override;
83 void* underlying_solver() override;
84
85 void ExtractNewVariables() override;
86 void ExtractNewConstraints() override;
87 void ExtractObjective() override;
88
89 void SetParameters(const MPSolverParameters& param) override;
90 void SetRelativeMipGap(double value) override;
91 void SetPrimalTolerance(double value) override;
92 void SetDualTolerance(double value) override;
93 void SetPresolveMode(int value) override;
94 void SetScalingMode(int value) override;
95 void SetLpAlgorithm(int value) override;
97 const std::string& parameters) override;
98 absl::Status SetNumThreads(int num_threads) override;
99
100 private:
101 void NonIncrementalChange();
102
103 const bool solve_as_a_mip_;
104 std::optional<HighsSolveInfo> solve_info_;
105};
106
107HighsInterface::HighsInterface(MPSolver* const solver, bool solve_as_a_mip)
108 : MPSolverInterface(solver), solve_as_a_mip_(solve_as_a_mip) {}
109
111
113 // Reset extraction as this interface is not incremental yet.
114 Reset();
115 ExtractModel();
116
117 // Mark variables and constraints as extracted.
118 for (int i = 0; i < solver_->variables_.size(); ++i) {
120 }
121 for (int i = 0; i < solver_->constraints_.size(); ++i) {
123 }
124
125 MPModelProto model_proto;
126 solver_->ExportModelToProto(&model_proto);
127 MPModelRequest request;
128 *request.mutable_model() = std::move(model_proto);
129 request.set_solver_type(solve_as_a_mip_
132
133 SetParameters(param);
136 solver_->solver_specific_parameter_string_);
137 if (solver_->time_limit()) {
139 static_cast<double>(solver_->time_limit()) / 1000.0);
140 }
141
142 // Set parameters.
143 solve_info_ = HighsSolveInfo();
144 absl::StatusOr<MPSolutionResponse> response =
145 HighsSolveProto(std::move(request), &*solve_info_);
146
147 if (!response.ok()) {
148 LOG(ERROR) << "Unexpected error solving with Highs: " << 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
156 if (response->status() == MPSOLVER_FEASIBLE ||
157 response->status() == MPSOLVER_OPTIMAL) {
158 const absl::Status result = solver_->LoadSolutionFromProto(*response);
159 if (!result.ok()) {
160 LOG(ERROR) << "LoadSolutionFromProto failed: " << result;
161 }
162 }
163
164 return result_status_;
165}
166
169 solve_info_.reset();
170}
171
173 NonIncrementalChange();
174}
175
176void HighsInterface::SetVariableBounds(int index, double lb, double ub) {
177 NonIncrementalChange();
178}
179
180void HighsInterface::SetVariableInteger(int index, bool integer) {
181 NonIncrementalChange();
182}
183
184void HighsInterface::SetConstraintBounds(int index, double lb, double ub) {
185 NonIncrementalChange();
186}
187
189 NonIncrementalChange();
190}
191
193 NonIncrementalChange();
194}
195
197 const MPVariable* const variable,
198 double new_value, double old_value) {
199 NonIncrementalChange();
200}
201
203 NonIncrementalChange();
204}
205
207 double coefficient) {
208 NonIncrementalChange();
209}
210
212 NonIncrementalChange();
213}
214
215void HighsInterface::ClearObjective() { NonIncrementalChange(); }
216
218 return 0; // FIXME.
219}
220
221int64_t HighsInterface::nodes() const {
222 QCHECK(solve_info_.has_value())
223 << "Number of nodes only available after solve";
224 return solve_info_->mip_node_count;
225}
226
228 // TODO(user): While basis status isn't well defined for PDLP, we could
229 // guess statuses that might be useful.
231}
232
234 // TODO(user): While basis status isn't well defined for PDLP, we could
235 // guess statuses that might be useful.
237}
238
239bool HighsInterface::IsContinuous() const { return true; }
240
241bool HighsInterface::IsLP() const { return true; }
242
243bool HighsInterface::IsMIP() const { return solve_as_a_mip_; }
244
245std::string HighsInterface::SolverVersion() const { return "PDLP Solver"; }
246
247// TODO(user): Consider returning the SolveLog here, as it could be essential
248// for interpreting the PDLP solution.
249void* HighsInterface::underlying_solver() { return nullptr; }
250
251void HighsInterface::ExtractNewVariables() { NonIncrementalChange(); }
252
253void HighsInterface::ExtractNewConstraints() { NonIncrementalChange(); }
254
255void HighsInterface::ExtractObjective() { NonIncrementalChange(); }
256
260
261absl::Status HighsInterface::SetNumThreads(int num_threads) {
262 if (num_threads < 1) {
263 return absl::InvalidArgumentError(
264 absl::StrCat("Invalid number of threads: ", num_threads));
265 }
266 // parameters_.set_num_threads(num_threads);
267 return absl::OkStatus();
268}
269
270// These have no effect. Use SetSolverSpecificParametersAsString instead.
277
279 const std::string& parameters) {
280 // return ProtobufTextFormatMergeFromString(parameters, &parameters_);
281 return false;
282}
283
284void HighsInterface::NonIncrementalChange() {
285 // The current implementation is not incremental.
287}
288
289namespace {
290
291// See MpSolverInterfaceFactoryRepository for details.
292const void* const kRegisterHighsLp ABSL_ATTRIBUTE_UNUSED = [] {
294 [](MPSolver* solver) { return new HighsInterface(solver, false); },
296 return nullptr;
297}();
298
299// See MpSolverInterfaceFactoryRepository for details.
300const void* const kRegisterHighsMip ABSL_ATTRIBUTE_UNUSED = [] {
302 [](MPSolver* solver) { return new HighsInterface(solver, true); },
304 return nullptr;
305}();
306
307} // namespace
308
309} // namespace operations_research
MPSolver::BasisStatus row_status(int constraint_index) const override
void SetConstraintBounds(int index, double lb, double ub) override
absl::Status SetNumThreads(int num_threads) override
void AddVariable(MPVariable *var) override
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
bool SupportsDirectlySolveProto(std::atomic< bool > *interrupt) const override
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
MPSolutionResponse DirectlySolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt) override
bool SetSolverSpecificParametersAsString(const std::string &parameters) override
int64_t iterations() const override
void SetPresolveMode(int value) override
void SetVariableInteger(int index, bool integer) override
void SetScalingMode(int value) override
void SetVariableBounds(int index, double lb, double ub) override
std::string SolverVersion() const override
MPSolver::BasisStatus column_status(int variable_index) const override
void SetDualTolerance(double value) override
void SetRelativeMipGap(double value) override
HighsInterface(MPSolver *solver, bool solve_as_a_mip)
void SetParameters(const MPSolverParameters &param) override
void AddRowConstraint(MPConstraint *ct) override
void SetOptimizationDirection(bool maximize) override
void SetPrimalTolerance(double value) override
void ClearConstraint(MPConstraint *constraint) override
void SetLpAlgorithm(int value) override
void SetObjectiveOffset(double value) override
void set_solver_specific_parameters(Arg_ &&arg, Args_... args)
static constexpr SolverType HIGHS_LINEAR_PROGRAMMING
static constexpr SolverType HIGHS_MIXED_INTEGER_PROGRAMMING
::operations_research::MPModelProto *PROTOBUF_NONNULL mutable_model()
void set_solver_type(::operations_research::MPModelRequest_SolverType value)
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)
void SetCommonParameters(const MPSolverParameters &param)
@ ABNORMAL
abnormal, i.e., error of some kind.
The class for variables of a Mathematical Programming (MP) model.
OR-Tools root namespace.
absl::StatusOr< MPSolutionResponse > HighsSolveProto(LazyMutableCopy< MPModelRequest > request, HighsSolveInfo *solve_info)
MPSolutionResponse ConvertStatusOrMPSolutionResponse(bool log_error, absl::StatusOr< MPSolutionResponse > response)
Definition proto_utils.h:37