108 const CallbackRegistrationProto& callback_registration,
111 callback_registration.mip_solution_filter(), model_summary.
variables))
112 <<
"invalid CallbackRegistrationProto.mip_solution_filter";
114 callback_registration.mip_node_filter(), model_summary.
variables))
115 <<
"invalid CallbackRegistrationProto.mip_node_filter";
117 const int num_events = callback_registration.request_registration_size();
118 bool can_add_lazy_constraints =
false;
119 bool can_add_cuts =
false;
120 for (
int k = 0; k < num_events; ++k) {
121 const CallbackEventProto requested_event =
122 callback_registration.request_registration(k);
123 if (requested_event == CALLBACK_EVENT_UNSPECIFIED ||
124 !CallbackEventProto_IsValid(requested_event)) {
125 return absl::InvalidArgumentError(absl::StrCat(
126 "invalid event ", requested_event,
" can not be registered"));
128 if (requested_event == CALLBACK_EVENT_MIP_NODE) {
129 can_add_lazy_constraints =
true;
132 if (requested_event == CALLBACK_EVENT_MIP_SOLUTION) {
133 can_add_lazy_constraints =
true;
136 if (callback_registration.add_cuts() && !can_add_cuts) {
137 return absl::InvalidArgumentError(
138 "can only add cuts at event CALLBACK_EVENT_MIP_NODE but this event was "
141 if (callback_registration.add_lazy_constraints() &&
142 !can_add_lazy_constraints) {
143 return absl::InvalidArgumentError(
144 "can only add lazy constraints at events CALLBACK_EVENT_MIP_NODE and "
145 "CALLBACK_EVENT_MIP_SOLUTION but neither of these events were "
149 return absl::OkStatus();
153 const CallbackDataProto& cb_data,
154 const CallbackRegistrationProto& callback_registration,
156 const CallbackEventProto
event = cb_data.event();
158 <<
"invalid CallbackDataProto.event for given CallbackRegistrationProto";
160 const bool has_primal_solution = cb_data.has_primal_solution_vector();
161 if (has_primal_solution && event != CALLBACK_EVENT_MIP_SOLUTION &&
162 event != CALLBACK_EVENT_MIP_NODE) {
163 return absl::InvalidArgumentError(
164 absl::StrCat(
"can't provide primal_solution_vector for event ", event,
168#ifdef RETURN_IF_SCALAR
169#error Collision in macro definition RETURN_IF_SCALAR
171#define RETURN_IF_SCALAR(stat, value, option) \
173 if (stat.has_##value()) { \
174 RETURN_IF_ERROR(CheckScalar(static_cast<double>(stat.value()), option)) \
175 << "Invalid CallbackDataProto." << #stat << "." << #value; \
180 .allow_negative_infinity =
false};
181 const DoubleOptions noneg = {.allow_positive_infinity =
false,
182 .allow_negative =
false};
184 const auto& presolve_stats = cb_data.presolve_stats();
189 const auto& simplex_stats = cb_data.simplex_stats();
196 const auto& barrier_stats = cb_data.barrier_stats();
205 const auto& mip_stats = cb_data.mip_stats();
216 <<
"Invalid CallbackDataProto.runtime.seconds";
218 <<
"Invalid CallbackDataProto.runtime.nanos";
219#undef RETURN_IF_SCALAR
223 case CALLBACK_EVENT_MIP_NODE:
224 case CALLBACK_EVENT_MIP_SOLUTION: {
225 if (has_primal_solution) {
226 const SparseVectorFilterProto& filter =
227 event == CALLBACK_EVENT_MIP_NODE
228 ? callback_registration.mip_node_filter()
229 : callback_registration.mip_solution_filter();
231 cb_data.primal_solution_vector(), filter, model_summary))
232 <<
"invalid CallbackDataProto.primal_solution_vector";
233 }
else if (event == CALLBACK_EVENT_MIP_SOLUTION) {
234 return absl::InvalidArgumentError(
235 absl::StrCat(
"must provide primal_solution_vector for event ",
241 case CALLBACK_EVENT_UNSPECIFIED:
245 <<
"CALLBACK_EVENT_UNSPECIFIED can not be a registered event, this "
246 "points to either an invalid CallbackRegistrationProto (which "
248 "one of the assumptions of this function), or memory corruption";
255 return absl::OkStatus();
259 const CallbackResultProto& callback_result,
260 const CallbackEventProto callback_event,
261 const CallbackRegistrationProto& callback_registration,
265 CHECK_OK(IsEventRegistered(callback_event, callback_registration));
267 if (!callback_result.cuts().empty()) {
268 if (callback_event != CALLBACK_EVENT_MIP_NODE &&
269 callback_event != CALLBACK_EVENT_MIP_SOLUTION) {
270 return absl::InvalidArgumentError(absl::StrCat(
271 "invalid CallbackResultProto, can't return cuts for callback_event ",
274 for (
const CallbackResultProto::GeneratedLinearConstraint& cut :
275 callback_result.cuts()) {
277 cut, callback_registration.add_cuts(),
278 callback_registration.add_lazy_constraints(), model_summary));
281 if (!callback_result.suggested_solutions().empty()) {
282 if (callback_event != CALLBACK_EVENT_MIP_NODE) {
283 return absl::InvalidArgumentError(absl::StrCat(
284 "invalid CallbackResultProto, can't return suggested solutions for "
288 for (
const SparseDoubleVectorProto& primal_solution_vector :
289 callback_result.suggested_solutions()) {
291 primal_solution_vector, SparseVectorFilterProto(), model_summary))
292 <<
"invalid CallbackResultProto.suggested_solutions";
296 return absl::OkStatus();
300 const CallbackRegistrationProto& registration,
301 const absl::flat_hash_set<CallbackEventProto>& supported_events) {
302 std::vector<CallbackEventProto> unsupported_events;
303 for (
const CallbackEventProto event :
EventSet(registration)) {
304 if (!supported_events.contains(event)) {
305 unsupported_events.push_back(event);
309 if (unsupported_events.empty()) {
310 return absl::OkStatus();
313 std::sort(unsupported_events.begin(), unsupported_events.end());
315 const bool plural = unsupported_events.size() >= 2;
316 return absl::InvalidArgumentError(
317 absl::StrCat(
"event", (plural ?
"s { " :
" "),
318 absl::StrJoin(unsupported_events,
", ",
319 ProtoEnumFormatter<CallbackEventProto>()),
320 (plural ?
" } are" :
" is"),
" not supported"));