OR-Tools  9.6
callback.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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 
87 namespace operations_research {
88 namespace math_opt {
89 
90 struct CallbackData;
91 struct CallbackResult;
92 
93 using Callback = std::function<CallbackResult(const CallbackData&)>;
94 
95 // The supported events for LP/MIP callbacks.
96 enum class CallbackEvent {
97  // The solver is currently running presolve.
98  //
99  // This event is supported for MIP & LP models by SolverType::kGurobi. Other
100  // solvers don't support this event.
101  kPresolve = CALLBACK_EVENT_PRESOLVE,
102 
103  // The solver is currently running the simplex method.
104  //
105  // This event is supported for MIP & LP models by SolverType::kGurobi. Other
106  // solvers don't support this event.
107  kSimplex = CALLBACK_EVENT_SIMPLEX,
108 
109  // The solver is in the MIP loop (called periodically before starting a new
110  // node). Useful for early termination. Note that this event does not provide
111  // information on LP relaxations nor about new incumbent solutions.
112  //
113  // This event is supported for MIP models only by SolverType::kGurobi. Other
114  // solvers don't support this event.
115  kMip = CALLBACK_EVENT_MIP,
116 
117  // Called every time a new MIP incumbent is found.
118  //
119  // This event is fully supported for MIP models by SolverType::kGurobi. CP-SAT
120  // has partial support: you can view the solutions and request termination,
121  // but you cannot add lazy constraints. Other solvers don't support this
122  // event.
123  kMipSolution = CALLBACK_EVENT_MIP_SOLUTION,
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 CommonSolveParameters 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 only by SolverType::kGurobi. Other
134  // solvers don't support this event.
135  kMipNode = CALLBACK_EVENT_MIP_NODE,
136 
137  // Called in each iterate of an interior point/barrier method.
138  //
139  // This event is supported for LP models only by SolverType::kGurobi. Other
140  // solvers don't support this event.
141  kBarrier = CALLBACK_EVENT_BARRIER,
142 };
143 
144 MATH_OPT_DEFINE_ENUM(CallbackEvent, CALLBACK_EVENT_UNSPECIFIED);
145 
146 // Provided with a callback at the start of a Solve() to inform the solver:
147 // * what information the callback needs,
148 // * how the callback might alter the solve process.
150  // Returns a failure if the referenced variables don't belong to the input
151  // expected_storage (which must not be nullptr).
152  absl::Status CheckModelStorage(const ModelStorage* expected_storage) const;
153 
154  // Returns the proto equivalent of this object.
155  //
156  // The caller should use CheckModelStorage() as this function does not check
157  // internal consistency of the referenced variables.
158  CallbackRegistrationProto Proto() const;
159 
160  // The events the solver should invoke the callback at.
161  //
162  // A solver will return an InvalidArgument status when called with registered
163  // events that are not supported for the selected solver and the type of
164  // model. For example registring for CallbackEvent::kMip with a model that
165  // only contains continuous variables will fail for most solvers (see the
166  // documentation of each event to see which solvers support them and in which
167  // case).
168  absl::flat_hash_set<CallbackEvent> events;
169 
170  // Restricts the variable returned in CallbackData.solution for event
171  // CallbackEvent::kMipSolution. This can improve performance.
173 
174  // Restricts the variable returned in CallbackData.solution for event
175  // CallbackEvent::kMipNode. This can improve performance.
177 
178  // If the callback will ever add "user cuts" at event CallbackEvent::kMipNode
179  // during the solve process (a linear constraint that excludes the current LP
180  // solution but does not cut off any integer points).
181  bool add_cuts = false;
182 
183  // If the callback will ever add "lazy constraints" at event
184  // CallbackEvent::kMipNode or CallbackEvent::kMipSolution during the solve
185  // process (a linear constraint that excludes integer points).
186  bool add_lazy_constraints = false;
187 };
188 
189 // The input to the Callback function.
190 //
191 // The information available depends on the current event.
192 struct CallbackData {
193  // Users will typically not need this function other than for testing.
194  CallbackData(CallbackEvent event, absl::Duration runtime);
195 
196  // Users will typically not need this function.
197  // Will CHECK fail if proto is not valid.
198  CallbackData(const ModelStorage* storage, const CallbackDataProto& proto);
199 
200  // The current state of the underlying solver.
202 
203  // If event == CallbackEvent::kMipNode, the primal_solution contains the
204  // primal solution to the current LP-node relaxation. In some cases, no
205  // solution will be available (e.g. because LP was infeasible or the solve
206  // was imprecise).
207  // If event == CallbackEvent::kMipSolution, the primal_solution contains the
208  // newly found primal (integer) feasible solution. The solution is always
209  // present.
210  // Otherwise, the primal_solution is not available.
211  std::optional<VariableMap<double>> solution;
212 
213  // Time since `Solve()` was called. Available for all events except
214  // CallbackEvent::kPolling.
215  absl::Duration runtime;
216 
217  // Only available for event == CallbackEvent::kPresolve.
218  CallbackDataProto::PresolveStats presolve_stats;
219 
220  // Only available for event == CallbackEvent::kSimplex.
221  CallbackDataProto::SimplexStats simplex_stats;
222 
223  // Only available for event == CallbackEvent::kBarrier.
224  CallbackDataProto::BarrierStats barrier_stats;
225 
226  // Only available for event of CallbackEvent::kMip, CallbackEvent::kMipNode,
227  // or CallbackEvent::kMipSolution.
228  CallbackDataProto::MipStats mip_stats;
229 };
230 
231 // The value returned by the Callback function.
233  // Prefer AddUserCut and AddLazyConstraint below instead of using this
234  // directly.
237  bool is_lazy = false;
238 
239  const ModelStorage* storage() const {
241  }
242  };
243 
244  // Adds a "user cut," a linear constraint that excludes the current LP
245  // solution but does not cut off any integer points. Use only for
246  // CallbackEvent::kMipNode.
247  void AddUserCut(BoundedLinearExpression linear_constraint) {
248  new_constraints.push_back({std::move(linear_constraint), false});
249  }
250 
251  // Adds a "lazy constraint," a linear constraint that excludes integer points.
252  // Use only for CallbackEvent::kMipNode and CallbackEvent::kMipSolution.
253  void AddLazyConstraint(BoundedLinearExpression linear_constraint) {
254  new_constraints.push_back({std::move(linear_constraint), true});
255  }
256 
257  // Returns a failure if the referenced variables don't belong to the input
258  // expected_storage (which must not be nullptr).
259  absl::Status CheckModelStorage(const ModelStorage* expected_storage) const;
260 
261  // Returns the proto equivalent of this object.
262  //
263  // The caller should use CheckModelStorage() as this function does not check
264  // internal consistency of the referenced variables.
265  CallbackResultProto Proto() const;
266 
267  // Stop the solve process and return early. Can be called from any event.
268  bool terminate = false;
269 
270  // The user cuts and lazy constraints added. Prefer AddUserCut() and
271  // AddLazyConstraint() to modifying this directly.
272  std::vector<GeneratedLinearConstraint> new_constraints;
273 
274  // A solution or partially defined solution to give to the solver.
275  std::vector<VariableMap<double>> suggested_solutions;
276 };
277 
278 } // namespace math_opt
279 } // namespace operations_research
280 
281 #endif // OR_TOOLS_MATH_OPT_CPP_CALLBACK_H_
CpModelProto proto
std::function< CallbackResult(const CallbackData &)> Callback
Definition: callback.h:93
MATH_OPT_DEFINE_ENUM(BasisStatus, BASIS_STATUS_UNSPECIFIED)
Collection of objects used to extend the Constraint Solver library.
CallbackDataProto::PresolveStats presolve_stats
Definition: callback.h:218
CallbackData(CallbackEvent event, absl::Duration runtime)
Definition: callback.cc:69
std::optional< VariableMap< double > > solution
Definition: callback.h:211
CallbackDataProto::SimplexStats simplex_stats
Definition: callback.h:221
CallbackDataProto::BarrierStats barrier_stats
Definition: callback.h:224
CallbackDataProto::MipStats mip_stats
Definition: callback.h:228
CallbackRegistrationProto Proto() const
Definition: callback.cc:105
absl::Status CheckModelStorage(const ModelStorage *expected_storage) const
Definition: callback.cc:92
absl::flat_hash_set< CallbackEvent > events
Definition: callback.h:168
std::vector< VariableMap< double > > suggested_solutions
Definition: callback.h:275
void AddLazyConstraint(BoundedLinearExpression linear_constraint)
Definition: callback.h:253
CallbackResultProto Proto() const
Definition: callback.cc:135
absl::Status CheckModelStorage(const ModelStorage *expected_storage) const
Definition: callback.cc:119
void AddUserCut(BoundedLinearExpression linear_constraint)
Definition: callback.h:247
std::vector< GeneratedLinearConstraint > new_constraints
Definition: callback.h:272