Google OR-Tools v9.11
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-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// 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 OR_TOOLS_MATH_OPT_CPP_CALLBACK_H_
70#define OR_TOOLS_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/time/time.h"
80#include "absl/types/span.h"
81#include "ortools/math_opt/callback.pb.h"
82#include "ortools/math_opt/cpp/enums.h" // IWYU pragma: export
86
87namespace operations_research {
88namespace math_opt {
89
90struct CallbackData;
91struct CallbackResult;
92
93using Callback = std::function<CallbackResult(const CallbackData&)>;
94
95// The supported events during a solve for callbacks.
96enum class CallbackEvent {
97 // The solver is currently running presolve.
98 //
99 // This event is supported for SolverType::kGurobi only.
100 kPresolve = CALLBACK_EVENT_PRESOLVE,
101
102 // The solver is currently running the simplex method.
103 //
104 // This event is supported for SolverType::kGurobi only.
105 kSimplex = CALLBACK_EVENT_SIMPLEX,
106
107 // The solver is in the MIP loop (called periodically before starting a new
108 // node). Useful for early termination. Note that this event does not provide
109 // information on LP relaxations nor about new incumbent solutions.
110 //
111 // This event is supported for MIP models with SolverType::kGurobi only.
112 kMip = CALLBACK_EVENT_MIP,
113
114 // Called every time a new MIP incumbent is found.
115 //
116 // This event is fully supported for MIP models by SolverType::kGurobi.
117 // SolverType::kCpSat has partial support: you can view the solutions and
118 // request termination, but you cannot add lazy constraints. Other solvers
119 // don't support this event.
120 kMipSolution = CALLBACK_EVENT_MIP_SOLUTION,
121
122 // Called inside a MIP node. Note that there is no guarantee that the
123 // callback function will be called on every node. That behavior is
124 // solver-dependent.
125 //
126 // Disabling cuts using SolveParameters may interfere with this event
127 // being called and/or adding cuts at this event, the behavior is solver
128 // specific.
129 //
130 // This event is supported for MIP models with SolverType::kGurobi only.
131 kMipNode = CALLBACK_EVENT_MIP_NODE,
132
133 // Called in each iterate of an interior point/barrier method.
134 //
135 // This event is supported for SolverType::kGurobi only.
136 kBarrier = CALLBACK_EVENT_BARRIER,
137};
138
139MATH_OPT_DEFINE_ENUM(CallbackEvent, CALLBACK_EVENT_UNSPECIFIED);
140
141// Provided with a callback at the start of a Solve() to inform the solver:
142// * what information the callback needs,
143// * how the callback might alter the solve process.
145 // Returns a failure if the referenced variables don't belong to the input
146 // expected_storage (which must not be nullptr).
147 absl::Status CheckModelStorage(const ModelStorage* expected_storage) const;
148
149 // Returns the proto equivalent of this object.
150 //
151 // The caller should use CheckModelStorage() as this function does not check
152 // internal consistency of the referenced variables.
153 CallbackRegistrationProto Proto() const;
154
155 // The events the solver should invoke the callback at.
156 //
157 // When a solver is called with registered events that are not supported,
158 // an InvalidArgument is returned. The supported events may depend on the
159 // model. For example registering for CallbackEvent::kMip with a model that
160 // only contains continuous variables will fail for most solvers. See the
161 // documentation of each event to see their supported solvers/model types.
162 absl::flat_hash_set<CallbackEvent> events;
163
164 // Restricts the variable returned in CallbackData.solution for event
165 // CallbackEvent::kMipSolution. This can improve performance.
167
168 // Restricts the variable returned in CallbackData.solution for event
169 // CallbackEvent::kMipNode. This can improve performance.
171
172 // If the callback will ever add "user cuts" at event CallbackEvent::kMipNode
173 // during the solve process (a linear constraint that excludes the current LP
174 // solution but does not cut off any integer points).
175 bool add_cuts = false;
176
177 // If the callback will ever add "lazy constraints" at event
178 // CallbackEvent::kMipNode or CallbackEvent::kMipSolution during the solve
179 // process (a linear constraint that excludes integer points).
181};
182
183// The input to the Callback function.
184//
185// The information available depends on the current event.
187 // Users will typically not need this function other than for testing.
188 CallbackData(CallbackEvent event, absl::Duration runtime);
189
190 // Users will typically not need this function.
191 // Will CHECK fail if proto is not valid.
192 CallbackData(const ModelStorage* storage, const CallbackDataProto& proto);
193
194 // The current state of the underlying solver.
196
197 // If event == CallbackEvent::kMipNode, the primal_solution contains the
198 // primal solution to the current LP-node relaxation. In some cases, no
199 // solution will be available (e.g. because LP was infeasible or the solve
200 // was imprecise).
201 // If event == CallbackEvent::kMipSolution, the primal_solution contains the
202 // newly found primal (integer) feasible solution. The solution is always
203 // present.
204 // Otherwise, the primal_solution is not available.
205 std::optional<VariableMap<double>> solution;
206
207 // Time since `Solve()` was called. Available for all events.
208 absl::Duration runtime;
209
210 // Only available for event == CallbackEvent::kPresolve.
211 CallbackDataProto::PresolveStats presolve_stats;
212
213 // Only available for event == CallbackEvent::kSimplex.
214 CallbackDataProto::SimplexStats simplex_stats;
215
216 // Only available for event == CallbackEvent::kBarrier.
217 CallbackDataProto::BarrierStats barrier_stats;
218
219 // Only available for event of CallbackEvent::kMip, CallbackEvent::kMipNode,
220 // or CallbackEvent::kMipSolution.
221 CallbackDataProto::MipStats mip_stats;
222};
223
224// The value returned by the Callback function.
226 // Prefer AddUserCut and AddLazyConstraint below instead of using this
227 // directly.
230 bool is_lazy = false;
231
232 const ModelStorage* storage() const {
234 }
235 };
236
237 // Adds a "user cut," a linear constraint that excludes the current LP
238 // solution but does not cut off any integer points. Use only for
239 // CallbackEvent::kMipNode.
240 void AddUserCut(BoundedLinearExpression linear_constraint) {
241 new_constraints.push_back({std::move(linear_constraint), false});
242 }
243
244 // Adds a "lazy constraint," a linear constraint that excludes integer points.
245 // Use only for CallbackEvent::kMipNode and CallbackEvent::kMipSolution.
247 new_constraints.push_back({std::move(linear_constraint), true});
248 }
249
250 // Returns a failure if the referenced variables don't belong to the input
251 // expected_storage (which must not be nullptr).
252 absl::Status CheckModelStorage(const ModelStorage* expected_storage) const;
253
254 // Returns the proto equivalent of this object.
255 //
256 // The caller should use CheckModelStorage() as this function does not check
257 // internal consistency of the referenced variables.
258 CallbackResultProto Proto() const;
259
260 // Stop the solve process and return early. Can be called from any event.
261 bool terminate = false;
262
263 // The user cuts and lazy constraints added. Prefer AddUserCut() and
264 // AddLazyConstraint() to modifying this directly.
265 std::vector<GeneratedLinearConstraint> new_constraints;
266
267 // A solution or partially defined solution to give to the solver.
268 std::vector<VariableMap<double>> suggested_solutions;
269};
270
271} // namespace math_opt
272} // namespace operations_research
273
274#endif // OR_TOOLS_MATH_OPT_CPP_CALLBACK_H_
CpModelProto proto
The output proto.
#define MATH_OPT_DEFINE_ENUM(CppEnum, proto_unspecified_value)
Definition enums.h:325
std::function< CallbackResult(const CallbackData &)> Callback
Definition callback.h:93
CallbackEvent
The supported events during a solve for callbacks.
Definition callback.h:96
In SWIG mode, we don't want anything besides these top-level includes.
A LinearExpression with upper and lower bounds.
CallbackDataProto::PresolveStats presolve_stats
Only available for event == CallbackEvent::kPresolve.
Definition callback.h:211
absl::Duration runtime
Time since Solve() was called. Available for all events.
Definition callback.h:208
CallbackDataProto::SimplexStats simplex_stats
Only available for event == CallbackEvent::kSimplex.
Definition callback.h:214
CallbackDataProto::BarrierStats barrier_stats
Only available for event == CallbackEvent::kBarrier.
Definition callback.h:217
std::optional< VariableMap< double > > solution
Definition callback.h:205
CallbackDataProto::MipStats mip_stats
Definition callback.h:221
CallbackData(CallbackEvent event, absl::Duration runtime)
Users will typically not need this function other than for testing.
Definition callback.cc:69
CallbackEvent event
The current state of the underlying solver.
Definition callback.h:195
absl::flat_hash_set< CallbackEvent > events
Definition callback.h:162
absl::Status CheckModelStorage(const ModelStorage *expected_storage) const
Definition callback.cc:92
CallbackRegistrationProto Proto() const
Definition callback.cc:101
The value returned by the Callback function.
Definition callback.h:225
absl::Status CheckModelStorage(const ModelStorage *expected_storage) const
Definition callback.cc:115
std::vector< GeneratedLinearConstraint > new_constraints
Definition callback.h:265
void AddLazyConstraint(BoundedLinearExpression linear_constraint)
Definition callback.h:246
bool terminate
Stop the solve process and return early. Can be called from any event.
Definition callback.h:261
std::vector< VariableMap< double > > suggested_solutions
A solution or partially defined solution to give to the solver.
Definition callback.h:268
void AddUserCut(BoundedLinearExpression linear_constraint)
Definition callback.h:240