31#if !defined(__PORTABLE_PLATFORM__)
32#include "absl/synchronization/notification.h"
33#include "google/protobuf/text_format.h"
38#include "absl/base/attributes.h"
39#include "absl/container/flat_hash_set.h"
40#include "absl/memory/memory.h"
41#include "absl/status/status.h"
42#include "absl/strings/str_cat.h"
43#include "absl/strings/str_format.h"
44#include "absl/strings/str_join.h"
45#include "absl/strings/str_split.h"
46#include "absl/synchronization/mutex.h"
99ABSL_FLAG(std::string, cp_model_dump_prefix,
".\\",
100 "Prefix filename for all dumped files");
103 "Prefix filename for all dumped files");
106 "DEBUG ONLY. When set to true, SolveCpModel() will dump its model "
107 "protos (original model, presolved model, mapping model) in text "
108 "format to 'FLAGS_cp_model_dump_prefix'{model|presolved_model|"
109 "mapping_model}.pb.txt.");
112 "DEBUG ONLY. When set to true, solve will dump all "
113 "lns models proto in text format to "
114 "'FLAGS_cp_model_dump_prefix'lns_xxx.pb.txt.");
117 bool, cp_model_dump_problematic_lns,
false,
118 "DEBUG ONLY. Similar to --cp_model_dump_lns, but only dump fragment for "
119 "which we got an issue while validating the postsolved solution. This "
120 "allows to debug presolve issues without dumping all the models.");
123 "DEBUG ONLY. If true, the final response of each solve will be "
124 "dumped to 'FLAGS_cp_model_dump_prefix'response.pb.txt");
127 "This is interpreted as a text SatParameters proto. The "
128 "specified fields will override the normal ones for all solves.");
131 "If non-empty, a proof in DRAT format will be written to this file. "
132 "This will only be used for pure-SAT problems.");
135 "If true, a proof in DRAT format will be stored in memory and "
136 "checked if the problem is UNSAT. This will only be used for "
137 "pure-SAT problems.");
140 std::numeric_limits<double>::infinity(),
141 "Maximum time in seconds to check the DRAT proof. This will only "
142 "be used is the drat_check flag is enabled.");
144ABSL_FLAG(
bool, cp_model_check_intermediate_solutions,
false,
145 "When true, all intermediate solutions found by the solver will be "
146 "checked. This can be expensive, therefore it is off by default.");
149 "If non-empty, dump a contention pprof proto to the specified "
150 "destination at the end of the solve.");
158std::string Summarize(
const std::string&
input) {
161 return absl::StrCat(
input.substr(0, half),
" ... ",
172 std::map<std::string, int> num_constraints_by_name;
173 std::map<std::string, int> num_reif_constraints_by_name;
174 std::map<std::string, int> name_to_num_literals;
175 std::map<std::string, int> name_to_num_terms;
176 std::map<std::string, int> name_to_num_complex_domain;
178 int no_overlap_2d_num_rectangles = 0;
179 int no_overlap_2d_num_optional_rectangles = 0;
180 int no_overlap_2d_num_linear_areas = 0;
181 int no_overlap_2d_num_quadratic_areas = 0;
183 int cumulative_num_intervals = 0;
184 int cumulative_num_optional_intervals = 0;
185 int cumulative_num_variable_sizes = 0;
186 int cumulative_num_variable_demands = 0;
188 int no_overlap_num_intervals = 0;
189 int no_overlap_num_optional_intervals = 0;
190 int no_overlap_num_variable_sizes = 0;
197 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) {
198 if (
ct.linear().vars_size() == 1)
name +=
"1";
199 if (
ct.linear().vars_size() == 2)
name +=
"2";
200 if (
ct.linear().vars_size() == 3)
name +=
"3";
201 if (
ct.linear().vars_size() > 3)
name +=
"N";
204 num_constraints_by_name[
name]++;
205 if (!
ct.enforcement_literal().empty()) {
206 num_reif_constraints_by_name[
name]++;
215 auto expression_is_fixed =
217 for (
const int ref : expr.vars()) {
218 if (!variable_is_fixed(ref)) {
225 auto interval_has_fixed_size = [&
model_proto, &expression_is_fixed](
int c) {
229 auto constraint_is_optional = [&
model_proto](
int i) {
235 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) {
236 name_to_num_literals[
name] +=
ct.bool_or().literals().size();
237 }
else if (
ct.constraint_case() ==
238 ConstraintProto::ConstraintCase::kBoolAnd) {
239 name_to_num_literals[
name] +=
ct.bool_and().literals().size();
240 }
else if (
ct.constraint_case() ==
241 ConstraintProto::ConstraintCase::kAtMostOne) {
242 name_to_num_literals[
name] +=
ct.at_most_one().literals().size();
243 }
else if (
ct.constraint_case() ==
244 ConstraintProto::ConstraintCase::kExactlyOne) {
245 name_to_num_literals[
name] +=
ct.exactly_one().literals().size();
246 }
else if (
ct.constraint_case() ==
247 ConstraintProto::ConstraintCase::kNoOverlap2D) {
248 const int num_boxes =
ct.no_overlap_2d().x_intervals_size();
249 no_overlap_2d_num_rectangles += num_boxes;
250 for (
int i = 0; i < num_boxes; ++i) {
251 const int x_interval =
ct.no_overlap_2d().x_intervals(i);
252 const int y_interval =
ct.no_overlap_2d().y_intervals(i);
253 if (constraint_is_optional(x_interval) ||
254 constraint_is_optional(y_interval)) {
255 no_overlap_2d_num_optional_rectangles++;
257 const int num_fixed = interval_has_fixed_size(x_interval) +
258 interval_has_fixed_size(y_interval);
259 if (num_fixed == 0) {
260 no_overlap_2d_num_quadratic_areas++;
261 }
else if (num_fixed == 1) {
262 no_overlap_2d_num_linear_areas++;
265 }
else if (
ct.constraint_case() ==
266 ConstraintProto::ConstraintCase::kNoOverlap) {
267 const int num_intervals =
ct.no_overlap().intervals_size();
268 no_overlap_num_intervals += num_intervals;
269 for (
int i = 0; i < num_intervals; ++i) {
270 const int interval =
ct.no_overlap().intervals(i);
271 if (constraint_is_optional(
interval)) {
272 no_overlap_num_optional_intervals++;
274 if (!interval_has_fixed_size(
interval)) {
275 no_overlap_num_variable_sizes++;
278 }
else if (
ct.constraint_case() ==
279 ConstraintProto::ConstraintCase::kCumulative) {
280 const int num_intervals =
ct.cumulative().intervals_size();
281 cumulative_num_intervals += num_intervals;
282 for (
int i = 0; i < num_intervals; ++i) {
283 const int interval =
ct.cumulative().intervals(i);
284 if (constraint_is_optional(
interval)) {
285 cumulative_num_optional_intervals++;
287 if (!interval_has_fixed_size(
interval)) {
288 cumulative_num_variable_sizes++;
290 if (!expression_is_fixed(
ct.cumulative().demands(i))) {
291 cumulative_num_variable_demands++;
296 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear &&
297 ct.linear().vars_size() > 3) {
298 name_to_num_terms[
name] +=
ct.linear().vars_size();
300 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear &&
301 ct.linear().vars_size() > 1 &&
ct.linear().domain().size() > 2) {
302 name_to_num_complex_domain[
name]++;
306 int num_constants = 0;
307 std::set<int64_t> constant_values;
308 std::map<Domain, int> num_vars_per_domains;
310 if (
var.domain_size() == 2 &&
var.domain(0) ==
var.domain(1)) {
312 constant_values.insert(
var.domain(0));
330 &result,
"Search strategy: on ", strategy.variables_size(),
332 ProtoEnumToString<DecisionStrategyProto::VariableSelectionStrategy>(
333 strategy.variable_selection_strategy()),
335 ProtoEnumToString<DecisionStrategyProto::DomainReductionStrategy>(
336 strategy.domain_reduction_strategy()),
340 const std::string objective_string =
347 " in floating point objective)")
350 objective_string,
"\n");
351 if (num_vars_per_domains.size() < 100) {
352 for (
const auto& entry : num_vars_per_domains) {
353 const std::string temp = absl::StrCat(
" - ", entry.second,
" in ",
354 entry.first.ToString(),
"\n");
355 absl::StrAppend(&result, Summarize(temp));
358 int64_t max_complexity = 0;
361 for (
const auto& entry : num_vars_per_domains) {
365 max_complexity,
static_cast<int64_t
>(entry.first.NumIntervals()));
367 absl::StrAppend(&result,
" - ", num_vars_per_domains.size(),
368 " different domains in [",
min,
",",
max,
369 "] with a largest complexity of ", max_complexity,
".\n");
372 if (num_constants > 0) {
373 const std::string temp =
374 absl::StrCat(
" - ", num_constants,
" constants in {",
375 absl::StrJoin(constant_values,
","),
"} \n");
376 absl::StrAppend(&result, Summarize(temp));
379 std::vector<std::string> constraints;
380 constraints.reserve(num_constraints_by_name.size());
381 for (
const auto& entry : num_constraints_by_name) {
382 const std::string&
name = entry.first;
383 constraints.push_back(absl::StrCat(
"#",
name,
": ", entry.second));
385 absl::StrAppend(&constraints.back(),
386 " (#enforced: ", num_reif_constraints_by_name[
name],
")");
389 absl::StrAppend(&constraints.back(),
390 " (#literals: ", name_to_num_literals[
name],
")");
393 absl::StrAppend(&constraints.back(),
394 " (#terms: ", name_to_num_terms[
name],
")");
397 absl::StrAppend(&constraints.back(),
398 " (#complex_domain: ", name_to_num_complex_domain[
name],
401 if (
name ==
"kNoOverlap2D") {
402 absl::StrAppend(&constraints.back(),
403 " (#rectangles: ", no_overlap_2d_num_rectangles);
404 if (no_overlap_2d_num_optional_rectangles > 0) {
405 absl::StrAppend(&constraints.back(),
406 ", #optional: ", no_overlap_2d_num_optional_rectangles);
408 if (no_overlap_2d_num_linear_areas > 0) {
409 absl::StrAppend(&constraints.back(),
410 ", #linear_areas: ", no_overlap_2d_num_linear_areas);
412 if (no_overlap_2d_num_quadratic_areas > 0) {
413 absl::StrAppend(&constraints.back(),
", #quadratic_areas: ",
414 no_overlap_2d_num_quadratic_areas);
416 absl::StrAppend(&constraints.back(),
")");
417 }
else if (
name ==
"kCumulative") {
418 absl::StrAppend(&constraints.back(),
419 " (#intervals: ", cumulative_num_intervals);
420 if (cumulative_num_optional_intervals > 0) {
421 absl::StrAppend(&constraints.back(),
422 ", #optional: ", cumulative_num_optional_intervals);
424 if (cumulative_num_variable_sizes > 0) {
425 absl::StrAppend(&constraints.back(),
426 ", #variable_sizes: ", cumulative_num_variable_sizes);
428 if (cumulative_num_variable_demands > 0) {
429 absl::StrAppend(&constraints.back(),
", #variable_demands: ",
430 cumulative_num_variable_demands);
432 absl::StrAppend(&constraints.back(),
")");
433 }
else if (
name ==
"kNoOverlap") {
434 absl::StrAppend(&constraints.back(),
435 " (#intervals: ", no_overlap_num_intervals);
436 if (no_overlap_num_optional_intervals > 0) {
437 absl::StrAppend(&constraints.back(),
438 ", #optional: ", no_overlap_num_optional_intervals);
440 if (no_overlap_num_variable_sizes > 0) {
441 absl::StrAppend(&constraints.back(),
442 ", #variable_sizes: ", no_overlap_num_variable_sizes);
444 absl::StrAppend(&constraints.back(),
")");
447 std::sort(constraints.begin(), constraints.end());
448 absl::StrAppend(&result, absl::StrJoin(constraints,
"\n"));
454 bool has_objective) {
456 absl::StrAppend(&result,
"CpSolverResponse summary:");
457 absl::StrAppend(&result,
"\nstatus: ",
458 ProtoEnumToString<CpSolverStatus>(
response.status()));
461 absl::StrAppendFormat(&result,
"\nobjective: %.16g",
463 absl::StrAppendFormat(&result,
"\nbest_bound: %.16g",
466 absl::StrAppend(&result,
"\nobjective: NA");
467 absl::StrAppend(&result,
"\nbest_bound: NA");
470 absl::StrAppend(&result,
"\nbooleans: ",
response.num_booleans());
471 absl::StrAppend(&result,
"\nconflicts: ",
response.num_conflicts());
472 absl::StrAppend(&result,
"\nbranches: ",
response.num_branches());
476 absl::StrAppend(&result,
477 "\npropagations: ",
response.num_binary_propagations());
479 &result,
"\ninteger_propagations: ",
response.num_integer_propagations());
481 absl::StrAppend(&result,
"\nrestarts: ",
response.num_restarts());
482 absl::StrAppend(&result,
"\nlp_iterations: ",
response.num_lp_iterations());
483 absl::StrAppend(&result,
"\nwalltime: ",
response.wall_time());
484 absl::StrAppend(&result,
"\nusertime: ",
response.user_time());
485 absl::StrAppend(&result,
486 "\ndeterministic_time: ",
response.deterministic_time());
487 absl::StrAppend(&result,
"\ngap_integral: ",
response.gap_integral());
488 absl::StrAppend(&result,
"\n");
494#if !defined(__PORTABLE_PLATFORM__)
497void FillSolutionInResponse(
const CpModelProto&
model_proto,
const Model&
model,
501 auto* mapping =
model.Get<CpModelMapping>();
504 std::vector<int64_t> solution;
506 if (mapping->IsInteger(i)) {
507 const IntegerVariable
var = mapping->Integer(i);
513 DCHECK(mapping->IsBoolean(i));
515 if (trail->Assignment().LiteralIsAssigned(
literal)) {
519 solution.push_back(0);
525 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
529 for (
const int64_t
value : solution) {
536IntegerVariable GetOrCreateVariableWithTightBound(
537 const std::vector<std::pair<IntegerVariable, int64_t>>& terms,
540 if (terms.size() == 1 && terms.front().second == 1) {
541 return terms.front().first;
543 if (terms.size() == 1 && terms.front().second == -1) {
549 for (
const std::pair<IntegerVariable, int64_t> var_coeff : terms) {
552 const int64_t
coeff = var_coeff.second;
553 const int64_t prod1 = min_domain *
coeff;
554 const int64_t prod2 = max_domain *
coeff;
561IntegerVariable GetOrCreateVariableGreaterOrEqualToSumOf(
562 const std::vector<std::pair<IntegerVariable, int64_t>>& terms,
565 if (terms.size() == 1 && terms.front().second == 1) {
566 return terms.front().first;
568 if (terms.size() == 1 && terms.front().second == -1) {
573 const IntegerVariable new_var =
574 GetOrCreateVariableWithTightBound(terms,
model);
575 std::vector<IntegerVariable> vars;
576 std::vector<int64_t> coeffs;
577 for (
const auto& term : terms) {
578 vars.push_back(term.first);
579 coeffs.push_back(term.second);
581 vars.push_back(new_var);
582 coeffs.push_back(-1);
590IntegerVariable AddLPConstraints(
const CpModelProto&
model_proto, Model* m) {
599 const int num_lp_constraints = relaxation.linear_constraints.size();
600 const int num_lp_cut_generators = relaxation.cut_generators.size();
601 const int num_integer_variables =
602 m->GetOrCreate<IntegerTrail>()->NumIntegerVariables().value();
605 num_integer_variables);
606 auto get_constraint_index = [](
int ct_index) {
return ct_index; };
607 auto get_cut_generator_index = [num_lp_constraints](
int cut_index) {
608 return num_lp_constraints + cut_index;
610 auto get_var_index = [num_lp_constraints,
611 num_lp_cut_generators](IntegerVariable
var) {
612 return num_lp_constraints + num_lp_cut_generators +
var.value();
614 for (
int i = 0; i < num_lp_constraints; i++) {
615 for (
const IntegerVariable
var : relaxation.linear_constraints[i].vars) {
616 components.
AddEdge(get_constraint_index(i), get_var_index(
var));
619 for (
int i = 0; i < num_lp_cut_generators; ++i) {
620 for (
const IntegerVariable
var : relaxation.cut_generators[i].vars) {
621 components.
AddEdge(get_cut_generator_index(i), get_var_index(
var));
626 std::vector<int> component_sizes(num_components, 0);
627 const std::vector<int> index_to_component = components.
GetComponentIds();
628 for (
int i = 0; i < num_lp_constraints; i++) {
629 ++component_sizes[index_to_component[get_constraint_index(i)]];
631 for (
int i = 0; i < num_lp_cut_generators; i++) {
632 ++component_sizes[index_to_component[get_cut_generator_index(i)]];
640 auto* mapping = m->GetOrCreate<CpModelMapping>();
642 const IntegerVariable
var =
644 ++component_sizes[index_to_component[get_var_index(
var)]];
648 std::vector<LinearProgrammingConstraint*> lp_constraints(num_components,
650 std::vector<std::vector<LinearConstraint>> component_to_constraints(
652 for (
int i = 0; i < num_lp_constraints; i++) {
653 const int c = index_to_component[get_constraint_index(i)];
654 if (component_sizes[c] <= 1)
continue;
655 component_to_constraints[c].push_back(relaxation.linear_constraints[i]);
656 if (lp_constraints[c] ==
nullptr) {
657 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
660 lp_constraints[c]->AddLinearConstraint(relaxation.linear_constraints[i]);
664 for (
int i = 0; i < num_lp_cut_generators; i++) {
665 const int c = index_to_component[get_cut_generator_index(i)];
666 if (lp_constraints[c] ==
nullptr) {
667 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
669 lp_constraints[c]->AddCutGenerator(std::move(relaxation.cut_generators[i]));
673 std::vector<std::vector<std::pair<IntegerVariable, int64_t>>>
674 component_to_cp_terms(num_components);
675 std::vector<std::pair<IntegerVariable, int64_t>> top_level_cp_terms;
676 int num_components_containing_objective = 0;
681 const IntegerVariable
var =
684 const int c = index_to_component[get_var_index(
var)];
685 if (lp_constraints[c] !=
nullptr) {
686 lp_constraints[c]->SetObjectiveCoefficient(
var, IntegerValue(
coeff));
687 component_to_cp_terms[c].push_back(std::make_pair(
var,
coeff));
690 top_level_cp_terms.push_back(std::make_pair(
var,
coeff));
694 for (
int c = 0; c < num_components; ++c) {
695 if (component_to_cp_terms[c].empty())
continue;
696 const IntegerVariable sub_obj_var =
697 GetOrCreateVariableGreaterOrEqualToSumOf(component_to_cp_terms[c], m);
698 top_level_cp_terms.push_back(std::make_pair(sub_obj_var, 1));
699 lp_constraints[c]->SetMainObjectiveVariable(sub_obj_var);
700 num_components_containing_objective++;
704 const IntegerVariable main_objective_var =
706 ? GetOrCreateVariableGreaterOrEqualToSumOf(top_level_cp_terms, m)
711 for (LinearProgrammingConstraint* lp_constraint : lp_constraints) {
712 if (lp_constraint ==
nullptr)
continue;
713 lp_constraint->RegisterWith(m);
714 VLOG(3) <<
"LP constraint: " << lp_constraint->DimensionString() <<
".";
717 VLOG(3) << top_level_cp_terms.size()
718 <<
" terms in the main objective linear equation ("
719 << num_components_containing_objective <<
" from LP constraints).";
720 return main_objective_var;
738#if !defined(__PORTABLE_PLATFORM__)
741 const std::string& params) {
743 if (!params.empty()) {
744 CHECK(google::protobuf::TextFormat::ParseFromString(params, &
parameters))
771void RegisterVariableBoundsLevelZeroExport(
772 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
774 CHECK(shared_bounds_manager !=
nullptr);
775 int saved_trail_index = 0;
776 auto broadcast_level_zero_bounds =
778 const std::vector<IntegerVariable>& modified_vars)
mutable {
779 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
781 std::vector<int> model_variables;
782 std::vector<int64_t> new_lower_bounds;
783 std::vector<int64_t> new_upper_bounds;
784 absl::flat_hash_set<int> visited_variables;
787 auto* integer_trail =
model->Get<IntegerTrail>();
788 for (
const IntegerVariable&
var : modified_vars) {
790 const int model_var =
791 mapping->GetProtoVariableFromIntegerVariable(positive_var);
792 if (model_var == -1 || visited_variables.contains(model_var)) {
799 visited_variables.insert(model_var);
800 const int64_t new_lb =
801 integer_trail->LevelZeroLowerBound(positive_var).value();
802 const int64_t new_ub =
803 integer_trail->LevelZeroUpperBound(positive_var).value();
806 model_variables.push_back(model_var);
807 new_lower_bounds.push_back(new_lb);
808 new_upper_bounds.push_back(new_ub);
812 auto* trail =
model->Get<Trail>();
813 for (; saved_trail_index < trail->Index(); ++saved_trail_index) {
814 const Literal fixed_literal = (*trail)[saved_trail_index];
815 const int model_var = mapping->GetProtoVariableFromBooleanVariable(
816 fixed_literal.Variable());
817 if (model_var == -1 || visited_variables.contains(model_var)) {
824 visited_variables.insert(model_var);
825 model_variables.push_back(model_var);
826 if (fixed_literal.IsPositive()) {
827 new_lower_bounds.push_back(1);
828 new_upper_bounds.push_back(1);
830 new_lower_bounds.push_back(0);
831 new_upper_bounds.push_back(0);
835 if (!model_variables.empty()) {
836 shared_bounds_manager->ReportPotentialNewBounds(
841 if (!
model->Get<SatParameters>()->interleave_search()) {
842 shared_bounds_manager->Synchronize();
854 const IntegerVariable num_vars =
855 model->GetOrCreate<IntegerTrail>()->NumIntegerVariables();
856 std::vector<IntegerVariable> all_variables;
857 all_variables.reserve(num_vars.value());
858 for (IntegerVariable
var(0);
var < num_vars; ++
var) {
859 all_variables.push_back(
var);
861 broadcast_level_zero_bounds(all_variables);
863 model->GetOrCreate<GenericLiteralWatcher>()
864 ->RegisterLevelZeroModifiedVariablesCallback(broadcast_level_zero_bounds);
870void RegisterVariableBoundsLevelZeroImport(
871 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
873 CHECK(shared_bounds_manager !=
nullptr);
874 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
875 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
876 const int id = shared_bounds_manager->RegisterNewId();
878 const auto& import_level_zero_bounds = [&
model_proto, shared_bounds_manager,
879 model, integer_trail, id, mapping]() {
880 std::vector<int> model_variables;
881 std::vector<int64_t> new_lower_bounds;
882 std::vector<int64_t> new_upper_bounds;
883 shared_bounds_manager->GetChangedBounds(
884 id, &model_variables, &new_lower_bounds, &new_upper_bounds);
885 bool new_bounds_have_been_imported =
false;
886 for (
int i = 0; i < model_variables.size(); ++i) {
887 const int model_var = model_variables[i];
890 if (!mapping->IsInteger(model_var))
continue;
891 const IntegerVariable
var = mapping->Integer(model_var);
892 const IntegerValue new_lb(new_lower_bounds[i]);
893 const IntegerValue new_ub(new_upper_bounds[i]);
894 const IntegerValue old_lb = integer_trail->LowerBound(
var);
895 const IntegerValue old_ub = integer_trail->UpperBound(
var);
896 const bool changed_lb = new_lb > old_lb;
897 const bool changed_ub = new_ub < old_ub;
898 if (!changed_lb && !changed_ub)
continue;
900 new_bounds_have_been_imported =
true;
902 const IntegerVariableProto& var_proto =
904 const std::string& var_name =
905 var_proto.
name().empty()
906 ? absl::StrCat(
"anonymous_var(", model_var,
")")
908 LOG(
INFO) <<
" '" <<
model->Name() <<
"' imports new bounds for "
909 << var_name <<
": from [" << old_lb <<
", " << old_ub
910 <<
"] to [" << new_lb <<
", " << new_ub <<
"]";
924 if (new_bounds_have_been_imported &&
925 !
model->GetOrCreate<SatSolver>()->FinishPropagation()) {
930 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
931 import_level_zero_bounds);
936void RegisterObjectiveBestBoundExport(
937 IntegerVariable objective_var,
938 SharedResponseManager* shared_response_manager, Model*
model) {
939 auto* integer_trail =
model->Get<IntegerTrail>();
940 const auto broadcast_objective_lower_bound =
941 [objective_var, integer_trail, shared_response_manager,
942 model](
const std::vector<IntegerVariable>& unused) {
943 shared_response_manager->UpdateInnerObjectiveBounds(
944 model->Name(), integer_trail->LevelZeroLowerBound(objective_var),
945 integer_trail->LevelZeroUpperBound(objective_var));
947 if (!
model->Get<SatParameters>()->interleave_search()) {
948 shared_response_manager->Synchronize();
951 model->GetOrCreate<GenericLiteralWatcher>()
952 ->RegisterLevelZeroModifiedVariablesCallback(
953 broadcast_objective_lower_bound);
959void RegisterObjectiveBoundsImport(
960 SharedResponseManager* shared_response_manager, Model*
model) {
961 auto* solver =
model->GetOrCreate<SatSolver>();
962 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
963 auto* objective =
model->GetOrCreate<ObjectiveDefinition>();
965 const auto import_objective_bounds = [
name, solver, integer_trail, objective,
966 shared_response_manager]() {
967 if (solver->AssumptionLevel() != 0)
return true;
968 bool propagate =
false;
970 const IntegerValue external_lb =
971 shared_response_manager->SynchronizedInnerObjectiveLowerBound();
972 const IntegerValue current_lb =
973 integer_trail->LowerBound(objective->objective_var);
974 if (external_lb > current_lb) {
976 objective->objective_var, external_lb),
983 const IntegerValue external_ub =
984 shared_response_manager->SynchronizedInnerObjectiveUpperBound();
985 const IntegerValue current_ub =
986 integer_trail->UpperBound(objective->objective_var);
987 if (external_ub < current_ub) {
989 objective->objective_var, external_ub),
996 if (!propagate)
return true;
998 VLOG(3) <<
"'" <<
name <<
"' imports objective bounds: external ["
999 << objective->ScaleIntegerObjective(external_lb) <<
", "
1000 << objective->ScaleIntegerObjective(external_ub) <<
"], current ["
1001 << objective->ScaleIntegerObjective(current_lb) <<
", "
1002 << objective->ScaleIntegerObjective(current_ub) <<
"]";
1004 return solver->FinishPropagation();
1007 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
1008 import_objective_bounds);
1012 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1013 CHECK(shared_response_manager !=
nullptr);
1014 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1017 const auto unsat = [shared_response_manager, sat_solver,
model] {
1018 sat_solver->NotifyThatModelIsUnsat();
1019 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1020 absl::StrCat(
model->Name(),
" [loading]"));
1024 model->GetOrCreate<IntegerEncoder>()->DisableImplicationBetweenLiteral();
1026 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1027 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1028 const bool view_all_booleans_as_integers =
1048 if (sat_solver->IsModelUnsat())
return unsat();
1054 std::set<std::string> unsupported_types;
1055 int num_ignored_constraints = 0;
1057 if (mapping->ConstraintIsAlreadyLoaded(&
ct)) {
1058 ++num_ignored_constraints;
1073 if (sat_solver->FinishPropagation()) {
1074 Trail* trail =
model->GetOrCreate<Trail>();
1075 const int old_num_fixed = trail->Index();
1076 if (trail->Index() > old_num_fixed) {
1077 VLOG(3) <<
"Constraint fixed " << trail->Index() - old_num_fixed
1082 if (sat_solver->IsModelUnsat()) {
1083 VLOG(2) <<
"UNSAT during extraction (after adding '"
1089 if (num_ignored_constraints > 0) {
1090 VLOG(3) << num_ignored_constraints <<
" constraints were skipped.";
1092 if (!unsupported_types.empty()) {
1093 VLOG(1) <<
"There is unsupported constraints types in this model: ";
1094 for (
const std::string& type : unsupported_types) {
1095 VLOG(1) <<
" - " << type;
1100 model->GetOrCreate<IntegerEncoder>()
1101 ->AddAllImplicationsBetweenAssociatedLiterals();
1102 if (!sat_solver->FinishPropagation())
return unsat();
1108 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1109 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1113 const LinearRelaxation relaxation =
1115 const int num_lp_constraints = relaxation.linear_constraints.size();
1116 if (num_lp_constraints == 0)
return;
1117 auto* feasibility_pump =
model->GetOrCreate<FeasibilityPump>();
1118 for (
int i = 0; i < num_lp_constraints; i++) {
1119 feasibility_pump->AddLinearConstraint(relaxation.linear_constraints[i]);
1124 const IntegerVariable
var =
1127 feasibility_pump->SetObjectiveCoefficient(
var, IntegerValue(
coeff));
1137 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1142 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1143 const auto unsat = [shared_response_manager, sat_solver,
model] {
1144 sat_solver->NotifyThatModelIsUnsat();
1145 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1146 absl::StrCat(
model->Name(),
" [loading]"));
1149 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1150 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1156 if (
model->Mutable<PrecedencesPropagator>() !=
nullptr &&
1158 model->Mutable<PrecedencesPropagator>()
1159 ->AddGreaterThanAtLeastOneOfConstraints(
model);
1160 if (!sat_solver->FinishPropagation())
return unsat();
1167 Prober* prober =
model->GetOrCreate<Prober>();
1168 prober->ProbeBooleanVariables(1.0);
1169 if (
model->GetOrCreate<SatSolver>()->IsModelUnsat()) {
1172 if (!
model->GetOrCreate<BinaryImplicationGraph>()
1173 ->ComputeTransitiveReduction()) {
1186 std::vector<std::pair<IntegerVariable, int64_t>> terms;
1187 terms.reserve(obj.vars_size());
1188 for (
int i = 0; i < obj.vars_size(); ++i) {
1190 std::make_pair(mapping->Integer(obj.vars(i)), obj.coeffs(i)));
1193 objective_var = GetOrCreateVariableWithTightBound(terms,
model);
1195 objective_var = GetOrCreateVariableGreaterOrEqualToSumOf(terms,
model);
1203 auto* objective_definition =
model->GetOrCreate<ObjectiveDefinition>();
1205 objective_definition->scaling_factor = objective_proto.scaling_factor();
1206 if (objective_definition->scaling_factor == 0.0) {
1207 objective_definition->scaling_factor = 1.0;
1209 objective_definition->offset = objective_proto.offset();
1210 objective_definition->objective_var = objective_var;
1212 const int size = objective_proto.vars_size();
1213 objective_definition->vars.resize(size);
1214 objective_definition->coeffs.resize(size);
1215 for (
int i = 0; i < objective_proto.vars_size(); ++i) {
1218 objective_definition->vars[i] = mapping->Integer(objective_proto.vars(i));
1219 objective_definition->coeffs[i] = IntegerValue(objective_proto.coeffs(i));
1222 const int ref = objective_proto.vars(i);
1223 if (mapping->IsInteger(ref)) {
1224 const IntegerVariable
var = mapping->Integer(objective_proto.vars(i));
1225 objective_definition->objective_impacting_variables.insert(
1231 model->TakeOwnership(
1232 new LevelZeroEquality(objective_var, objective_definition->vars,
1233 objective_definition->coeffs,
model));
1239 const Domain automatic_domain =
1240 model->GetOrCreate<IntegerTrail>()->InitialVariableDomain(
1244 VLOG(3) <<
"Automatic internal objective domain: " << automatic_domain;
1245 VLOG(3) <<
"User specified internal objective domain: " << user_domain;
1247 const bool ok =
model->GetOrCreate<IntegerTrail>()->UpdateInitialDomain(
1248 objective_var, user_domain);
1250 VLOG(2) <<
"UNSAT due to the objective domain.";
1261 if (!automatic_domain.IsIncludedIn(user_domain)) {
1262 std::vector<IntegerVariable> vars;
1263 std::vector<int64_t> coeffs;
1265 for (
int i = 0; i < obj.vars_size(); ++i) {
1266 vars.push_back(mapping->Integer(obj.vars(i)));
1267 coeffs.push_back(obj.coeffs(i));
1269 vars.push_back(objective_var);
1270 coeffs.push_back(-1);
1278 "Initial num_bool: ", sat_solver->NumVariables());
1279 if (!sat_solver->FinishPropagation())
return unsat();
1283 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1284 shared_response_manager->UpdateInnerObjectiveBounds(
1285 absl::StrCat(
model->Name(),
" initial_propagation"),
1286 integer_trail->LowerBound(objective_var),
1287 integer_trail->UpperBound(objective_var));
1290 RegisterObjectiveBestBoundExport(objective_var, shared_response_manager,
1296 if (
model->GetOrCreate<SatParameters>()->share_objective_bounds()) {
1297 RegisterObjectiveBoundsImport(shared_response_manager,
model);
1303 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1304 auto* lp_dispatcher =
model->GetOrCreate<LinearProgrammingDispatcher>();
1305 auto* lp_vars =
model->GetOrCreate<LPVariables>();
1306 IntegerVariable size = integer_trail->NumIntegerVariables();
1307 for (IntegerVariable positive_var(0); positive_var < size;
1308 positive_var += 2) {
1310 lp_var.positive_var = positive_var;
1312 mapping->GetProtoVariableFromIntegerVariable(positive_var);
1315 if (lp_var.model_var >= 0) {
1316 lp_vars->vars.push_back(lp_var);
1317 lp_vars->model_vars_size =
1318 std::max(lp_vars->model_vars_size, lp_var.model_var + 1);
1323 auto* search_heuristics =
model->GetOrCreate<SearchHeuristics>();
1327 search_heuristics->fixed_search =
1329 search_heuristics->fixed_search,
model);
1333 std::vector<BooleanOrIntegerVariable> vars;
1334 std::vector<IntegerValue> values;
1338 BooleanOrIntegerVariable
var;
1339 if (mapping->IsBoolean(ref)) {
1340 var.bool_var = mapping->Literal(ref).Variable();
1342 var.int_var = mapping->Integer(ref);
1344 vars.push_back(
var);
1353 const std::string solution_info =
model->Name();
1355 shared_response_manager]() {
1358 response.set_solution_info(solution_info);
1362 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1363 CoreBasedOptimizer* core =
1364 new CoreBasedOptimizer(objective_var, objective.vars, objective.coeffs,
1365 solution_observer,
model);
1366 model->Register<CoreBasedOptimizer>(core);
1367 model->TakeOwnership(core);
1378 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1379 if (shared_response_manager->ProblemIsSolved())
return;
1381 const std::string& solution_info =
model->Name();
1383 &shared_response_manager]() {
1386 response.set_solution_info(solution_info);
1393 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1395 const SatParameters&
parameters = *
model->GetOrCreate<SatParameters>();
1397 std::vector<BooleanVariable> bool_vars;
1398 std::vector<IntegerVariable> int_vars;
1399 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1400 absl::flat_hash_set<BooleanVariable> visited;
1402 if (mapping.IsBoolean(v)) {
1403 const BooleanVariable bool_var = mapping.Literal(v).Variable();
1404 if (!visited.contains(bool_var)) {
1405 visited.insert(bool_var);
1406 bool_vars.push_back(bool_var);
1409 IntegerVariable
var = mapping.Integer(v);
1410 if (integer_trail->IsFixed(
var))
continue;
1411 int_vars.push_back(
var);
1420 solution_observer();
1425 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1429 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1434 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1435 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1437 std::vector<int> core_in_proto_format;
1438 for (
const Literal l : core) {
1439 core_in_proto_format.push_back(
1440 mapping.GetProtoVariableFromBooleanVariable(l.Variable()));
1441 if (!l.IsPositive()) {
1442 core_in_proto_format.back() =
NegatedRef(core_in_proto_format.back());
1445 shared_response_manager->AddUnsatCore(core_in_proto_format);
1449 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1450 const IntegerVariable objective_var = objective.objective_var;
1454 auto* search =
model->GetOrCreate<LbTreeSearch>();
1455 status = search->Search(solution_observer);
1461 objective, solution_observer,
model);
1463 status =
model->Mutable<CoreBasedOptimizer>()->Optimize();
1470 solution_observer,
model);
1473 objective_var, solution_observer,
model);
1481 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1488 shared_response_manager->SetStatsFromModel(
model);
1496 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1497 if (shared_response_manager->ProblemIsSolved())
return;
1510 const SatParameters saved_params = *
parameters;
1519 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1523 const std::string& solution_info =
model->Name();
1527 response.set_solution_info(absl::StrCat(solution_info,
" [hint]"));
1536 const IntegerVariable objective_var =
1537 model->GetOrCreate<ObjectiveDefinition>()->objective_var;
1538 model->GetOrCreate<SatSolver>()->Backtrack(0);
1539 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1540 if (!integer_trail->Enqueue(
1543 shared_response_manager->GetInnerObjectiveUpperBound()),
1545 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1546 absl::StrCat(solution_info,
" [hint]"));
1547 shared_response_manager->SetStatsFromModel(
model);
1557 !
model->GetOrCreate<TimeLimit>()->LimitReached() &&
1559 LOG(
FATAL) <<
"QuickSolveWithHint() didn't find a feasible solution. "
1567void MinimizeL1DistanceWithHint(
const CpModelProto&
model_proto, Model*
model) {
1571 local_model.Register<ModelSharedTimeLimit>(
1572 model->GetOrCreate<ModelSharedTimeLimit>());
1577 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1578 if (shared_response_manager->ProblemIsSolved())
return;
1580 auto*
parameters = local_model.GetOrCreate<SatParameters>();
1587 const SatParameters saved_params = *
model->GetOrCreate<SatParameters>();
1602 const int new_var_index = updated_model_proto.variables_size();
1603 IntegerVariableProto* var_proto = updated_model_proto.add_variables();
1605 const int64_t max_domain =
1609 var_proto->add_domain(min_domain);
1610 var_proto->add_domain(max_domain);
1613 ConstraintProto*
const linear_constraint_proto =
1614 updated_model_proto.add_constraints();
1615 LinearConstraintProto* linear = linear_constraint_proto->mutable_linear();
1616 linear->add_vars(new_var_index);
1617 linear->add_coeffs(1);
1618 linear->add_vars(
var);
1619 linear->add_coeffs(-1);
1620 linear->add_domain(-
value);
1621 linear->add_domain(-
value);
1624 const int abs_var_index = updated_model_proto.variables_size();
1625 IntegerVariableProto* abs_var_proto = updated_model_proto.add_variables();
1626 const int64_t abs_min_domain = 0;
1627 const int64_t abs_max_domain =
1628 std::max(std::abs(min_domain), std::abs(max_domain));
1629 abs_var_proto->add_domain(abs_min_domain);
1630 abs_var_proto->add_domain(abs_max_domain);
1631 auto* abs_ct = updated_model_proto.add_constraints()->mutable_lin_max();
1632 abs_ct->mutable_target()->add_vars(abs_var_index);
1633 abs_ct->mutable_target()->add_coeffs(1);
1634 LinearExpressionProto* left = abs_ct->add_exprs();
1635 left->add_vars(new_var_index);
1636 left->add_coeffs(1);
1637 LinearExpressionProto* right = abs_ct->add_exprs();
1638 right->add_vars(new_var_index);
1639 right->add_coeffs(-1);
1641 updated_model_proto.mutable_objective()->add_vars(abs_var_index);
1642 updated_model_proto.mutable_objective()->add_coeffs(1);
1645 auto* local_response_manager =
1646 local_model.GetOrCreate<SharedResponseManager>();
1647 local_response_manager->InitializeObjective(updated_model_proto);
1650 LoadCpModel(updated_model_proto, &local_model);
1653 const auto& mapping = *local_model.GetOrCreate<CpModelMapping>();
1655 mapping.Literals(updated_model_proto.assumptions()), &local_model);
1657 const std::string& solution_info =
model->Name();
1662 CpSolverResponse updated_response;
1663 FillSolutionInResponse(updated_model_proto, local_model,
1665 LOG(
INFO) <<
"Found solution with repaired hint penalty = "
1669 response.set_solution_info(absl::StrCat(solution_info,
" [repaired]"));
1678void PostsolveResponseWithFullSolver(
int num_variables_in_original_model,
1679 CpModelProto mapping_proto,
1680 const std::vector<int>& postsolve_mapping,
1681 std::vector<int64_t>* solution) {
1686 for (
int i = 0; i < solution->size(); ++i) {
1687 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1688 var_proto->clear_domain();
1689 var_proto->add_domain((*solution)[i]);
1690 var_proto->add_domain((*solution)[i]);
1696 Model postsolve_model;
1699 SatParameters& params = *postsolve_model.GetOrCreate<SatParameters>();
1700 params.set_linearization_level(0);
1701 params.set_cp_model_probing_level(0);
1704 LoadCpModel(mapping_proto, &postsolve_model);
1705 SolveLoadedCpModel(mapping_proto, &postsolve_model);
1706 const CpSolverResponse postsolve_response =
1707 postsolve_model.GetOrCreate<SharedResponseManager>()->GetResponse();
1713 CHECK_LE(num_variables_in_original_model,
1714 postsolve_response.solution().size());
1716 postsolve_response.solution().begin(),
1717 postsolve_response.solution().begin() + num_variables_in_original_model);
1720void PostsolveResponseWrapper(
const SatParameters& params,
1721 int num_variable_in_original_model,
1722 const CpModelProto& mapping_proto,
1723 const std::vector<int>& postsolve_mapping,
1724 std::vector<int64_t>* solution) {
1725 if (params.debug_postsolve_with_full_solver()) {
1726 PostsolveResponseWithFullSolver(num_variable_in_original_model,
1727 mapping_proto, postsolve_mapping, solution);
1730 postsolve_mapping, solution);
1735CpSolverResponse SolvePureSatModel(
const CpModelProto&
model_proto,
1737 SolverLogger* logger) {
1738 std::unique_ptr<SatSolver> solver(
new SatSolver());
1741 model->GetOrCreate<TimeLimit>()->ResetLimitFromParameters(
parameters);
1744 std::unique_ptr<DratProofHandler> drat_proof_handler;
1745#if !defined(__PORTABLE_PLATFORM__)
1746 if (!absl::GetFlag(FLAGS_drat_output).empty() ||
1747 absl::GetFlag(FLAGS_drat_check)) {
1748 if (!absl::GetFlag(FLAGS_drat_output).empty()) {
1752 drat_proof_handler = absl::make_unique<DratProofHandler>(
1753 false, output, absl::GetFlag(FLAGS_drat_check));
1755 drat_proof_handler = absl::make_unique<DratProofHandler>();
1757 solver->SetDratProofHandler(drat_proof_handler.get());
1761 auto get_literal = [](
int ref) {
1762 if (ref >= 0)
return Literal(BooleanVariable(ref),
true);
1763 return Literal(BooleanVariable(
NegatedRef(ref)),
false);
1766 std::vector<Literal> temp;
1768 solver->SetNumVariables(num_variables);
1769 if (drat_proof_handler !=
nullptr) {
1770 drat_proof_handler->SetNumVariables(num_variables);
1774 for (
int ref = 0; ref < num_variables; ++ref) {
1776 if (domain.IsFixed()) {
1777 const Literal ref_literal =
1778 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
1779 drat_proof_handler->AddProblemClause({ref_literal});
1783 switch (
ct.constraint_case()) {
1784 case ConstraintProto::ConstraintCase::kBoolAnd: {
1785 if (
ct.enforcement_literal_size() == 0) {
1786 for (
const int ref :
ct.bool_and().literals()) {
1787 drat_proof_handler->AddProblemClause({get_literal(ref)});
1791 const Literal not_a =
1792 get_literal(
ct.enforcement_literal(0)).Negated();
1793 for (
const int ref :
ct.bool_and().literals()) {
1794 drat_proof_handler->AddProblemClause({not_a, get_literal(ref)});
1799 case ConstraintProto::ConstraintCase::kBoolOr:
1801 for (
const int ref :
ct.bool_or().literals()) {
1802 temp.push_back(get_literal(ref));
1804 for (
const int ref :
ct.enforcement_literal()) {
1805 temp.push_back(get_literal(ref).Negated());
1807 drat_proof_handler->AddProblemClause(temp);
1816 switch (
ct.constraint_case()) {
1817 case ConstraintProto::ConstraintCase::kBoolAnd: {
1818 if (
ct.enforcement_literal_size() == 0) {
1819 for (
const int ref :
ct.bool_and().literals()) {
1820 const Literal
b = get_literal(ref);
1821 solver->AddUnitClause(
b);
1825 const Literal not_a =
1826 get_literal(
ct.enforcement_literal(0)).Negated();
1827 for (
const int ref :
ct.bool_and().literals()) {
1828 const Literal
b = get_literal(ref);
1829 solver->AddProblemClause({not_a,
b});
1834 case ConstraintProto::ConstraintCase::kBoolOr:
1836 for (
const int ref :
ct.bool_or().literals()) {
1837 temp.push_back(get_literal(ref));
1839 for (
const int ref :
ct.enforcement_literal()) {
1840 temp.push_back(get_literal(ref).Negated());
1842 solver->AddProblemClause(temp);
1850 for (
int ref = 0; ref < num_variables; ++ref) {
1852 if (domain.Min() == domain.Max()) {
1853 const Literal ref_literal =
1854 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
1855 solver->AddUnitClause(ref_literal);
1862 std::vector<bool> solution;
1864 &solution, drat_proof_handler.get(), logger);
1867 for (
int ref = 0; ref < num_variables; ++ref) {
1868 response.add_solution(solution[ref]);
1872 status = solver->SolveWithTimeLimit(
model->GetOrCreate<TimeLimit>());
1875 for (
int ref = 0; ref < num_variables; ++ref) {
1877 solver->Assignment().LiteralIsTrue(get_literal(ref)) ? 1 : 0);
1884 model->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
1885 solver->model()->GetOrCreate<TimeLimit>()->GetElapsedDeterministicTime());
1906 response.set_num_booleans(solver->NumVariables());
1907 response.set_num_branches(solver->num_branches());
1908 response.set_num_conflicts(solver->num_failures());
1909 response.set_num_binary_propagations(solver->num_propagations());
1910 response.set_num_integer_propagations(0);
1913 model->Get<TimeLimit>()->GetElapsedDeterministicTime());
1919 absl::GetFlag(FLAGS_max_drat_time_in_seconds));
1920 switch (drat_status) {
1922 LOG(
INFO) <<
"DRAT status: UNKNOWN";
1925 LOG(
INFO) <<
"DRAT status: VALID";
1928 LOG(ERROR) <<
"DRAT status: INVALID";
1934 LOG(
INFO) <<
"DRAT wall time: " << drat_timer.
Get();
1935 }
else if (drat_proof_handler !=
nullptr) {
1938 LOG(
INFO) <<
"DRAT status: NA";
1939 LOG(
INFO) <<
"DRAT wall time: NA";
1940 LOG(
INFO) <<
"DRAT user time: NA";
1945#if !defined(__PORTABLE_PLATFORM__)
1948struct SharedClasses {
1959 bool SearchIsDone() {
1960 if (
response->ProblemIsSolved())
return true;
1967class FullProblemSolver :
public SubSolver {
1969 FullProblemSolver(
const std::string&
name,
1970 const SatParameters& local_parameters,
bool split_in_chunks,
1971 SharedClasses* shared)
1974 split_in_chunks_(split_in_chunks),
1975 local_model_(
absl::make_unique<Model>(
name)) {
1977 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
1978 shared_->time_limit->UpdateLocalLimit(
1979 local_model_->GetOrCreate<TimeLimit>());
1981 if (shared->response !=
nullptr) {
1982 local_model_->Register<SharedResponseManager>(shared->response);
1985 if (shared->relaxation_solutions !=
nullptr) {
1986 local_model_->Register<SharedRelaxationSolutionRepository>(
1987 shared->relaxation_solutions);
1990 if (shared->lp_solutions !=
nullptr) {
1991 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
1994 if (shared->incomplete_solutions !=
nullptr) {
1995 local_model_->Register<SharedIncompleteSolutionManager>(
1996 shared->incomplete_solutions);
2000 bool TaskIsAvailable()
override {
2001 if (shared_->SearchIsDone())
return false;
2003 absl::MutexLock mutex_lock(&mutex_);
2004 return previous_task_is_completed_;
2007 std::function<void()> GenerateTask(int64_t task_id)
override {
2009 absl::MutexLock mutex_lock(&mutex_);
2010 previous_task_is_completed_ =
false;
2013 if (solving_first_chunk_) {
2014 LoadCpModel(*shared_->model_proto, local_model_.get());
2020 if (shared_->bounds !=
nullptr) {
2021 RegisterVariableBoundsLevelZeroExport(
2022 *shared_->model_proto, shared_->bounds, local_model_.get());
2023 RegisterVariableBoundsLevelZeroImport(
2024 *shared_->model_proto, shared_->bounds, local_model_.get());
2027 if (local_model_->GetOrCreate<SatParameters>()->repair_hint()) {
2028 MinimizeL1DistanceWithHint(*shared_->model_proto, local_model_.get());
2030 QuickSolveWithHint(*shared_->model_proto, local_model_.get());
2034 solving_first_chunk_ =
false;
2036 if (split_in_chunks_) {
2038 absl::MutexLock mutex_lock(&mutex_);
2039 previous_task_is_completed_ =
true;
2044 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2045 if (split_in_chunks_) {
2048 auto* params = local_model_->GetOrCreate<SatParameters>();
2049 params->set_max_deterministic_time(1);
2050 time_limit->ResetLimitFromParameters(*params);
2051 shared_->time_limit->UpdateLocalLimit(
time_limit);
2054 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2055 SolveLoadedCpModel(*shared_->model_proto, local_model_.get());
2057 absl::MutexLock mutex_lock(&mutex_);
2058 deterministic_time_since_last_synchronize_ +=
2059 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2063 if (shared_->SearchIsDone()) {
2064 shared_->time_limit->Stop();
2069 if (split_in_chunks_) {
2070 absl::MutexLock mutex_lock(&mutex_);
2071 previous_task_is_completed_ =
true;
2079 local_model_.reset();
2086 void Synchronize()
override {
2087 absl::MutexLock mutex_lock(&mutex_);
2088 deterministic_time_ += deterministic_time_since_last_synchronize_;
2089 shared_->time_limit->AdvanceDeterministicTime(
2090 deterministic_time_since_last_synchronize_);
2091 deterministic_time_since_last_synchronize_ = 0.0;
2094 std::string StatisticsString()
const override {
2098 if (local_model_ ==
nullptr)
return std::string();
2101 *local_model_->GetOrCreate<LinearProgrammingConstraintCollection>();
2102 std::string lp_stats;
2104 local_model_->GetOrCreate<SatParameters>()->linearization_level() >=
2106 for (
const auto* lp : lps) {
2107 const std::string raw_statistics = lp->Statistics();
2108 const std::vector<absl::string_view> lines =
2109 absl::StrSplit(raw_statistics,
'\n', absl::SkipEmpty());
2110 for (
const absl::string_view& line : lines) {
2111 absl::StrAppend(&lp_stats,
" ", line,
"\n");
2119 SharedClasses* shared_;
2120 const bool split_in_chunks_;
2121 std::unique_ptr<Model> local_model_;
2125 bool solving_first_chunk_ =
true;
2128 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2130 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2133class FeasibilityPumpSolver :
public SubSolver {
2135 FeasibilityPumpSolver(
const SatParameters& local_parameters,
2136 SharedClasses* shared)
2137 : SubSolver(
"feasibility_pump"),
2139 local_model_(
absl::make_unique<Model>(name_)) {
2141 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
2142 shared_->time_limit->UpdateLocalLimit(
2143 local_model_->GetOrCreate<TimeLimit>());
2145 if (shared->response !=
nullptr) {
2146 local_model_->Register<SharedResponseManager>(shared->response);
2149 if (shared->relaxation_solutions !=
nullptr) {
2150 local_model_->Register<SharedRelaxationSolutionRepository>(
2151 shared->relaxation_solutions);
2154 if (shared->lp_solutions !=
nullptr) {
2155 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
2158 if (shared->incomplete_solutions !=
nullptr) {
2159 local_model_->Register<SharedIncompleteSolutionManager>(
2160 shared->incomplete_solutions);
2164 if (shared_->bounds !=
nullptr) {
2165 RegisterVariableBoundsLevelZeroImport(
2166 *shared_->model_proto, shared_->bounds, local_model_.get());
2170 bool TaskIsAvailable()
override {
2171 if (shared_->SearchIsDone())
return false;
2172 absl::MutexLock mutex_lock(&mutex_);
2173 return previous_task_is_completed_;
2176 std::function<void()> GenerateTask(int64_t task_id)
override {
2179 absl::MutexLock mutex_lock(&mutex_);
2180 if (!previous_task_is_completed_)
return;
2181 previous_task_is_completed_ =
false;
2184 absl::MutexLock mutex_lock(&mutex_);
2185 if (solving_first_chunk_) {
2186 LoadFeasibilityPump(*shared_->model_proto, local_model_.get());
2189 if (local_model_->Get<FeasibilityPump>() ==
nullptr)
return;
2190 solving_first_chunk_ =
false;
2192 previous_task_is_completed_ =
true;
2197 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2198 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2199 auto* feasibility_pump = local_model_->Mutable<FeasibilityPump>();
2200 if (!feasibility_pump->Solve()) {
2201 shared_->response->NotifyThatImprovingProblemIsInfeasible(name_);
2205 absl::MutexLock mutex_lock(&mutex_);
2206 deterministic_time_since_last_synchronize_ +=
2207 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2211 if (shared_->SearchIsDone()) {
2212 shared_->time_limit->Stop();
2216 absl::MutexLock mutex_lock(&mutex_);
2217 previous_task_is_completed_ =
true;
2221 void Synchronize()
override {
2222 absl::MutexLock mutex_lock(&mutex_);
2223 deterministic_time_ += deterministic_time_since_last_synchronize_;
2224 shared_->time_limit->AdvanceDeterministicTime(
2225 deterministic_time_since_last_synchronize_);
2226 deterministic_time_since_last_synchronize_ = 0.0;
2232 SharedClasses* shared_;
2233 std::unique_ptr<Model> local_model_;
2239 bool solving_first_chunk_ ABSL_GUARDED_BY(mutex_) =
true;
2241 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2243 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2247class LnsSolver :
public SubSolver {
2249 LnsSolver(std::unique_ptr<NeighborhoodGenerator> generator,
2251 NeighborhoodGeneratorHelper* helper, SharedClasses* shared)
2252 : SubSolver(generator->
name()),
2253 generator_(
std::move(generator)),
2258 bool TaskIsAvailable()
override {
2259 if (shared_->SearchIsDone())
return false;
2260 return generator_->ReadyToGenerate();
2263 std::function<void()> GenerateTask(int64_t task_id)
override {
2264 return [task_id,
this]() {
2265 if (shared_->SearchIsDone())
return;
2270 const int32_t low =
static_cast<int32_t
>(task_id);
2271 const int32_t high =
static_cast<int32_t
>(task_id >> 32);
2272 std::seed_seq seed{low, high, parameters_.random_seed()};
2275 NeighborhoodGenerator::SolveData data;
2276 data.difficulty = generator_->difficulty();
2277 data.deterministic_limit = generator_->deterministic_limit();
2280 CpSolverResponse base_response;
2282 const SharedSolutionRepository<int64_t>& repo =
2283 shared_->response->SolutionsRepository();
2284 if (repo.NumSolutions() > 0) {
2286 const SharedSolutionRepository<int64_t>::Solution solution =
2287 repo.GetRandomBiasedSolution(random);
2288 for (
const int64_t
value : solution.variable_values) {
2289 base_response.add_solution(
value);
2294 data.initial_best_objective = repo.GetSolution(0).rank;
2295 data.base_objective = solution.rank;
2304 data.initial_best_objective =
2305 shared_->response->GetInnerObjectiveUpperBound();
2306 data.base_objective = data.initial_best_objective;
2310 Neighborhood neighborhood =
2311 generator_->Generate(base_response, data.difficulty, random);
2313 if (!neighborhood.is_generated)
return;
2315 data.neighborhood_id = neighborhood.id;
2317 const int64_t num_calls =
std::max(int64_t{1}, generator_->num_calls());
2318 const double fully_solved_proportion =
2319 static_cast<double>(generator_->num_fully_solved_calls()) /
2320 static_cast<double>(num_calls);
2321 std::string source_info =
name();
2322 if (!neighborhood.source_info.empty()) {
2323 absl::StrAppend(&source_info,
"_", neighborhood.source_info);
2325 const std::string solution_info = absl::StrFormat(
2326 "%s(d=%0.2f s=%i t=%0.2f p=%0.2f)", source_info, data.difficulty,
2327 task_id, data.deterministic_limit, fully_solved_proportion);
2329 SatParameters local_params(parameters_);
2330 local_params.set_max_deterministic_time(data.deterministic_limit);
2331 local_params.set_stop_after_first_solution(
false);
2332 local_params.set_log_search_progress(
false);
2333 local_params.set_cp_model_probing_level(0);
2334 local_params.set_symmetry_level(0);
2335 local_params.set_solution_pool_size(0);
2337 Model local_model(solution_info);
2338 *(local_model.GetOrCreate<SatParameters>()) = local_params;
2339 TimeLimit* local_time_limit = local_model.GetOrCreate<TimeLimit>();
2340 local_time_limit->ResetLimitFromParameters(local_params);
2341 shared_->time_limit->UpdateLocalLimit(local_time_limit);
2344 CpModelProto lns_fragment;
2345 CpModelProto mapping_proto;
2346 auto context = absl::make_unique<PresolveContext>(
2347 &local_model, &lns_fragment, &mapping_proto);
2349 *lns_fragment.mutable_variables() = neighborhood.delta.variables();
2351 ModelCopy copier(
context.get());
2354 if (!copier.ImportAndSimplifyConstraints(
2355 helper_->ModelProto(), neighborhood.constraints_to_ignore)) {
2360 if (!neighborhood.delta.constraints().empty() &&
2361 !copier.ImportAndSimplifyConstraints(neighborhood.delta, {})) {
2368 helper_->ModelProto(),
context.get());
2369 lns_fragment.set_name(absl::StrCat(
"lns_", task_id));
2372 if (neighborhood.delta.has_solution_hint()) {
2373 *lns_fragment.mutable_solution_hint() =
2374 neighborhood.delta.solution_hint();
2377 CpModelProto debug_copy;
2378 if (absl::GetFlag(FLAGS_cp_model_dump_problematic_lns)) {
2381 debug_copy = lns_fragment;
2384#if !defined(__PORTABLE_PLATFORM__)
2387 if (absl::GetFlag(FLAGS_cp_model_dump_lns)) {
2389 const std::string lns_name =
2390 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2391 lns_fragment.name(),
".pb.txt");
2392 LOG(
INFO) <<
"Dumping LNS model to '" << lns_name <<
"'.";
2396 std::vector<int> postsolve_mapping;
2402 neighborhood.delta.Clear();
2407 auto* local_response_manager =
2408 local_model.GetOrCreate<SharedResponseManager>();
2409 local_response_manager->InitializeObjective(lns_fragment);
2412 LoadCpModel(lns_fragment, &local_model);
2413 QuickSolveWithHint(lns_fragment, &local_model);
2414 SolveLoadedCpModel(lns_fragment, &local_model);
2416 local_response_manager->MutableResponse()->set_status(presolve_status);
2418 CpSolverResponse local_response = local_response_manager->GetResponse();
2422 if (local_params.cp_model_presolve() &&
2425 std::vector<int64_t> solution(local_response.solution().begin(),
2426 local_response.solution().end());
2427 PostsolveResponseWrapper(local_params,
2428 helper_->ModelProto().variables_size(),
2429 mapping_proto, postsolve_mapping, &solution);
2430 local_response.mutable_solution()->Assign(solution.begin(),
2434 data.status = local_response.status();
2435 data.deterministic_time = local_time_limit->GetElapsedDeterministicTime();
2437 bool new_solution =
false;
2438 bool display_lns_info =
false;
2439 if (generator_->IsRelaxationGenerator()) {
2440 bool has_feasible_solution =
false;
2443 has_feasible_solution =
true;
2447 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2448 local_response.solution_info());
2451 if (shared_->model_proto->has_objective()) {
2454 const IntegerValue current_obj_lb =
2455 shared_->response->GetInnerObjectiveLowerBound();
2457 const IntegerValue local_obj_lb =
2458 local_response_manager->GetInnerObjectiveLowerBound();
2461 lns_fragment.objective(), local_obj_lb.value());
2464 const IntegerValue new_inner_obj_lb = IntegerValue(
2466 scaled_local_obj_bound) -
2468 data.new_objective_bound = new_inner_obj_lb;
2469 data.initial_best_objective_bound = current_obj_lb;
2470 if (new_inner_obj_lb > current_obj_lb) {
2471 shared_->response->UpdateInnerObjectiveBounds(
2478 if (has_feasible_solution) {
2480 *shared_->model_proto,
2481 std::vector<int64_t>(local_response.solution().begin(),
2482 local_response.solution().end()))) {
2483 shared_->response->NewSolution(local_response,
2488 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2489 local_response.solution_info());
2490 shared_->time_limit->Stop();
2493 shared_->relaxation_solutions->NewRelaxationSolution(local_response);
2496 const std::vector<int64_t> solution(local_response.solution().begin(),
2497 local_response.solution().end());
2499 if (!solution.empty()) {
2505 const bool feasible =
2508 if (absl::GetFlag(FLAGS_cp_model_dump_problematic_lns)) {
2509 const std::string
name =
2510 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2511 debug_copy.name(),
".pb.txt");
2512 LOG(
INFO) <<
"Dumping problematic LNS model to '" <<
name <<
"'.";
2515 LOG(
FATAL) <<
"Infeasible LNS solution! " << solution_info
2516 <<
" solved with params "
2517 << local_params.ShortDebugString();
2533 !shared_->model_proto->has_symmetry() && !solution.empty() &&
2534 neighborhood.is_simple &&
2535 !neighborhood.variables_that_can_be_fixed_to_local_optimum
2537 display_lns_info =
true;
2538 shared_->bounds->FixVariablesFromPartialSolution(
2540 neighborhood.variables_that_can_be_fixed_to_local_optimum);
2544 data.new_objective = data.base_objective;
2548 shared_->model_proto->objective(), local_response));
2555 const std::vector<int64_t> base_solution(
2556 base_response.solution().begin(), base_response.solution().end());
2557 if (solution != base_solution) {
2558 new_solution =
true;
2559 shared_->response->NewSolution(local_response,
nullptr);
2562 if (!neighborhood.is_reduced &&
2565 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2566 local_response.solution_info());
2567 shared_->time_limit->Stop();
2571 generator_->AddSolveData(data);
2574 auto* logger = shared_->global_model->GetOrCreate<SolverLogger>();
2575 std::string s = absl::StrCat(
" LNS ",
name(),
":");
2578 shared_->model_proto->objective(),
2582 shared_->model_proto->objective(),
2585 absl::StrAppend(&s,
" [new_sol:", base_obj,
" -> ", new_obj,
"]");
2587 if (neighborhood.is_simple) {
2589 &s,
" [",
"relaxed:", neighborhood.num_relaxed_variables,
2590 " in_obj:", neighborhood.num_relaxed_variables_in_objective,
2592 neighborhood.variables_that_can_be_fixed_to_local_optimum.size(),
2595 SOLVER_LOG(logger, s,
" [d:", data.difficulty,
", id:", task_id,
2596 ", dtime:", data.deterministic_time,
"/",
2597 data.deterministic_limit,
2598 ", status:", ProtoEnumToString<CpSolverStatus>(data.status),
2599 ", #calls:", generator_->num_calls(),
2600 ", p:", fully_solved_proportion,
"]");
2605 void Synchronize()
override {
2606 generator_->Synchronize();
2607 const double old = deterministic_time_;
2608 deterministic_time_ = generator_->deterministic_time();
2609 shared_->time_limit->AdvanceDeterministicTime(deterministic_time_ - old);
2615 std::unique_ptr<NeighborhoodGenerator> generator_;
2616 NeighborhoodGeneratorHelper* helper_;
2617 const SatParameters parameters_;
2618 SharedClasses* shared_;
2621void SolveCpModelParallel(
const CpModelProto&
model_proto,
2626 <<
"Enumerating all solutions in parallel is not supported.";
2628 std::unique_ptr<SharedBoundsManager> shared_bounds_manager;
2630 shared_bounds_manager = absl::make_unique<SharedBoundsManager>(
model_proto);
2633 std::unique_ptr<SharedRelaxationSolutionRepository>
2634 shared_relaxation_solutions;
2636 shared_relaxation_solutions =
2637 absl::make_unique<SharedRelaxationSolutionRepository>(
2640 shared_relaxation_solutions.get());
2643 auto shared_lp_solutions = absl::make_unique<SharedLPSolutionRepository>(
2649 std::unique_ptr<SharedIncompleteSolutionManager> shared_incomplete_solutions;
2654 if (use_feasibility_pump) {
2655 shared_incomplete_solutions =
2656 absl::make_unique<SharedIncompleteSolutionManager>();
2658 shared_incomplete_solutions.get());
2661 SharedClasses shared;
2665 shared.bounds = shared_bounds_manager.get();
2667 shared.relaxation_solutions = shared_relaxation_solutions.get();
2668 shared.lp_solutions = shared_lp_solutions.get();
2669 shared.incomplete_solutions = shared_incomplete_solutions.get();
2673 std::vector<std::unique_ptr<SubSolver>> subsolvers;
2676 subsolvers.push_back(absl::make_unique<SynchronizationPoint>([&shared]() {
2677 shared.response->Synchronize();
2678 shared.response->MutableSolutionsRepository()->Synchronize();
2679 if (shared.bounds !=
nullptr) {
2680 shared.bounds->Synchronize();
2682 if (shared.relaxation_solutions !=
nullptr) {
2683 shared.relaxation_solutions->Synchronize();
2685 if (shared.lp_solutions !=
nullptr) {
2686 shared.lp_solutions->Synchronize();
2696 local_params.set_linearization_level(0);
2697 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2698 "first_solution", local_params,
2706 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2707 local_params.name(), local_params,
2713 if (use_feasibility_pump) {
2714 subsolvers.push_back(
2715 absl::make_unique<FeasibilityPumpSolver>(
parameters, &shared));
2722 auto unique_helper = absl::make_unique<NeighborhoodGeneratorHelper>(
2725 NeighborhoodGeneratorHelper* helper = unique_helper.get();
2726 subsolvers.push_back(std::move(unique_helper));
2729 std::vector<SatParameters> lns_params = {
parameters};
2730 lns_params.back().
set_name(
"default");
2732 std::vector<SatParameters> lns_params =
2735 for (
const SatParameters& local_params : lns_params) {
2740 subsolvers.push_back(absl::make_unique<LnsSolver>(
2741 absl::make_unique<RelaxRandomVariablesGenerator>(
2742 helper, absl::StrCat(
"rnd_var_lns_", local_params.name())),
2743 local_params, helper, &shared));
2744 subsolvers.push_back(absl::make_unique<LnsSolver>(
2745 absl::make_unique<RelaxRandomConstraintsGenerator>(
2746 helper, absl::StrCat(
"rnd_cst_lns_", local_params.name())),
2747 local_params, helper, &shared));
2748 subsolvers.push_back(absl::make_unique<LnsSolver>(
2749 absl::make_unique<VariableGraphNeighborhoodGenerator>(
2750 helper, absl::StrCat(
"graph_var_lns_", local_params.name())),
2751 local_params, helper, &shared));
2752 subsolvers.push_back(absl::make_unique<LnsSolver>(
2753 absl::make_unique<ConstraintGraphNeighborhoodGenerator>(
2754 helper, absl::StrCat(
"graph_cst_lns_", local_params.name())),
2755 local_params, helper, &shared));
2762 subsolvers.push_back(absl::make_unique<LnsSolver>(
2763 absl::make_unique<SchedulingTimeWindowNeighborhoodGenerator>(
2764 helper, absl::StrCat(
"scheduling_time_window_lns_",
2765 local_params.name())),
2766 local_params, helper, &shared));
2767 subsolvers.push_back(absl::make_unique<LnsSolver>(
2768 absl::make_unique<SchedulingNeighborhoodGenerator>(
2770 absl::StrCat(
"scheduling_random_lns_", local_params.name())),
2771 local_params, helper, &shared));
2775 const int num_circuit =
2777 const int num_routes =
2779 if (num_circuit + num_routes > 0) {
2780 subsolvers.push_back(absl::make_unique<LnsSolver>(
2781 absl::make_unique<RoutingRandomNeighborhoodGenerator>(
2782 helper, absl::StrCat(
"routing_random_lns_", local_params.name())),
2783 local_params, helper, &shared));
2785 subsolvers.push_back(absl::make_unique<LnsSolver>(
2786 absl::make_unique<RoutingPathNeighborhoodGenerator>(
2787 helper, absl::StrCat(
"routing_path_lns_", local_params.name())),
2788 local_params, helper, &shared));
2790 if (num_routes > 0 || num_circuit > 1) {
2791 subsolvers.push_back(absl::make_unique<LnsSolver>(
2792 absl::make_unique<RoutingFullPathNeighborhoodGenerator>(
2794 absl::StrCat(
"routing_full_path_lns_", local_params.name())),
2795 local_params, helper, &shared));
2807 subsolvers.push_back(absl::make_unique<LnsSolver>(
2808 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2809 helper, shared.response, shared.relaxation_solutions,
2810 shared.lp_solutions,
nullptr,
2811 absl::StrCat(
"rins_lns_", local_params.name())),
2812 local_params, helper, &shared));
2815 subsolvers.push_back(absl::make_unique<LnsSolver>(
2816 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2817 helper,
nullptr, shared.relaxation_solutions,
2818 shared.lp_solutions, shared.incomplete_solutions,
2819 absl::StrCat(
"rens_lns_", local_params.name())),
2820 local_params, helper, &shared));
2824 subsolvers.push_back(absl::make_unique<LnsSolver>(
2826 ConsecutiveConstraintsRelaxationNeighborhoodGenerator>(
2827 helper, absl::StrCat(
"rnd_rel_lns_", local_params.name())),
2828 local_params, helper, &shared));
2830 subsolvers.push_back(absl::make_unique<LnsSolver>(
2831 absl::make_unique<WeightedRandomRelaxationNeighborhoodGenerator>(
2832 helper, absl::StrCat(
"wgt_rel_lns_", local_params.name())),
2833 local_params, helper, &shared));
2840 subsolvers.push_back(absl::make_unique<SynchronizationPoint>(
2841 [&shared]() { shared.response->UpdateGapIntegral(); }));
2845 if (logger->LoggingIsEnabled()) {
2846 std::vector<std::string> names;
2847 for (
const auto& subsolver : subsolvers) {
2848 if (!subsolver->name().empty()) names.push_back(subsolver->name());
2852 absl::StrFormat(
"Starting Search at %.2fs with %i "
2853 "workers and subsolvers: [ %s ]",
2854 shared.wall_timer->Get(), num_search_workers,
2855 absl::StrJoin(names,
", ")));
2868 SOLVER_LOG(logger,
"Sub-solver search statistics:");
2869 for (
const auto& subsolver : subsolvers) {
2870 const std::string stats = subsolver->StatisticsString();
2871 if (stats.empty())
continue;
2872 SOLVER_LOG(logger, absl::StrCat(
" '", subsolver->name(),
"':\n", stats));
2882void AddPostsolveClauses(
const std::vector<int>& postsolve_mapping,
2883 Model*
model, CpModelProto* mapping_proto) {
2884 auto* mapping =
model->GetOrCreate<CpModelMapping>();
2885 auto* postsolve =
model->GetOrCreate<PostsolveClauses>();
2886 for (
const auto& clause : postsolve->clauses) {
2887 auto*
ct = mapping_proto->add_constraints()->mutable_bool_or();
2888 for (
const Literal l : clause) {
2889 int var = mapping->GetProtoVariableFromBooleanVariable(l.Variable());
2891 var = postsolve_mapping[
var];
2895 postsolve->clauses.clear();
2904 user_timer->
Start();
2906#if !defined(__PORTABLE_PLATFORM__)
2909#if !defined(__PORTABLE_PLATFORM__)
2911 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
2912 const std::string
file =
2913 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
"model.pb.txt");
2914 LOG(
INFO) <<
"Dumping cp model proto to '" <<
file <<
"'.";
2919#if !defined(__PORTABLE_PLATFORM__)
2921 if (!absl::GetFlag(FLAGS_cp_model_params).empty()) {
2924 CHECK(google::protobuf::TextFormat::ParseFromString(
2925 absl::GetFlag(FLAGS_cp_model_params), &flag_params));
2936 std::string log_string;
2938 logger->AddInfoLoggingCallback([&log_string](
const std::string&
message) {
2939 absl::StrAppend(&log_string,
message,
"\n");
2945 absl::GetFlag(FLAGS_cp_model_dump_prefix));
2947#if !defined(__PORTABLE_PLATFORM__)
2951 if (absl::GetFlag(FLAGS_cp_model_dump_response)) {
2952 shared_response_manager->AddFinalResponsePostprocessor(
2954 const std::string
file = absl::StrCat(
2955 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"response.pb.txt");
2956 LOG(
INFO) <<
"Dumping response proto to '" <<
file <<
"'.";
2964 shared_response_manager->AddFinalResponsePostprocessor(
2971 if (!log_string.empty()) {
2972 response->set_solve_log(log_string);
2980 shared_response_manager->AddResponsePostprocessor(
2986 shared_time_limit->GetElapsedDeterministicTime());
2995 if (!error.empty()) {
2996 SOLVER_LOG(logger,
"Invalid parameters: ", error);
3001 shared_response_manager->MutableResponse()->set_status(
3003 shared_response_manager->MutableResponse()->set_solution_info(error);
3004 return shared_response_manager->GetResponse();
3009 model->GetOrCreate<
TimeLimit>()->ResetLimitFromParameters(params);
3011#if !defined(__PORTABLE_PLATFORM__)
3015 [&shared_time_limit]() { shared_time_limit->Stop(); });
3025#if !defined(__PORTABLE_PLATFORM__)
3027 const int num_cores =
3030 : std::max<int>(std::thread::hardware_concurrency(), 1);
3032 const int num_cores = 1;
3034 SOLVER_LOG(logger,
"Setting number of workers to ", num_cores);
3038 SOLVER_LOG(logger,
"Parameters: ", params.ShortDebugString());
3047 if (!error.empty()) {
3048 SOLVER_LOG(logger,
"Invalid model: ", error);
3049 shared_response_manager->MutableResponse()->set_status(
3051 shared_response_manager->MutableResponse()->set_solution_info(error);
3052 return shared_response_manager->GetResponse();
3068 bool is_pure_sat =
true;
3070 if (
var.domain_size() != 2 ||
var.domain(0) < 0 ||
var.domain(1) > 1) {
3071 is_pure_sat =
false;
3077 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolOr &&
3078 ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolAnd) {
3079 is_pure_sat =
false;
3087 *shared_response_manager->MutableResponse() =
3090 *shared_response_manager->MutableResponse()
3093 return shared_response_manager->GetResponse();
3100 absl::StrFormat(
"Starting presolve at %.2fs",
wall_timer->
Get()));
3103 auto context = absl::make_unique<PresolveContext>(
model, &new_cp_model_proto,
3109 VLOG(1) <<
"Model found infeasible during copy";
3121 " variables to their value in the solution hints.");
3128 const std::string var_name = var_proto.
name().empty()
3129 ? absl::StrCat(
"var(",
var,
")")
3134 "Hint found infeasible when assigning variable '", var_name,
3135 "' with domain", var_domain.
ToString(),
" the value ",
3159 "The solution hint is complete and is feasible.");
3164 "The solution hint is complete, but it is infeasible! we "
3165 "will try to repair it.");
3172 shared_response_manager->AddFinalResponsePostprocessor(
3175 if (
response->solution().empty())
return;
3179 double value = float_obj.offset();
3180 const int num_terms = float_obj.vars().size();
3181 for (
int i = 0; i < num_terms; ++i) {
3182 value += float_obj.coeffs(i) *
3183 static_cast<double>(
response->solution(float_obj.vars(i)));
3192 *
response->mutable_integer_objective() = integer_obj;
3198 !integer_obj.scaling_was_exact()) {
3199 const int64_t integer_lb = response->inner_objective_lower_bound();
3200 const double lb = ComputeTrueObjectiveLowerBound(
3201 model_proto, integer_obj, integer_lb);
3202 SOLVER_LOG(logger,
"[Scaling] scaled_objective_bound: ",
3203 response->best_objective_bound(),
3204 " corrected_bound: ", lb,
3205 " delta: ", response->best_objective_bound() - lb);
3209 if (float_obj.maximize()) {
3210 response->set_best_objective_bound(
3211 std::max(lb, response->objective_value()));
3213 response->set_best_objective_bound(
3214 std::min(lb, response->objective_value()));
3221 const double gap = std::abs(response->objective_value() -
3222 response->best_objective_bound());
3223 if (gap > params.absolute_gap_limit()) {
3225 "[Scaling] Warning: OPTIMAL was reported, yet the "
3227 gap,
") is greater than requested absolute limit (",
3228 params.absolute_gap_limit(),
").");
3235 (params.num_search_workers() > 1 ||
model_proto.has_objective())) {
3238 "Warning: solving with assumptions was requested in a non-fully "
3239 "supported setting.\nWe will assumes these assumptions true while "
3240 "solving, but if the model is infeasible, you will not get a useful "
3241 "'sufficient_assumptions_for_infeasibility' field in the response, it "
3242 "will include all assumptions.");
3250 shared_response_manager->AddFinalResponsePostprocessor(
3255 *
response->mutable_sufficient_assumptions_for_infeasibility() =
3259 context->InitializeNewDomains();
3261 if (!
context->SetLiteralToTrue(ref)) {
3262 shared_response_manager->MutableResponse()->set_status(
3264 shared_response_manager->MutableResponse()
3265 ->add_sufficient_assumptions_for_infeasibility(ref);
3266 return shared_response_manager->GetResponse();
3272 std::vector<int> postsolve_mapping;
3276 SOLVER_LOG(logger,
"Problem closed by presolve.");
3277 shared_response_manager->MutableResponse()->set_status(presolve_status);
3278 return shared_response_manager->GetResponse();
3286 if (params.cp_model_presolve()) {
3287 shared_response_manager->AddSolutionPostprocessor(
3289 &postsolve_mapping](std::vector<int64_t>* solution) {
3290 AddPostsolveClauses(postsolve_mapping,
model, &mapping_proto);
3291 PostsolveResponseWrapper(params,
model_proto.variables_size(),
3292 mapping_proto, postsolve_mapping, solution);
3294 shared_response_manager->AddResponsePostprocessor(
3300 ->mutable_sufficient_assumptions_for_infeasibility())) {
3302 ? postsolve_mapping[ref]
3305 if (!
response->solution().empty()) {
3308 std::vector<int64_t>(
response->solution().begin(),
3310 &mapping_proto, &postsolve_mapping))
3311 <<
"postsolved solution";
3313 if (params.fill_tightened_domains_in_response()) {
3316 if (mapping_proto.variables().size() >=
3318 for (
int i = 0; i <
model_proto.variables().size(); ++i) {
3319 *
response->add_tightened_variables() =
3320 mapping_proto.variables(i);
3326 shared_response_manager->AddFinalResponsePostprocessor(
3328 if (!
response->solution().empty()) {
3334 shared_response_manager->AddResponsePostprocessor(
3337 const int initial_size =
model_proto.variables_size();
3338 if (
response->solution_size() > 0) {
3339 response->mutable_solution()->Truncate(initial_size);
3341 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
3344 std::vector<int64_t>(
response->solution().begin(),
3348 if (params.fill_tightened_domains_in_response()) {
3357 if (params.symmetry_level() > 1) {
3361 const auto& observers =
model->GetOrCreate<SolutionObservers>()->observers;
3362 if (!observers.empty()) {
3363 shared_response_manager->AddSolutionCallback(
3364 [&observers](
const CpSolverResponse&
response) {
3365 for (
const auto& observer : observers) {
3375 if (new_cp_model_proto.has_objective()) {
3376 shared_response_manager->InitializeObjective(new_cp_model_proto);
3377 shared_response_manager->SetGapLimitsFromParameters(params);
3382 shared_response_manager->UpdateGapIntegral();
3384#if !defined(__PORTABLE_PLATFORM__)
3385 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
3386 const std::string presolved_file = absl::StrCat(
3387 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"presolved_model.pb.txt");
3388 LOG(
INFO) <<
"Dumping presolved cp model proto to '" << presolved_file
3393 const std::string mapping_file = absl::StrCat(
3394 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"mapping_model.pb.txt");
3395 LOG(
INFO) <<
"Dumping mapping cp model proto to '" << mapping_file <<
"'.";
3400 if (params.stop_after_presolve() || shared_time_limit->LimitReached()) {
3401 int64_t num_terms = 0;
3402 for (
const ConstraintProto&
ct : new_cp_model_proto.constraints()) {
3406 logger,
"Stopped after presolve.",
3407 "\nPresolvedNumVariables: ", new_cp_model_proto.variables().size(),
3408 "\nPresolvedNumConstraints: ", new_cp_model_proto.constraints().size(),
3409 "\nPresolvedNumTerms: ", num_terms);
3411 shared_response_manager->SetStatsFromModel(
model);
3412 return shared_response_manager->GetResponse();
3416 if (params.stop_after_first_solution()) {
3417 shared_response_manager->AddSolutionCallback(
3418 [shared_time_limit](
const CpSolverResponse&
response) {
3419 shared_time_limit->Stop();
3423#if defined(__PORTABLE_PLATFORM__)
3427 if (params.num_search_workers() > 1 || params.interleave_search()) {
3428 SolveCpModelParallel(new_cp_model_proto,
model);
3432 SOLVER_LOG(logger, absl::StrFormat(
"Starting to load the model at %.2fs",
3434 shared_response_manager->SetUpdateGapIntegralOnEachChange(
true);
3435 LoadCpModel(new_cp_model_proto,
model);
3436 shared_response_manager->LoadDebugSolution(
model);
3439 SOLVER_LOG(logger, absl::StrFormat(
"Starting sequential search at %.2fs",
3441 if (params.repair_hint()) {
3442 MinimizeL1DistanceWithHint(new_cp_model_proto,
model);
3444 QuickSolveWithHint(new_cp_model_proto,
model);
3446 SolveLoadedCpModel(new_cp_model_proto,
model);
3449 if (logger->LoggingIsEnabled()) {
3450 if (params.num_search_workers() <= 1) {
3452 *
model->GetOrCreate<LinearProgrammingConstraintCollection>();
3455 for (
const auto* lp : lps) {
3461 if (params.num_search_workers() > 1) {
3463 shared_response_manager->DisplayImprovementStatistics();
3467 return shared_response_manager->GetResponse();
3482#if !defined(__PORTABLE_PLATFORM__)
3484 const std::string& params) {
#define CHECK_NE(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
#define VLOG(verboselevel)
bool AddEdge(int node1, int node2)
std::vector< int > GetComponentIds()
void SetNumberOfNodes(int num_nodes)
int GetNumberOfComponents() const
We call domain any subset of Int64 = [kint64min, kint64max].
std::string ToString() const
Returns a compact string of a vector of intervals like "[1,4][6][10,20]".
void EnableLogging(bool enable)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
const ::operations_research::sat::IntervalConstraintProto & interval() const
int32_t enforcement_literal(int index) const
const std::string & name() const
const ::operations_research::sat::CpObjectiveProto & objective() const
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
bool has_floating_point_objective() const
const ::operations_research::sat::DecisionStrategyProto & search_strategy(int index) const
const ::operations_research::sat::PartialVariableAssignment & solution_hint() const
bool has_objective() const
bool has_solution_hint() const
int variables_size() const
const ::operations_research::sat::FloatObjectiveProto & floating_point_objective() const
int32_t assumptions(int index) const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
int64_t domain(int index) const
int32_t vars(int index) const
int64_t coeffs(int index) const
double scaling_factor() const
const std::string & name() const
int64_t domain(int index) const
const ::operations_research::sat::LinearExpressionProto & size() const
Literal(int signed_value)
Class that owns everything related to a particular optimization model.
void Register(T *non_owned_class)
Register a non-owned class that will be "singleton" in the model.
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
int32_t vars(int index) const
int64_t values(int index) const
bool optimize_with_core() const
bool interleave_search() const
int32_t linearization_level() const
bool use_lns_only() const
void MergeFrom(const SatParameters &from)
void set_search_branching(::operations_research::sat::SatParameters_SearchBranching value)
bool log_search_progress() const
bool enumerate_all_solutions() const
bool optimize_with_lb_tree_search() const
int32_t num_search_workers() const
int32_t interleave_batch_size() const
::operations_research::sat::SatParameters_SearchBranching search_branching() const
bool use_feasibility_pump() const
bool fix_variables_to_their_hinted_value() const
void set_optimize_with_core(bool value)
bool use_relaxation_lns() const
bool use_rins_lns() const
bool catch_sigint_signal() const
bool use_sat_inprocessing() const
void set_name(ArgT0 &&arg0, ArgT... args)
bool debug_crash_on_bad_hint() const
bool log_subsolver_statistics() const
int32_t binary_search_num_conflicts() const
void set_stop_after_first_solution(bool value)
void set_max_number_of_conflicts(int64_t value)
bool mip_compute_true_objective_bound() const
bool cp_model_presolve() const
bool fill_tightened_domains_in_response() const
bool use_absl_random() const
int32_t symmetry_level() const
bool auto_detect_greater_than_at_least_one_of() const
int32_t hint_conflict_limit() const
bool use_probing_search() const
static constexpr SearchBranching HINT_SEARCH
bool optimize_with_max_hs() const
bool log_to_response() const
int32_t cp_model_probing_level() const
bool log_to_stdout() const
bool share_level_zero_bounds() const
static constexpr SearchBranching FIXED_SEARCH
bool diversify_lns_params() const
void set_dump_prefix(const std::string &dump_prefix)
void NewSolution(const CpSolverResponse &response, Model *model)
SharedBoundsManager * bounds
SharedRelaxationSolutionRepository * relaxation_solutions
SharedLPSolutionRepository * lp_solutions
CpModelProto const * model_proto
SharedIncompleteSolutionManager * incomplete_solutions
ABSL_FLAG(std::string, cp_model_dump_prefix, "/tmp/", "Prefix filename for all dumped files")
SharedResponseManager * response
ModelSharedTimeLimit * time_limit
GurobiMPCallbackContext * context
absl::Cleanup< absl::decay_t< Callback > > MakeCleanup(Callback &&callback)
absl::Status SetTextProto(const absl::string_view &filename, const google::protobuf::Message &proto, int flags)
absl::Status Open(const absl::string_view &filename, const absl::string_view &mode, File **f, int flags)
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
bool ContainsKey(const Collection &collection, const Key &key)
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
std::function< void(Model *)> NewFeasibleSolutionObserver(const std::function< void(const CpSolverResponse &response)> &observer)
Creates a solution observer with the model with model.Add(NewFeasibleSolutionObserver([](response){....
void DeterministicLoop(const std::vector< std::unique_ptr< SubSolver > > &subsolvers, int num_threads, int batch_size)
void DetectAndAddSymmetryToProto(const SatParameters ¶ms, CpModelProto *proto, SolverLogger *logger)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void RestrictObjectiveDomainWithBinarySearch(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
std::function< SatParameters(Model *)> NewSatParameters(const std::string ¶ms)
Creates parameters for the solver, which you can add to the model with.
SatSolver::Status ResetAndSolveIntegerProblem(const std::vector< Literal > &assumptions, Model *model)
void LoadVariables(const CpModelProto &model_proto, bool view_all_booleans_as_integers, Model *m)
std::string CpSolverResponseStats(const CpSolverResponse &response, bool has_objective)
Returns a string with some statistics on the solver response.
bool LoadConstraint(const ConstraintProto &ct, Model *m)
std::vector< int > UsedVariables(const ConstraintProto &ct)
double UnscaleObjectiveValue(const CpObjectiveProto &proto, double value)
bool RefIsPositive(int ref)
std::string ValidateParameters(const SatParameters ¶ms)
void ExtractElementEncoding(const CpModelProto &model_proto, Model *m)
CpSolverResponse SolveWithParameters(const CpModelProto &model_proto, const std::string ¶ms)
Solves the given CpModelProto with the given sat parameters as string in JSon format,...
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
void PostsolveResponse(const int64_t num_variables_in_original_model, const CpModelProto &mapping_proto, const std::vector< int > &postsolve_mapping, std::vector< int64_t > *solution)
void LoadBooleanSymmetries(const CpModelProto &model_proto, Model *m)
const IntegerVariable kNoIntegerVariable(-1)
std::function< BooleanOrIntegerLiteral()> FollowHint(const std::vector< BooleanOrIntegerVariable > &vars, const std::vector< IntegerValue > &values, Model *model)
void NonDeterministicLoop(const std::vector< std::unique_ptr< SubSolver > > &subsolvers, int num_threads)
std::function< IntegerVariable(Model *)> ConstantIntegerVariable(int64_t value)
double ScaleObjectiveValue(const CpObjectiveProto &proto, int64_t value)
void ConfigureSearchHeuristics(Model *model)
std::string ValidateCpModel(const CpModelProto &model, bool after_presolve)
SatSolver::Status MinimizeWithHittingSetAndLazyEncoding(const ObjectiveDefinition &objective_definition, const std::function< void()> &feasible_solution_observer, Model *model)
IntegerVariable PositiveVariable(IntegerVariable i)
void CopyEverythingExceptVariablesAndConstraintsFieldsIntoContext(const CpModelProto &in_model, PresolveContext *context)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
bool ImportConstraintsWithBasicPresolveIntoContext(const CpModelProto &in_model, PresolveContext *context)
std::string CpModelStats(const CpModelProto &model_proto)
Returns a string with some statistics on the given CpModelProto.
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
void DetectOptionalVariables(const CpModelProto &model_proto, Model *m)
CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model)
Solves the given CpModelProto.
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> ExcludeCurrentSolutionWithoutIgnoredVariableAndBacktrack()
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
void MinimizeCoreWithPropagation(TimeLimit *limit, SatSolver *solver, std::vector< Literal > *core)
SatSolver::Status ContinuousProbing(const std::vector< BooleanVariable > &bool_vars, const std::vector< IntegerVariable > &int_vars, const std::function< void()> &feasible_solution_observer, Model *model)
CpSolverStatus PresolveCpModel(PresolveContext *context, std::vector< int > *postsolve_mapping)
std::function< SatParameters(Model *)> NewSatParameters(const sat::SatParameters ¶meters)
SatSolver::Status SolveWithPresolve(std::unique_ptr< SatSolver > *solver, TimeLimit *time_limit, std::vector< bool > *solution, DratProofHandler *drat_proof_handler, SolverLogger *logger)
void AddFullEncodingFromSearchBranching(const CpModelProto &model_proto, Model *m)
std::vector< SatParameters > GetDiverseSetOfParameters(const SatParameters &base_params, const CpModelProto &cp_model, const int num_workers)
std::string ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case)
void ExtractEncoding(const CpModelProto &model_proto, Model *m)
void PropagateEncodingFromEquivalenceRelations(const CpModelProto &model_proto, Model *m)
bool SolutionIsFeasible(const CpModelProto &model, const std::vector< int64_t > &variable_values, const CpModelProto *mapping_proto, const std::vector< int > *postsolve_mapping)
std::function< BooleanOrIntegerLiteral()> ConstructSearchStrategy(const CpModelProto &cp_model_proto, const std::vector< IntegerVariable > &variable_mapping, IntegerVariable objective_var, Model *model)
LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, Model *m)
CpSolverResponse Solve(const CpModelProto &model_proto)
Solves the given CpModelProto and returns an instance of CpSolverResponse.
std::function< BooleanOrIntegerLiteral()> InstrumentSearchStrategy(const CpModelProto &cp_model_proto, const std::vector< IntegerVariable > &variable_mapping, const std::function< BooleanOrIntegerLiteral()> &instrumented_strategy, Model *model)
SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
Collection of objects used to extend the Constraint Solver library.
int OrToolsMinorVersion()
std::mt19937 random_engine_t
std::string ProtobufDebugString(const P &message)
int OrToolsMajorVersion()
int OrToolsPatchVersion()
static int input(yyscan_t yyscanner)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
std::vector< std::function< void(const CpSolverResponse &response)> > observers
SolutionObservers(Model *model)
#define SOLVER_LOG(logger,...)
#define VLOG_IS_ON(verboselevel)