162 std::function<
void(
const std::string&)> logging_callback,
163 std::function<
void(
const MPSolution&)> solution_callback) {
174 if (logging_callback !=
nullptr) {
181 if (request->has_solver_specific_parameters()) {
183 if constexpr (!std::is_base_of<Message, sat::SatParameters>::value) {
184 if (!params.MergeFromString(request->solver_specific_parameters())) {
185 return InvalidParametersResponse(
187 "solver_specific_parameters is not a valid binary stream of the "
188 "SatParameters proto");
192 request->solver_specific_parameters(), ¶ms)) {
193 return InvalidParametersResponse(
195 "solver_specific_parameters is not a valid textual representation "
196 "of the SatParameters proto");
204 if (!error.empty()) {
205 return InvalidParametersResponse(
206 logger, absl::StrCat(
"Invalid CP-SAT parameters: ", error));
216 if (request->has_solver_time_limit_seconds()) {
224 std::optional<LazyMutableCopy<MPModelProto>> optional_model =
226 if (!optional_model) {
236 SOLVER_LOG(&logger, CpSolverResponseStats(cp_response));
243 std::unique_ptr<MPModelProto> mp_model =
244 std::move(optional_model).value().copy_or_move_as_unique_ptr();
248 std::move(request).dispose();
254 mp_model.get(), &logger);
258 return InvalidModelResponse(logger,
"Extra CP-SAT validation failed.");
264 return InfeasibleResponse(logger,
265 "An integer variable has an empty domain");
270 RemoveNearZeroTerms(params, mp_model.get(), &logger);
275 std::vector<std::unique_ptr<glop::Preprocessor>> for_postsolve;
278 glop_params, mp_model.get(), &for_postsolve, &logger);
284 return InfeasibleResponse(
285 logger,
"Problem proven infeasible during MIP presolve");
287 return InvalidModelResponse(
288 logger,
"Problem detected invalid during MIP presolve");
296 SOLVER_LOG(&logger,
"MIP presolve: problem infeasible or unbounded.");
297 LOG(INFO) << CpSolverResponseStats(cp_response);
302 "Problem proven infeasible or unbounded during MIP presolve");
309 return TimeLimitResponse(logger);
312 RemoveNearZeroTerms(params, mp_model.get(), &logger);
315 SOLVER_LOG(&logger,
"Scaling to pure integer problem.");
317 const int num_variables = mp_model->variable_size();
318 std::vector<double> var_scaling(num_variables, 1.0);
323 return InfeasibleResponse(
324 logger,
"A detected integer variable has an empty domain");
329 ? std::numeric_limits<double>::infinity()
333 for (
int i = 0; i < var_scaling.size(); ++i) {
334 var_scaling[i] *= other_scaling[i];
340 bool all_integer =
true;
342 if (!var.is_integer()) {
348 return InvalidModelResponse(
350 "The model contains non-integer variables but the parameter "
351 "'only_solve_ip' was set. Change this parameter if you "
352 "still want to solve a more constrained version of the original MIP "
353 "where non-integer variables can only take a finite set of values.");
358 if (!ConvertMPModelProtoToCpModelProto(params, *mp_model, &cp_model,
360 return InvalidModelResponse(logger,
361 "Failed to convert model into CP-SAT model");
363 DCHECK_EQ(cp_model.
variables().size(), var_scaling.size());
364 DCHECK_EQ(cp_model.
variables().size(), mp_model->variable().size());
367 if (mp_model->has_solution_hint()) {
369 const int size = mp_model->solution_hint().var_index().size();
370 for (
int i = 0; i < size; ++i) {
371 const int var = mp_model->solution_hint().var_index(i);
372 if (var >= var_scaling.size())
continue;
377 double value = mp_model->solution_hint().var_value(i) * var_scaling[var];
382 cp_model_hint->add_vars(var);
383 cp_model_hint->add_values(
static_cast<int64_t
>(std::round(value)));
388 const int old_num_variables = mp_model->variable().size();
389 const int old_num_constraints = mp_model->constraint().size();
390 const bool is_maximize = mp_model->maximize();
395 std::numeric_limits<double>::infinity()) {
402 sat_model.
Add(NewSatParameters(params));
403 if (interrupt_solve !=
nullptr) {
413 (glop::ColIndex(old_num_variables)));
416 static_cast<double>(cp_response.solution(v)) / var_scaling[v];
418 for (
int i = for_postsolve.size(); --i >= 0;) {
419 for_postsolve[i]->RecoverSolution(&glop_solution);
428 if (solution_callback !=
nullptr) {
431 solution_callback(post_solve(cp_response));
452 MPSolution post_solved_solution = post_solve(cp_response);
462 if (absl::MakeConstSpan(additional_solution.values()) ==
463 absl::MakeConstSpan(cp_response.
solution())) {
470 obj += additional_solution.values(var) * obj_coef;
485 return left->objective_value() > right->objective_value();
487 return left->objective_value() < right->objective_value();