Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
callback.h
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// IWYU pragma: private, include "ortools/math_opt/cpp/math_opt.h"
15// IWYU pragma: friend "ortools/math_opt/cpp/.*"
16
17// Data types for using callbacks with Solve() and IncrementalSolver.
18//
19// Callbacks allow to user to observe the progress of a solver and modify its
20// behavior mid solve. This is supported by allowing the user to a function of
21// type Callback as an optional argument to Solve() and
22// IncrementalSolver::Solve(). This function is called periodically throughout
23// the solve process. This file defines the data types needed to use this
24// callback.
25//
26// The example below registers a callback that listens for feasible solutions
27// the solvers finds along the way and accumulates them in a list for analysis
28// after the solve.
29//
30// using ::operations_research::math_opt::CallbackData;
31// using ::operations_research::math_opt::CallbackRegistration;
32// using ::operations_research::math_opt::CallbackResult;
33// using ::operations_research::math_opt::Model;
34// using ::operations_research::math_opt::SolveResult;
35// using ::operations_research::math_opt::Solve;
36// using ::operations_research::math_opt::Variable;
37// using ::operations_research::math_opt::VariableMap;
38//
39// Model model;
40// Variable x = model.AddBinaryVariable();
41// model.Maximize(x);
42// CallbackRegistration cb_reg;
43// cb_reg.events = {
44// operations_research::math_opt::CALLBACK_EVENT_MIP_SOLUTION};
45// std::vector<VariableMap<double>> solutions;
46// auto cb = [&solutions](const CallbackData& cb_data) {
47// // NOTE: this assumes the callback is always called from the same thread.
48// // Gurobi always does this, multi-threaded SCIP does not.
49// solutions.push_back(*cb_data.solution);
50// return CallbackResult();
51// };
52// absl::StatusOr<SolveResult> result = Solve(
53// model, operations_research::math_opt::SOLVER_TYPE_GUROBI,
54// /*parameters=*/{}, /*model_parameters=*/{}, cb_reb, cb);
55//
56// At the termination of the example, solutions will have {{x, 1.0}}, and
57// possibly {{x, 0.0}} as well.
58//
59// If the callback argument to Solve() is not null, it will be invoked on the
60// events specified by the callback_registration argument (and when the
61// callback is null, callback_registration must not request any events or will
62// CHECK fail). Some solvers do not support callbacks or certain events, in this
63// case the callback is ignored. TODO(b/180617976): change this behavior.
64//
65// Some solvers may call callback from multiple threads (SCIP will, Gurobi will
66// not). You should either solve with one thread (see
67// solver_parameters.threads), write a threadsafe callback, or consult
68// the documentation of your underlying solver.
69#ifndef ORTOOLS_MATH_OPT_CPP_CALLBACK_H_
70#define ORTOOLS_MATH_OPT_CPP_CALLBACK_H_
71
72#include <functional>
73#include <optional>
74#include <utility>
75#include <vector>
76
77#include "absl/container/flat_hash_set.h"
78#include "absl/status/status.h"
79#include "absl/status/statusor.h"
80#include "absl/time/time.h"
82#include "ortools/math_opt/cpp/enums.h" // IWYU pragma: export
87
88namespace operations_research {
89namespace math_opt {
90
91struct CallbackData;
92struct CallbackResult;
93
94using Callback = std::function<CallbackResult(const CallbackData&)>;
95
96// The supported events during a solve for callbacks.
97enum class CallbackEvent {
98 // The solver is currently running presolve.
99 //
100 // This event is supported for SolverType::kGurobi only.
102
103 // The solver is currently running the simplex method.
104 //
105 // This event is supported for SolverType::kGurobi only.
107
108 // The solver is in the MIP loop (called periodically before starting a new
109 // node). Useful for early termination. Note that this event does not provide
110 // information on LP relaxations nor about new incumbent solutions.
111 //
112 // This event is fully supported for MIP models with SolverType::kGurobi only.
113 // If used with SolverType::kCpSat, it is called when the dual bound is
114 // improved.
116
117 // Called every time a new MIP incumbent is found.
118 //
119 // This event is fully supported for MIP models by SolverType::kGurobi.
120 // SolverType::kCpSat has partial support: you can view the solutions and
121 // request termination, but you cannot add lazy constraints. Other solvers
122 // don't support this event.
124
125 // Called inside a MIP node. Note that there is no guarantee that the
126 // callback function will be called on every node. That behavior is
127 // solver-dependent.
128 //
129 // Disabling cuts using SolveParameters may interfere with this event
130 // being called and/or adding cuts at this event, the behavior is solver
131 // specific.
132 //
133 // This event is supported for MIP models with SolverType::kGurobi only.
135
136 // Called in each iterate of an interior point/barrier method.
137 //
138 // This event is supported for SolverType::kGurobi only.
140};
141
143
144// Provided with a callback at the start of a Solve() to inform the solver:
145// * what information the callback needs,
146// * how the callback might alter the solve process.
148 // Returns the CallbackRegistration equivalent to the proto.
149 //
150 // Returns an error if filters indices don't match existing variables or if
151 // events have incorrect values.
152 static absl::StatusOr<CallbackRegistration> FromProto(
153 const Model& model, const CallbackRegistrationProto& registration_proto);
154
155 // Returns a failure if the referenced variables don't belong to the input
156 // expected_storage (which must not be nullptr).
157 absl::Status CheckModelStorage(ModelStorageCPtr expected_storage) const;
158
159 // Returns the proto equivalent of this object.
160 //
161 // The caller should use CheckModelStorage() as this function does not check
162 // internal consistency of the referenced variables.
164
165 // The events the solver should invoke the callback at.
166 //
167 // When a solver is called with registered events that are not supported,
168 // an InvalidArgument is returned. The supported events may depend on the
169 // model. For example registering for CallbackEvent::kMip with a model that
170 // only contains continuous variables will fail for most solvers. See the
171 // documentation of each event to see their supported solvers/model types.
172 absl::flat_hash_set<CallbackEvent> events;
173
174 // Restricts the variable returned in CallbackData.solution for event
175 // CallbackEvent::kMipSolution. This can improve performance.
177
178 // Restricts the variable returned in CallbackData.solution for event
179 // CallbackEvent::kMipNode. This can improve performance.
181
182 // If the callback will ever add "user cuts" at event CallbackEvent::kMipNode
183 // during the solve process (a linear constraint that excludes the current LP
184 // solution but does not cut off any integer points).
185 bool add_cuts = false;
186
187 // If the callback will ever add "lazy constraints" at event
188 // CallbackEvent::kMipNode or CallbackEvent::kMipSolution during the solve
189 // process (a linear constraint that excludes integer points).
191};
192
193// The input to the Callback function.
194//
195// The information available depends on the current event.
197 // Users will typically not need this function other than for testing.
198 CallbackData(CallbackEvent event, absl::Duration runtime);
199
200 // Users will typically not need this function.
201 // Will CHECK fail if proto is not valid.
202 CallbackData(ModelStorageCPtr storage, const CallbackDataProto& proto);
203
204 // Returns a failure if the referenced variables don't belong to the input
205 // expected_storage (which must not be nullptr).
206 absl::Status CheckModelStorage(ModelStorageCPtr expected_storage) const;
207
208 // Returns the proto equivalent of this object.
209 //
210 // The caller should use CheckModelStorage() as this function does not check
211 // internal consistency of the referenced variables.
212 absl::StatusOr<CallbackDataProto> Proto() const;
213
214 // The current state of the underlying solver.
216
217 // If event == CallbackEvent::kMipNode, the primal_solution contains the
218 // primal solution to the current LP-node relaxation. In some cases, no
219 // solution will be available (e.g. because LP was infeasible or the solve
220 // was imprecise).
221 // If event == CallbackEvent::kMipSolution, the primal_solution contains the
222 // newly found primal (integer) feasible solution. The solution is always
223 // present.
224 // Otherwise, the primal_solution is not available.
225 std::optional<VariableMap<double>> solution;
226
227 // Time since `Solve()` was called. Available for all events.
228 absl::Duration runtime;
229
230 // Only available for event == CallbackEvent::kPresolve.
232
233 // Only available for event == CallbackEvent::kSimplex.
235
236 // Only available for event == CallbackEvent::kBarrier.
238
239 // Only available for event of CallbackEvent::kMip, CallbackEvent::kMipNode,
240 // or CallbackEvent::kMipSolution.
242};
243
244// The value returned by the Callback function.
246 // Prefer AddUserCut and AddLazyConstraint below instead of using this
247 // directly.
250 bool is_lazy = false;
251
253 return linear_constraint.expression.storage();
254 }
255 };
256
257 // Adds a "user cut," a linear constraint that excludes the current LP
258 // solution but does not cut off any integer points. Use only for
259 // CallbackEvent::kMipNode.
260 void AddUserCut(BoundedLinearExpression linear_constraint) {
261 new_constraints.push_back({std::move(linear_constraint), false});
262 }
263
264 // Adds a "lazy constraint," a linear constraint that excludes integer points.
265 // Use only for CallbackEvent::kMipNode and CallbackEvent::kMipSolution.
267 new_constraints.push_back({std::move(linear_constraint), true});
268 }
269
270 // Returns the CallbackResult equivalent to the proto.
271 //
272 // Returns an error if constraints or solutions indices don't match existing
273 // variables.
274 static absl::StatusOr<CallbackResult> FromProto(
275 const Model& model, const CallbackResultProto& result_proto);
276
277 // Returns a failure if the referenced variables don't belong to the input
278 // expected_storage (which must not be nullptr).
279 absl::Status CheckModelStorage(ModelStorageCPtr expected_storage) const;
280
281 // Returns the proto equivalent of this object.
282 //
283 // The caller should use CheckModelStorage() as this function does not check
284 // internal consistency of the referenced variables.
286
287 // When true it tells the solver to interrupt the solve as soon as possible.
288 //
289 // It can be set from any event. This is equivalent to using a
290 // SolveInterrupter and triggering it from the callback.
291 //
292 // Some solvers don't support interruption, in that case this is simply
293 // ignored and the solve terminates as usual. On top of that solvers may not
294 // immediately stop the solve. Thus the user should expect the callback to
295 // still be called after they set `terminate` to true in a previous
296 // call. Returning with `terminate` false after having previously returned
297 // true won't cancel the interruption.
298 bool terminate = false;
299
300 // The user cuts and lazy constraints added. Prefer AddUserCut() and
301 // AddLazyConstraint() to modifying this directly.
302 std::vector<GeneratedLinearConstraint> new_constraints;
303
304 // A solution or partially defined solution to give to the solver.
305 std::vector<VariableMap<double>> suggested_solutions;
306};
307
308} // namespace math_opt
309} // namespace operations_research
310
311#endif // ORTOOLS_MATH_OPT_CPP_CALLBACK_H_
CallbackDataProto_SimplexStats SimplexStats
CallbackDataProto_BarrierStats BarrierStats
CallbackDataProto_PresolveStats PresolveStats
#define MATH_OPT_DEFINE_ENUM(CppEnum, proto_unspecified_value)
Definition enums.h:325
const ModelStorage *absl_nonnull ModelStorageCPtr
std::function< CallbackResult(const CallbackData &)> Callback
Definition callback.h:94
const ModelStorage *absl_nullable NullableModelStorageCPtr
OR-Tools root namespace.
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
void AddLazyConstraint(BoundedLinearExpression linear_constraint)
Definition callback.h:266
std::vector< VariableMap< double > > suggested_solutions
Definition callback.h:305
absl::Status CheckModelStorage(ModelStorageCPtr expected_storage) const
Definition callback.cc:223
void AddUserCut(BoundedLinearExpression linear_constraint)
Definition callback.h:260