Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
callback.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
15
16#include <algorithm>
17#include <optional>
18#include <utility>
19
20#include "absl/status/status.h"
21#include "absl/status/statusor.h"
22#include "absl/strings/string_view.h"
23#include "absl/time/time.h"
24#include "absl/types/span.h"
36
37namespace operations_research {
38namespace math_opt {
39
40std::optional<absl::string_view> Enum<CallbackEvent>::ToOptString(
41 CallbackEvent value) {
42 switch (value) {
44 return "presolve";
46 return "simplex";
48 return "mip";
50 return "mip_solution";
52 return "mip_node";
54 return "barrier";
55 }
56 return std::nullopt;
57}
58
59absl::Span<const CallbackEvent> Enum<CallbackEvent>::AllValues() {
60 static constexpr CallbackEvent kCallbackEventValues[] = {
64 };
65 return absl::MakeConstSpan(kCallbackEventValues);
66}
67
71
73 const CallbackDataProto& proto)
74 // iOS 11 does not support .value() hence we use operator* here and CHECK
75 // below that we have a value.
76 : event(*EnumFromProto(proto.event())),
80 mip_stats(proto.mip_stats()) {
81 CHECK(EnumFromProto(proto.event()).has_value());
82 if (proto.has_primal_solution_vector()) {
84 .value();
85 }
86 auto maybe_time = util_time::DecodeGoogleApiProto(proto.runtime());
87 CHECK_OK(maybe_time.status());
88 runtime = *maybe_time;
89}
90
92 const ModelStorageCPtr expected_storage) const {
93 if (solution.has_value()) {
94 for (const auto& [v, _] : solution.value()) {
96 /*storage=*/v.storage(), /*expected_storage=*/expected_storage))
97 << "invalid variable " << v << " in solution";
98 }
99 }
100 return absl::OkStatus();
101}
102
103absl::StatusOr<CallbackDataProto> CallbackData::Proto() const {
104 CallbackDataProto proto;
109 *proto.mutable_mip_stats() = mip_stats;
110 if (solution.has_value()) {
113 }
116 _ << "failed to encode runtime");
117 return proto;
118}
119
120absl::StatusOr<CallbackRegistration> CallbackRegistration::FromProto(
121 const Model& model, const CallbackRegistrationProto& registration_proto) {
123
124 // Parses `events`.
125 for (int e = 0; e < registration_proto.request_registration_size(); ++e) {
126 const CallbackEventProto event_proto =
127 registration_proto.request_registration(e);
128 const std::optional<CallbackEvent> event = EnumFromProto(event_proto);
129 if (event == std::nullopt) {
131 << "value CallbackRegistrationProto.request_registration[" << e
132 << "] is CALLBACK_EVENT_UNSPECIFIED";
133 }
134 if (!result.events.insert(event.value()).second) {
136 << "value " << event
137 << " is repeated at "
138 "CallbackRegistrationProto.request_registration["
139 << e << "]";
140 }
141 }
142
144 result.mip_solution_filter,
145 VariableFilterFromProto(model, registration_proto.mip_solution_filter()),
146 _ << "invalid CallbackRegistrationProto.mip_solution_filter");
148 result.mip_node_filter,
149 VariableFilterFromProto(model, registration_proto.mip_node_filter()),
150 _ << "invalid CallbackRegistrationProto.mip_node_filter");
151
152 result.add_cuts = registration_proto.add_cuts();
153 result.add_lazy_constraints = registration_proto.add_lazy_constraints();
154
155 return result;
156}
157
159 const ModelStorageCPtr expected_storage) const {
160 RETURN_IF_ERROR(mip_node_filter.CheckModelStorage(expected_storage))
161 << "invalid mip_node_filter";
162 RETURN_IF_ERROR(mip_solution_filter.CheckModelStorage(expected_storage))
163 << "invalid mip_solution_filter";
164 return absl::OkStatus();
165}
166
169 for (const CallbackEvent event : events) {
171 }
172 std::sort(result.mutable_request_registration()->begin(),
173 result.mutable_request_registration()->end());
175 *result.mutable_mip_node_filter() = mip_node_filter.Proto();
177 result.set_add_cuts(add_cuts);
178 return result;
179}
180
181absl::StatusOr<CallbackResult> CallbackResult::FromProto(
182 const Model& model, const CallbackResultProto& result_proto) {
183 CallbackResult result = {
184 .terminate = result_proto.terminate(),
185 };
186
187 // Add new_constraints.
188 for (int c = 0; c < result_proto.cuts_size(); ++c) {
189 const CallbackResultProto::GeneratedLinearConstraint& constraint_proto =
190 result_proto.cuts(c);
192 const VariableMap<double> coefficients,
194 constraint_proto.linear_expression()),
195 _ << "invalid CallbackResultProto.cuts[" << c << "].linear_expression");
196 LinearExpression expression;
197 for (const auto [v, coeff] : coefficients) {
198 expression += coeff * v;
199 };
200 result.new_constraints.push_back({
201 .linear_constraint = BoundedLinearExpression(
202 /*expression=*/std::move(expression),
203 /*lower_bound=*/constraint_proto.lower_bound(),
204 /*upper_bound=*/constraint_proto.upper_bound()),
205 .is_lazy = constraint_proto.is_lazy(),
206 });
207 }
208
209 // Add suggested_solutions.
210 for (int s = 0; s < result_proto.suggested_solutions_size(); ++s) {
211 const SparseDoubleVectorProto suggested_solution_proto =
212 result_proto.suggested_solutions(s);
214 VariableMap<double> suggested_solution,
215 VariableValuesFromProto(model.storage(), suggested_solution_proto),
216 _ << "invalid CallbackResultProto.suggested_solutions[" << s << "]");
217 result.suggested_solutions.push_back(std::move(suggested_solution));
218 }
219
220 return result;
221}
222
224 const ModelStorageCPtr expected_storage) const {
225 for (const GeneratedLinearConstraint& constraint : new_constraints) {
227 internal::CheckModelStorage(/*storage=*/constraint.storage(),
228 /*expected_storage=*/expected_storage))
229 << "invalid new_constraints";
230 }
232 for (const auto& [v, _] : solution) {
234 /*storage=*/v.storage(), /*expected_storage=*/expected_storage))
235 << "invalid variable " << v << " in suggested_solutions";
236 }
237 }
238 return absl::OkStatus();
239}
240
242 CallbackResultProto result;
243 result.set_terminate(terminate);
246 }
247 for (const GeneratedLinearConstraint& constraint : new_constraints) {
249 result.add_cuts();
250 constraint_proto->set_is_lazy(constraint.is_lazy);
251 constraint_proto->set_lower_bound(
252 constraint.linear_constraint.lower_bound_minus_offset());
253 constraint_proto->set_upper_bound(
254 constraint.linear_constraint.upper_bound_minus_offset());
255 *constraint_proto->mutable_linear_expression() =
256 VariableValuesToProto(constraint.linear_constraint.expression.terms());
257 }
258 return result;
259}
260
261} // namespace math_opt
262} // namespace operations_research
#define RETURN_IF_ERROR(expr)
void set_event(::operations_research::math_opt::CallbackEventProto value)
::operations_research::math_opt::CallbackDataProto_BarrierStats *PROTOBUF_NONNULL mutable_barrier_stats()
::operations_research::math_opt::CallbackEventProto event() const
::operations_research::math_opt::CallbackDataProto_MipStats *PROTOBUF_NONNULL mutable_mip_stats()
::operations_research::math_opt::SparseDoubleVectorProto *PROTOBUF_NONNULL mutable_primal_solution_vector()
::operations_research::math_opt::CallbackDataProto_PresolveStats *PROTOBUF_NONNULL mutable_presolve_stats()
const ::google::protobuf::Duration & runtime() const
::operations_research::math_opt::CallbackDataProto_SimplexStats *PROTOBUF_NONNULL mutable_simplex_stats()
const ::operations_research::math_opt::SparseDoubleVectorProto & primal_solution_vector() const
::google::protobuf::Duration *PROTOBUF_NONNULL mutable_runtime()
::operations_research::math_opt::SparseVectorFilterProto *PROTOBUF_NONNULL mutable_mip_node_filter()
::operations_research::math_opt::SparseVectorFilterProto *PROTOBUF_NONNULL mutable_mip_solution_filter()
const ::operations_research::math_opt::SparseVectorFilterProto & mip_solution_filter() const
::google::protobuf::RepeatedField< int > *PROTOBUF_NONNULL mutable_request_registration()
void add_request_registration(::operations_research::math_opt::CallbackEventProto value)
::operations_research::math_opt::CallbackEventProto request_registration(int index) const
const ::operations_research::math_opt::SparseVectorFilterProto & mip_node_filter() const
::operations_research::math_opt::SparseDoubleVectorProto *PROTOBUF_NONNULL mutable_linear_expression()
const ::operations_research::math_opt::SparseDoubleVectorProto & linear_expression() const
const ::operations_research::math_opt::SparseDoubleVectorProto & suggested_solutions(int index) const
const ::operations_research::math_opt::CallbackResultProto_GeneratedLinearConstraint & cuts(int index) const
CallbackResultProto_GeneratedLinearConstraint GeneratedLinearConstraint
::operations_research::math_opt::SparseDoubleVectorProto *PROTOBUF_NONNULL add_suggested_solutions()
::operations_research::math_opt::CallbackResultProto_GeneratedLinearConstraint *PROTOBUF_NONNULL add_cuts()
ModelStorageCPtr storage() const
Definition model.h:921
absl::Status CheckModelStorage(const NullableModelStorageCPtr storage, const ModelStorageCPtr expected_storage)
Definition key_types.h:169
const ModelStorage *absl_nonnull ModelStorageCPtr
absl::flat_hash_map< Variable, V > VariableMap
std::optional< typename EnumProto< P >::Cpp > EnumFromProto(P proto_value)
Definition enums.h:281
SparseDoubleVectorProto VariableValuesToProto(const VariableMap< double > &variable_values)
Enum< E >::Proto EnumToProto(std::optional< E > value)
Definition enums.h:270
absl::StatusOr< VariableMap< double > > VariableValuesFromProto(const ModelStorageCPtr model, const SparseDoubleVectorProto &vars_proto)
absl::StatusOr< MapFilter< Variable > > VariableFilterFromProto(const Model &model, const SparseVectorFilterProto &proto)
Definition map_filter.cc:28
OR-Tools root namespace.
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
inline ::absl::StatusOr< absl::Duration > DecodeGoogleApiProto(const google::protobuf::Duration &proto)
Definition protoutil.h:42
inline ::absl::StatusOr< google::protobuf::Duration > EncodeGoogleApiProto(absl::Duration d)
Definition protoutil.h:27
StatusBuilder InvalidArgumentErrorBuilder()
CallbackDataProto::PresolveStats presolve_stats
Definition callback.h:231
absl::Status CheckModelStorage(ModelStorageCPtr expected_storage) const
Definition callback.cc:91
CallbackDataProto::SimplexStats simplex_stats
Definition callback.h:234
CallbackDataProto::BarrierStats barrier_stats
Definition callback.h:237
std::optional< VariableMap< double > > solution
Definition callback.h:225
CallbackDataProto::MipStats mip_stats
Definition callback.h:241
absl::StatusOr< CallbackDataProto > Proto() const
Definition callback.cc:103
CallbackData(CallbackEvent event, absl::Duration runtime)
Definition callback.cc:68
absl::flat_hash_set< CallbackEvent > events
Definition callback.h:172
static absl::StatusOr< CallbackRegistration > FromProto(const Model &model, const CallbackRegistrationProto &registration_proto)
Definition callback.cc:120
absl::Status CheckModelStorage(ModelStorageCPtr expected_storage) const
Definition callback.cc:158
CallbackRegistrationProto Proto() const
Definition callback.cc:167
std::vector< GeneratedLinearConstraint > new_constraints
Definition callback.h:302
static absl::StatusOr< CallbackResult > FromProto(const Model &model, const CallbackResultProto &result_proto)
Definition callback.cc:181
std::vector< VariableMap< double > > suggested_solutions
Definition callback.h:305
absl::Status CheckModelStorage(ModelStorageCPtr expected_storage) const
Definition callback.cc:223
static absl::Span< const E > AllValues()
static std::optional< absl::string_view > ToOptString(E value)
#define OR_ASSIGN_OR_RETURN3(lhs, rexpr, error_expression)