4545// std::vector<VariableMap<double>> solutions;
4646// auto cb = [&solutions](const CallbackData& cb_data) {
4747// // NOTE: this assumes the callback is always called from the same thread.
48- // // Gurobi always does this, multi-threaded SCIP does not.
48+ // // Gurobi always does this, multi-threaded SCIP or Xpress do not.
4949// solutions.push_back(*cb_data.solution);
5050// return CallbackResult();
5151// };
6262// CHECK fail). Some solvers do not support callbacks or certain events, in this
6363// case the callback is ignored. TODO(b/180617976): change this behavior.
6464//
65- // Some solvers may call callback from multiple threads (SCIP will, Gurobi will
66- // not). You should either solve with one thread (see
65+ // Some solvers may call callback from multiple threads (SCIP and Xpress will,
66+ // Gurobi will not). You should either solve with one thread (see
6767// solver_parameters.threads), write a threadsafe callback, or consult
6868// the documentation of your underlying solver.
6969#ifndef ORTOOLS_MATH_OPT_CPP_CALLBACK_H_
@@ -97,26 +97,30 @@ using Callback = std::function<CallbackResult(const CallbackData&)>;
9797enum class CallbackEvent {
9898 // The solver is currently running presolve.
9999 //
100- // This event is supported for SolverType::kGurobi only.
100+ // This event is supported for SolverType::kGurobi or SolverType::kXpress
101+ // only.
101102 kPresolve = CALLBACK_EVENT_PRESOLVE ,
102103
103104 // The solver is currently running the simplex method.
104105 //
105- // This event is supported for SolverType::kGurobi only.
106+ // This event is supported for SolverType::kGurobi or SolverType::kXpress
107+ // only.
106108 kSimplex = CALLBACK_EVENT_SIMPLEX ,
107109
108110 // The solver is in the MIP loop (called periodically before starting a new
109111 // node). Useful for early termination. Note that this event does not provide
110112 // information on LP relaxations nor about new incumbent solutions.
111113 //
112- // This event is fully supported for MIP models with SolverType::kGurobi only.
114+ // This event is fully supported for MIP models with SolverType::kGurobi or
115+ // SolverType::kXpress only.
113116 // If used with SolverType::kCpSat, it is called when the dual bound is
114117 // improved.
115118 kMip = CALLBACK_EVENT_MIP ,
116119
117120 // Called every time a new MIP incumbent is found.
118121 //
119- // This event is fully supported for MIP models by SolverType::kGurobi.
122+ // This event is fully supported for MIP models by SolverType::kGurobi or
123+ // SolverType::kXpress only.
120124 // SolverType::kCpSat has partial support: you can view the solutions and
121125 // request termination, but you cannot add lazy constraints. Other solvers
122126 // don't support this event.
@@ -130,17 +134,37 @@ enum class CallbackEvent {
130134 // being called and/or adding cuts at this event, the behavior is solver
131135 // specific.
132136 //
133- // This event is supported for MIP models with SolverType::kGurobi only.
137+ // This event is supported for MIP models with SolverType::kGurobi or
138+ // SolverType::kXpress only.
139+ // For Xpress disabling cuts will prevent this event. To disable cuts
140+ // and still get this event called for Xpress, disable cuts by setting
141+ // COVERCUTS, GOMCUTS, TREECOVERCUTS, TREEGOMCUTS to 0.
134142 kMipNode = CALLBACK_EVENT_MIP_NODE ,
135143
136144 // Called in each iterate of an interior point/barrier method.
137145 //
138- // This event is supported for SolverType::kGurobi only.
146+ // This event is supported for SolverType::kGurobi or SolverType::kXpress
147+ // only.
139148 kBarrier = CALLBACK_EVENT_BARRIER ,
140149};
141150
142151MATH_OPT_DEFINE_ENUM (CallbackEvent, CALLBACK_EVENT_UNSPECIFIED );
143152
153+ // Where a solution for a CALLBACK_EVENT_MIP_SOLUTION came from.
154+ enum class CallbackSolutionSource {
155+ // The solution came from an LP relaxation that happened to be integer
156+ // feasible.
157+ kIntegral = CALLBACK_SOLUTION_SOURCE_INTEGRAL ,
158+ // The solution came from a heuristic.
159+ kHeuristic = CALLBACK_SOLUTION_SOURCE_HEURISTIC ,
160+ // The solution came from a solution vector provided by the user.
161+ // This may include solutions the solver had to "repair".
162+ kUser = CALLBACK_SOLUTION_SOURCE_USER ,
163+ };
164+
165+ MATH_OPT_DEFINE_ENUM (CallbackSolutionSource,
166+ CALLBACK_SOLUTION_SOURCE_UNSPECIFIED );
167+
144168// Provided with a callback at the start of a Solve() to inform the solver:
145169// * what information the callback needs,
146170// * how the callback might alter the solve process.
@@ -255,13 +279,17 @@ struct CallbackResult {
255279 };
256280
257281 // 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.
282+ // solution but does not cut off any integer points.
283+ // The constraint must be globally valid (and not only valid for the subtree
284+ // rooted at the MIP search node at which the event was triggered).
285+ // Use only for CallbackEvent::kMipNode.
260286 void AddUserCut (BoundedLinearExpression linear_constraint) {
261287 new_constraints.push_back ({std::move (linear_constraint), false });
262288 }
263289
264290 // Adds a "lazy constraint," a linear constraint that excludes integer points.
291+ // The constraint must be globally valid (and not only valid for the subtree
292+ // rooted at the MIP search node at which the event was triggered).
265293 // Use only for CallbackEvent::kMipNode and CallbackEvent::kMipSolution.
266294 void AddLazyConstraint (BoundedLinearExpression linear_constraint) {
267295 new_constraints.push_back ({std::move (linear_constraint), true });
@@ -299,12 +327,13 @@ struct CallbackResult {
299327
300328 // The user cuts and lazy constraints added. Prefer AddUserCut() and
301329 // AddLazyConstraint() to modifying this directly.
330+ // All constraints are assumed to be globally valid.
302331 std::vector<GeneratedLinearConstraint> new_constraints;
303332
304333 // A list of solutions (or partially defined solutions) to suggest to the
305- // solver. Some solvers (e.g. gurobi) will try and convert a partial solution
306- // into a full solution. Use only for CallbackEvent::kMipNode or
307- // CallbackEvent::kMipSolution.
334+ // solver. Some solvers (e.g. gurobi or Xpress ) will try and convert a
335+ // partial solution into a full solution. Use only for
336+ // CallbackEvent::kMipNode or CallbackEvent:: kMipSolution.
308337 std::vector<VariableMap<double >> suggested_solutions;
309338};
310339
0 commit comments