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;
177 int no_overlap_2d_num_rectangles = 0;
178 int no_overlap_2d_num_optional_rectangles = 0;
179 int no_overlap_2d_num_linear_areas = 0;
180 int no_overlap_2d_num_quadratic_areas = 0;
182 int cumulative_num_intervals = 0;
183 int cumulative_num_optional_intervals = 0;
184 int cumulative_num_variable_sizes = 0;
185 int cumulative_num_variable_demands = 0;
187 int no_overlap_num_intervals = 0;
188 int no_overlap_num_optional_intervals = 0;
189 int no_overlap_num_variable_sizes = 0;
196 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) {
197 if (
ct.linear().vars_size() == 1)
name +=
"1";
198 if (
ct.linear().vars_size() == 2)
name +=
"2";
199 if (
ct.linear().vars_size() == 3)
name +=
"3";
200 if (
ct.linear().vars_size() > 3)
name +=
"N";
203 num_constraints_by_name[
name]++;
204 if (!
ct.enforcement_literal().empty()) {
205 num_reif_constraints_by_name[
name]++;
214 auto expression_is_fixed =
216 for (
const int ref : expr.vars()) {
217 if (!variable_is_fixed(ref)) {
224 auto interval_has_fixed_size = [&
model_proto, &expression_is_fixed](
int c) {
228 auto constraint_is_optional = [&
model_proto](
int i) {
234 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) {
235 name_to_num_literals[
name] +=
ct.bool_or().literals().size();
236 }
else if (
ct.constraint_case() ==
237 ConstraintProto::ConstraintCase::kBoolAnd) {
238 name_to_num_literals[
name] +=
ct.bool_and().literals().size();
239 }
else if (
ct.constraint_case() ==
240 ConstraintProto::ConstraintCase::kAtMostOne) {
241 name_to_num_literals[
name] +=
ct.at_most_one().literals().size();
242 }
else if (
ct.constraint_case() ==
243 ConstraintProto::ConstraintCase::kExactlyOne) {
244 name_to_num_literals[
name] +=
ct.exactly_one().literals().size();
245 }
else if (
ct.constraint_case() ==
246 ConstraintProto::ConstraintCase::kNoOverlap2D) {
247 const int num_boxes =
ct.no_overlap_2d().x_intervals_size();
248 no_overlap_2d_num_rectangles += num_boxes;
249 for (
int i = 0; i < num_boxes; ++i) {
250 const int x_interval =
ct.no_overlap_2d().x_intervals(i);
251 const int y_interval =
ct.no_overlap_2d().y_intervals(i);
252 if (constraint_is_optional(x_interval) ||
253 constraint_is_optional(y_interval)) {
254 no_overlap_2d_num_optional_rectangles++;
256 const int num_fixed = interval_has_fixed_size(x_interval) +
257 interval_has_fixed_size(y_interval);
258 if (num_fixed == 0) {
259 no_overlap_2d_num_quadratic_areas++;
260 }
else if (num_fixed == 1) {
261 no_overlap_2d_num_linear_areas++;
264 }
else if (
ct.constraint_case() ==
265 ConstraintProto::ConstraintCase::kNoOverlap) {
266 const int num_intervals =
ct.no_overlap().intervals_size();
267 no_overlap_num_intervals += num_intervals;
268 for (
int i = 0; i < num_intervals; ++i) {
269 const int interval =
ct.no_overlap().intervals(i);
270 if (constraint_is_optional(
interval)) {
271 no_overlap_num_optional_intervals++;
273 if (!interval_has_fixed_size(
interval)) {
274 no_overlap_num_variable_sizes++;
277 }
else if (
ct.constraint_case() ==
278 ConstraintProto::ConstraintCase::kCumulative) {
279 const int num_intervals =
ct.cumulative().intervals_size();
280 cumulative_num_intervals += num_intervals;
281 for (
int i = 0; i < num_intervals; ++i) {
282 const int interval =
ct.cumulative().intervals(i);
283 if (constraint_is_optional(
interval)) {
284 cumulative_num_optional_intervals++;
286 if (!interval_has_fixed_size(
interval)) {
287 cumulative_num_variable_sizes++;
289 if (!expression_is_fixed(
ct.cumulative().demands(i))) {
290 cumulative_num_variable_demands++;
295 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear &&
296 ct.linear().vars_size() > 3) {
297 name_to_num_terms[
name] +=
ct.linear().vars_size();
301 int num_constants = 0;
302 std::set<int64_t> constant_values;
303 std::map<Domain, int> num_vars_per_domains;
305 if (
var.domain_size() == 2 &&
var.domain(0) ==
var.domain(1)) {
307 constant_values.insert(
var.domain(0));
325 &result,
"Search strategy: on ", strategy.variables_size(),
327 ProtoEnumToString<DecisionStrategyProto::VariableSelectionStrategy>(
328 strategy.variable_selection_strategy()),
330 ProtoEnumToString<DecisionStrategyProto::DomainReductionStrategy>(
331 strategy.domain_reduction_strategy()),
335 const std::string objective_string =
342 " in floating point objective)")
345 objective_string,
"\n");
346 if (num_vars_per_domains.size() < 100) {
347 for (
const auto& entry : num_vars_per_domains) {
348 const std::string temp = absl::StrCat(
" - ", entry.second,
" in ",
349 entry.first.ToString(),
"\n");
350 absl::StrAppend(&result, Summarize(temp));
353 int64_t max_complexity = 0;
356 for (
const auto& entry : num_vars_per_domains) {
360 max_complexity,
static_cast<int64_t
>(entry.first.NumIntervals()));
362 absl::StrAppend(&result,
" - ", num_vars_per_domains.size(),
363 " different domains in [",
min,
",",
max,
364 "] with a largest complexity of ", max_complexity,
".\n");
367 if (num_constants > 0) {
368 const std::string temp =
369 absl::StrCat(
" - ", num_constants,
" constants in {",
370 absl::StrJoin(constant_values,
","),
"} \n");
371 absl::StrAppend(&result, Summarize(temp));
374 std::vector<std::string> constraints;
375 constraints.reserve(num_constraints_by_name.size());
376 for (
const auto& entry : num_constraints_by_name) {
377 const std::string&
name = entry.first;
378 constraints.push_back(absl::StrCat(
"#",
name,
": ", entry.second));
380 absl::StrAppend(&constraints.back(),
381 " (#enforced: ", num_reif_constraints_by_name[
name],
")");
384 absl::StrAppend(&constraints.back(),
385 " (#literals: ", name_to_num_literals[
name],
")");
388 absl::StrAppend(&constraints.back(),
389 " (#terms: ", name_to_num_terms[
name],
")");
391 if (
name ==
"kNoOverlap2D") {
392 absl::StrAppend(&constraints.back(),
393 " (#rectangles: ", no_overlap_2d_num_rectangles);
394 if (no_overlap_2d_num_optional_rectangles > 0) {
395 absl::StrAppend(&constraints.back(),
396 ", #optional: ", no_overlap_2d_num_optional_rectangles);
398 if (no_overlap_2d_num_linear_areas > 0) {
399 absl::StrAppend(&constraints.back(),
400 ", #linear_areas: ", no_overlap_2d_num_linear_areas);
402 if (no_overlap_2d_num_quadratic_areas > 0) {
403 absl::StrAppend(&constraints.back(),
", #quadratic_areas: ",
404 no_overlap_2d_num_quadratic_areas);
406 absl::StrAppend(&constraints.back(),
")");
407 }
else if (
name ==
"kCumulative") {
408 absl::StrAppend(&constraints.back(),
409 " (#intervals: ", cumulative_num_intervals);
410 if (cumulative_num_optional_intervals > 0) {
411 absl::StrAppend(&constraints.back(),
412 ", #optional: ", cumulative_num_optional_intervals);
414 if (cumulative_num_variable_sizes > 0) {
415 absl::StrAppend(&constraints.back(),
416 ", #variable_sizes: ", cumulative_num_variable_sizes);
418 if (cumulative_num_variable_demands > 0) {
419 absl::StrAppend(&constraints.back(),
", #variable_demands: ",
420 cumulative_num_variable_demands);
422 absl::StrAppend(&constraints.back(),
")");
423 }
else if (
name ==
"kNoOverlap") {
424 absl::StrAppend(&constraints.back(),
425 " (#intervals: ", no_overlap_num_intervals);
426 if (no_overlap_num_optional_intervals > 0) {
427 absl::StrAppend(&constraints.back(),
428 ", #optional: ", no_overlap_num_optional_intervals);
430 if (no_overlap_num_variable_sizes > 0) {
431 absl::StrAppend(&constraints.back(),
432 ", #variable_sizes: ", no_overlap_num_variable_sizes);
434 absl::StrAppend(&constraints.back(),
")");
437 std::sort(constraints.begin(), constraints.end());
438 absl::StrAppend(&result, absl::StrJoin(constraints,
"\n"));
444 bool has_objective) {
446 absl::StrAppend(&result,
"CpSolverResponse summary:");
447 absl::StrAppend(&result,
"\nstatus: ",
448 ProtoEnumToString<CpSolverStatus>(
response.status()));
451 absl::StrAppendFormat(&result,
"\nobjective: %.16g",
453 absl::StrAppendFormat(&result,
"\nbest_bound: %.16g",
456 absl::StrAppend(&result,
"\nobjective: NA");
457 absl::StrAppend(&result,
"\nbest_bound: NA");
460 absl::StrAppend(&result,
"\nbooleans: ",
response.num_booleans());
461 absl::StrAppend(&result,
"\nconflicts: ",
response.num_conflicts());
462 absl::StrAppend(&result,
"\nbranches: ",
response.num_branches());
466 absl::StrAppend(&result,
467 "\npropagations: ",
response.num_binary_propagations());
469 &result,
"\ninteger_propagations: ",
response.num_integer_propagations());
471 absl::StrAppend(&result,
"\nrestarts: ",
response.num_restarts());
472 absl::StrAppend(&result,
"\nlp_iterations: ",
response.num_lp_iterations());
473 absl::StrAppend(&result,
"\nwalltime: ",
response.wall_time());
474 absl::StrAppend(&result,
"\nusertime: ",
response.user_time());
475 absl::StrAppend(&result,
476 "\ndeterministic_time: ",
response.deterministic_time());
477 absl::StrAppend(&result,
"\ngap_integral: ",
response.gap_integral());
478 absl::StrAppend(&result,
"\n");
484#if !defined(__PORTABLE_PLATFORM__)
487void FillSolutionInResponse(
const CpModelProto&
model_proto,
const Model&
model,
491 auto* mapping =
model.Get<CpModelMapping>();
494 std::vector<int64_t> solution;
496 if (mapping->IsInteger(i)) {
497 const IntegerVariable
var = mapping->Integer(i);
503 DCHECK(mapping->IsBoolean(i));
505 if (trail->Assignment().LiteralIsAssigned(
literal)) {
509 solution.push_back(0);
515 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
519 for (
const int64_t
value : solution) {
526IntegerVariable GetOrCreateVariableWithTightBound(
527 const std::vector<std::pair<IntegerVariable, int64_t>>& terms,
530 if (terms.size() == 1 && terms.front().second == 1) {
531 return terms.front().first;
533 if (terms.size() == 1 && terms.front().second == -1) {
539 for (
const std::pair<IntegerVariable, int64_t> var_coeff : terms) {
542 const int64_t coeff = var_coeff.second;
543 const int64_t prod1 = min_domain * coeff;
544 const int64_t prod2 = max_domain * coeff;
551IntegerVariable GetOrCreateVariableGreaterOrEqualToSumOf(
552 const std::vector<std::pair<IntegerVariable, int64_t>>& terms,
555 if (terms.size() == 1 && terms.front().second == 1) {
556 return terms.front().first;
558 if (terms.size() == 1 && terms.front().second == -1) {
563 const IntegerVariable new_var =
564 GetOrCreateVariableWithTightBound(terms,
model);
565 std::vector<IntegerVariable> vars;
566 std::vector<int64_t> coeffs;
567 for (
const auto& term : terms) {
568 vars.push_back(term.first);
569 coeffs.push_back(term.second);
571 vars.push_back(new_var);
572 coeffs.push_back(-1);
580IntegerVariable AddLPConstraints(
const CpModelProto&
model_proto, Model* m) {
589 const int num_lp_constraints = relaxation.linear_constraints.size();
590 const int num_lp_cut_generators = relaxation.cut_generators.size();
591 const int num_integer_variables =
592 m->GetOrCreate<IntegerTrail>()->NumIntegerVariables().value();
595 num_integer_variables);
596 auto get_constraint_index = [](
int ct_index) {
return ct_index; };
597 auto get_cut_generator_index = [num_lp_constraints](
int cut_index) {
598 return num_lp_constraints + cut_index;
600 auto get_var_index = [num_lp_constraints,
601 num_lp_cut_generators](IntegerVariable
var) {
602 return num_lp_constraints + num_lp_cut_generators +
var.value();
604 for (
int i = 0; i < num_lp_constraints; i++) {
605 for (
const IntegerVariable
var : relaxation.linear_constraints[i].vars) {
606 components.
AddEdge(get_constraint_index(i), get_var_index(
var));
609 for (
int i = 0; i < num_lp_cut_generators; ++i) {
610 for (
const IntegerVariable
var : relaxation.cut_generators[i].vars) {
611 components.
AddEdge(get_cut_generator_index(i), get_var_index(
var));
616 std::vector<int> component_sizes(num_components, 0);
617 const std::vector<int> index_to_component = components.
GetComponentIds();
618 for (
int i = 0; i < num_lp_constraints; i++) {
619 ++component_sizes[index_to_component[get_constraint_index(i)]];
621 for (
int i = 0; i < num_lp_cut_generators; i++) {
622 ++component_sizes[index_to_component[get_cut_generator_index(i)]];
630 auto* mapping = m->GetOrCreate<CpModelMapping>();
632 const IntegerVariable
var =
634 ++component_sizes[index_to_component[get_var_index(
var)]];
638 std::vector<LinearProgrammingConstraint*> lp_constraints(num_components,
640 std::vector<std::vector<LinearConstraint>> component_to_constraints(
642 for (
int i = 0; i < num_lp_constraints; i++) {
643 const int c = index_to_component[get_constraint_index(i)];
644 if (component_sizes[c] <= 1)
continue;
645 component_to_constraints[c].push_back(relaxation.linear_constraints[i]);
646 if (lp_constraints[c] ==
nullptr) {
647 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
650 lp_constraints[c]->AddLinearConstraint(relaxation.linear_constraints[i]);
654 for (
int i = 0; i < num_lp_cut_generators; i++) {
655 const int c = index_to_component[get_cut_generator_index(i)];
656 if (lp_constraints[c] ==
nullptr) {
657 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
659 lp_constraints[c]->AddCutGenerator(std::move(relaxation.cut_generators[i]));
663 std::vector<std::vector<std::pair<IntegerVariable, int64_t>>>
664 component_to_cp_terms(num_components);
665 std::vector<std::pair<IntegerVariable, int64_t>> top_level_cp_terms;
666 int num_components_containing_objective = 0;
671 const IntegerVariable
var =
674 const int c = index_to_component[get_var_index(
var)];
675 if (lp_constraints[c] !=
nullptr) {
676 lp_constraints[c]->SetObjectiveCoefficient(
var, IntegerValue(coeff));
677 component_to_cp_terms[c].push_back(std::make_pair(
var, coeff));
680 top_level_cp_terms.push_back(std::make_pair(
var, coeff));
684 for (
int c = 0; c < num_components; ++c) {
685 if (component_to_cp_terms[c].empty())
continue;
686 const IntegerVariable sub_obj_var =
687 GetOrCreateVariableGreaterOrEqualToSumOf(component_to_cp_terms[c], m);
688 top_level_cp_terms.push_back(std::make_pair(sub_obj_var, 1));
689 lp_constraints[c]->SetMainObjectiveVariable(sub_obj_var);
690 num_components_containing_objective++;
694 const IntegerVariable main_objective_var =
696 ? GetOrCreateVariableGreaterOrEqualToSumOf(top_level_cp_terms, m)
701 for (LinearProgrammingConstraint* lp_constraint : lp_constraints) {
702 if (lp_constraint ==
nullptr)
continue;
703 lp_constraint->RegisterWith(m);
704 VLOG(3) <<
"LP constraint: " << lp_constraint->DimensionString() <<
".";
707 VLOG(3) << top_level_cp_terms.size()
708 <<
" terms in the main objective linear equation ("
709 << num_components_containing_objective <<
" from LP constraints).";
710 return main_objective_var;
728#if !defined(__PORTABLE_PLATFORM__)
731 const std::string& params) {
733 if (!params.empty()) {
734 CHECK(google::protobuf::TextFormat::ParseFromString(params, &
parameters))
761void RegisterVariableBoundsLevelZeroExport(
762 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
764 CHECK(shared_bounds_manager !=
nullptr);
765 int saved_trail_index = 0;
766 auto broadcast_level_zero_bounds =
768 const std::vector<IntegerVariable>& modified_vars)
mutable {
769 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
771 std::vector<int> model_variables;
772 std::vector<int64_t> new_lower_bounds;
773 std::vector<int64_t> new_upper_bounds;
774 absl::flat_hash_set<int> visited_variables;
777 auto* integer_trail =
model->Get<IntegerTrail>();
778 for (
const IntegerVariable&
var : modified_vars) {
780 const int model_var =
781 mapping->GetProtoVariableFromIntegerVariable(positive_var);
782 if (model_var == -1 || visited_variables.contains(model_var)) {
789 visited_variables.insert(model_var);
790 const int64_t new_lb =
791 integer_trail->LevelZeroLowerBound(positive_var).value();
792 const int64_t new_ub =
793 integer_trail->LevelZeroUpperBound(positive_var).value();
796 model_variables.push_back(model_var);
797 new_lower_bounds.push_back(new_lb);
798 new_upper_bounds.push_back(new_ub);
802 auto* trail =
model->Get<Trail>();
803 for (; saved_trail_index < trail->Index(); ++saved_trail_index) {
804 const Literal fixed_literal = (*trail)[saved_trail_index];
805 const int model_var = mapping->GetProtoVariableFromBooleanVariable(
806 fixed_literal.Variable());
807 if (model_var == -1 || visited_variables.contains(model_var)) {
814 visited_variables.insert(model_var);
815 model_variables.push_back(model_var);
816 if (fixed_literal.IsPositive()) {
817 new_lower_bounds.push_back(1);
818 new_upper_bounds.push_back(1);
820 new_lower_bounds.push_back(0);
821 new_upper_bounds.push_back(0);
825 if (!model_variables.empty()) {
826 shared_bounds_manager->ReportPotentialNewBounds(
831 if (!
model->Get<SatParameters>()->interleave_search()) {
832 shared_bounds_manager->Synchronize();
844 const IntegerVariable num_vars =
845 model->GetOrCreate<IntegerTrail>()->NumIntegerVariables();
846 std::vector<IntegerVariable> all_variables;
847 all_variables.reserve(num_vars.value());
848 for (IntegerVariable
var(0);
var < num_vars; ++
var) {
849 all_variables.push_back(
var);
851 broadcast_level_zero_bounds(all_variables);
853 model->GetOrCreate<GenericLiteralWatcher>()
854 ->RegisterLevelZeroModifiedVariablesCallback(broadcast_level_zero_bounds);
860void RegisterVariableBoundsLevelZeroImport(
861 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
863 CHECK(shared_bounds_manager !=
nullptr);
864 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
865 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
866 const int id = shared_bounds_manager->RegisterNewId();
868 const auto& import_level_zero_bounds = [&
model_proto, shared_bounds_manager,
869 model, integer_trail, id, mapping]() {
870 std::vector<int> model_variables;
871 std::vector<int64_t> new_lower_bounds;
872 std::vector<int64_t> new_upper_bounds;
873 shared_bounds_manager->GetChangedBounds(
874 id, &model_variables, &new_lower_bounds, &new_upper_bounds);
875 bool new_bounds_have_been_imported =
false;
876 for (
int i = 0; i < model_variables.size(); ++i) {
877 const int model_var = model_variables[i];
880 if (!mapping->IsInteger(model_var))
continue;
881 const IntegerVariable
var = mapping->Integer(model_var);
882 const IntegerValue new_lb(new_lower_bounds[i]);
883 const IntegerValue new_ub(new_upper_bounds[i]);
884 const IntegerValue old_lb = integer_trail->LowerBound(
var);
885 const IntegerValue old_ub = integer_trail->UpperBound(
var);
886 const bool changed_lb = new_lb > old_lb;
887 const bool changed_ub = new_ub < old_ub;
888 if (!changed_lb && !changed_ub)
continue;
890 new_bounds_have_been_imported =
true;
892 const IntegerVariableProto& var_proto =
894 const std::string& var_name =
895 var_proto.
name().empty()
896 ? absl::StrCat(
"anonymous_var(", model_var,
")")
898 LOG(
INFO) <<
" '" <<
model->Name() <<
"' imports new bounds for "
899 << var_name <<
": from [" << old_lb <<
", " << old_ub
900 <<
"] to [" << new_lb <<
", " << new_ub <<
"]";
914 if (new_bounds_have_been_imported &&
915 !
model->GetOrCreate<SatSolver>()->FinishPropagation()) {
920 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
921 import_level_zero_bounds);
926void RegisterObjectiveBestBoundExport(
927 IntegerVariable objective_var,
928 SharedResponseManager* shared_response_manager, Model*
model) {
929 auto* integer_trail =
model->Get<IntegerTrail>();
930 const auto broadcast_objective_lower_bound =
931 [objective_var, integer_trail, shared_response_manager,
932 model](
const std::vector<IntegerVariable>& unused) {
933 shared_response_manager->UpdateInnerObjectiveBounds(
934 model->Name(), integer_trail->LevelZeroLowerBound(objective_var),
935 integer_trail->LevelZeroUpperBound(objective_var));
937 if (!
model->Get<SatParameters>()->interleave_search()) {
938 shared_response_manager->Synchronize();
941 model->GetOrCreate<GenericLiteralWatcher>()
942 ->RegisterLevelZeroModifiedVariablesCallback(
943 broadcast_objective_lower_bound);
949void RegisterObjectiveBoundsImport(
950 SharedResponseManager* shared_response_manager, Model*
model) {
951 auto* solver =
model->GetOrCreate<SatSolver>();
952 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
953 auto* objective =
model->GetOrCreate<ObjectiveDefinition>();
955 const auto import_objective_bounds = [
name, solver, integer_trail, objective,
956 shared_response_manager]() {
957 if (solver->AssumptionLevel() != 0)
return true;
958 bool propagate =
false;
960 const IntegerValue external_lb =
961 shared_response_manager->SynchronizedInnerObjectiveLowerBound();
962 const IntegerValue current_lb =
963 integer_trail->LowerBound(objective->objective_var);
964 if (external_lb > current_lb) {
966 objective->objective_var, external_lb),
973 const IntegerValue external_ub =
974 shared_response_manager->SynchronizedInnerObjectiveUpperBound();
975 const IntegerValue current_ub =
976 integer_trail->UpperBound(objective->objective_var);
977 if (external_ub < current_ub) {
979 objective->objective_var, external_ub),
986 if (!propagate)
return true;
988 VLOG(3) <<
"'" <<
name <<
"' imports objective bounds: external ["
989 << objective->ScaleIntegerObjective(external_lb) <<
", "
990 << objective->ScaleIntegerObjective(external_ub) <<
"], current ["
991 << objective->ScaleIntegerObjective(current_lb) <<
", "
992 << objective->ScaleIntegerObjective(current_ub) <<
"]";
994 return solver->FinishPropagation();
997 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
998 import_objective_bounds);
1002 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1003 CHECK(shared_response_manager !=
nullptr);
1004 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1007 const auto unsat = [shared_response_manager, sat_solver,
model] {
1008 sat_solver->NotifyThatModelIsUnsat();
1009 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1010 absl::StrCat(
model->Name(),
" [loading]"));
1014 model->GetOrCreate<IntegerEncoder>()->DisableImplicationBetweenLiteral();
1016 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1017 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1018 const bool view_all_booleans_as_integers =
1038 if (sat_solver->IsModelUnsat())
return unsat();
1044 std::set<std::string> unsupported_types;
1045 int num_ignored_constraints = 0;
1047 if (mapping->ConstraintIsAlreadyLoaded(&
ct)) {
1048 ++num_ignored_constraints;
1063 if (sat_solver->FinishPropagation()) {
1064 Trail* trail =
model->GetOrCreate<Trail>();
1065 const int old_num_fixed = trail->Index();
1066 if (trail->Index() > old_num_fixed) {
1067 VLOG(3) <<
"Constraint fixed " << trail->Index() - old_num_fixed
1072 if (sat_solver->IsModelUnsat()) {
1073 VLOG(2) <<
"UNSAT during extraction (after adding '"
1079 if (num_ignored_constraints > 0) {
1080 VLOG(3) << num_ignored_constraints <<
" constraints were skipped.";
1082 if (!unsupported_types.empty()) {
1083 VLOG(1) <<
"There is unsupported constraints types in this model: ";
1084 for (
const std::string& type : unsupported_types) {
1085 VLOG(1) <<
" - " << type;
1090 model->GetOrCreate<IntegerEncoder>()
1091 ->AddAllImplicationsBetweenAssociatedLiterals();
1092 if (!sat_solver->FinishPropagation())
return unsat();
1098 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1099 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1103 const LinearRelaxation relaxation =
1105 const int num_lp_constraints = relaxation.linear_constraints.size();
1106 if (num_lp_constraints == 0)
return;
1107 auto* feasibility_pump =
model->GetOrCreate<FeasibilityPump>();
1108 for (
int i = 0; i < num_lp_constraints; i++) {
1109 feasibility_pump->AddLinearConstraint(relaxation.linear_constraints[i]);
1114 const IntegerVariable
var =
1117 feasibility_pump->SetObjectiveCoefficient(
var, IntegerValue(coeff));
1127 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1132 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1133 const auto unsat = [shared_response_manager, sat_solver,
model] {
1134 sat_solver->NotifyThatModelIsUnsat();
1135 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1136 absl::StrCat(
model->Name(),
" [loading]"));
1139 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1140 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1146 if (
model->Mutable<PrecedencesPropagator>() !=
nullptr &&
1148 model->Mutable<PrecedencesPropagator>()
1149 ->AddGreaterThanAtLeastOneOfConstraints(
model);
1150 if (!sat_solver->FinishPropagation())
return unsat();
1157 Prober* prober =
model->GetOrCreate<Prober>();
1158 prober->ProbeBooleanVariables(1.0);
1159 if (
model->GetOrCreate<SatSolver>()->IsModelUnsat()) {
1162 if (!
model->GetOrCreate<BinaryImplicationGraph>()
1163 ->ComputeTransitiveReduction()) {
1176 std::vector<std::pair<IntegerVariable, int64_t>> terms;
1177 terms.reserve(obj.vars_size());
1178 for (
int i = 0; i < obj.vars_size(); ++i) {
1180 std::make_pair(mapping->Integer(obj.vars(i)), obj.coeffs(i)));
1183 objective_var = GetOrCreateVariableWithTightBound(terms,
model);
1185 objective_var = GetOrCreateVariableGreaterOrEqualToSumOf(terms,
model);
1193 auto* objective_definition =
model->GetOrCreate<ObjectiveDefinition>();
1195 objective_definition->scaling_factor = objective_proto.scaling_factor();
1196 if (objective_definition->scaling_factor == 0.0) {
1197 objective_definition->scaling_factor = 1.0;
1199 objective_definition->offset = objective_proto.offset();
1200 objective_definition->objective_var = objective_var;
1202 const int size = objective_proto.vars_size();
1203 objective_definition->vars.resize(size);
1204 objective_definition->coeffs.resize(size);
1205 for (
int i = 0; i < objective_proto.vars_size(); ++i) {
1208 objective_definition->vars[i] = mapping->Integer(objective_proto.vars(i));
1209 objective_definition->coeffs[i] = IntegerValue(objective_proto.coeffs(i));
1212 const int ref = objective_proto.vars(i);
1213 if (mapping->IsInteger(ref)) {
1214 const IntegerVariable
var = mapping->Integer(objective_proto.vars(i));
1215 objective_definition->objective_impacting_variables.insert(
1221 model->TakeOwnership(
1222 new LevelZeroEquality(objective_var, objective_definition->vars,
1223 objective_definition->coeffs,
model));
1229 const Domain automatic_domain =
1230 model->GetOrCreate<IntegerTrail>()->InitialVariableDomain(
1234 VLOG(3) <<
"Automatic internal objective domain: " << automatic_domain;
1235 VLOG(3) <<
"User specified internal objective domain: " << user_domain;
1237 const bool ok =
model->GetOrCreate<IntegerTrail>()->UpdateInitialDomain(
1238 objective_var, user_domain);
1240 VLOG(2) <<
"UNSAT due to the objective domain.";
1251 if (!automatic_domain.IsIncludedIn(user_domain)) {
1252 std::vector<IntegerVariable> vars;
1253 std::vector<int64_t> coeffs;
1255 for (
int i = 0; i < obj.vars_size(); ++i) {
1256 vars.push_back(mapping->Integer(obj.vars(i)));
1257 coeffs.push_back(obj.coeffs(i));
1259 vars.push_back(objective_var);
1260 coeffs.push_back(-1);
1268 "Initial num_bool: ", sat_solver->NumVariables());
1269 if (!sat_solver->FinishPropagation())
return unsat();
1273 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1274 shared_response_manager->UpdateInnerObjectiveBounds(
1275 absl::StrCat(
model->Name(),
" initial_propagation"),
1276 integer_trail->LowerBound(objective_var),
1277 integer_trail->UpperBound(objective_var));
1280 RegisterObjectiveBestBoundExport(objective_var, shared_response_manager,
1286 if (
model->GetOrCreate<SatParameters>()->share_objective_bounds()) {
1287 RegisterObjectiveBoundsImport(shared_response_manager,
model);
1293 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1294 auto* lp_dispatcher =
model->GetOrCreate<LinearProgrammingDispatcher>();
1295 auto* lp_vars =
model->GetOrCreate<LPVariables>();
1296 IntegerVariable size = integer_trail->NumIntegerVariables();
1297 for (IntegerVariable positive_var(0); positive_var < size;
1298 positive_var += 2) {
1300 lp_var.positive_var = positive_var;
1302 mapping->GetProtoVariableFromIntegerVariable(positive_var);
1305 if (lp_var.model_var >= 0) {
1306 lp_vars->vars.push_back(lp_var);
1307 lp_vars->model_vars_size =
1308 std::max(lp_vars->model_vars_size, lp_var.model_var + 1);
1313 auto* search_heuristics =
model->GetOrCreate<SearchHeuristics>();
1317 search_heuristics->fixed_search =
1319 search_heuristics->fixed_search,
model);
1323 std::vector<BooleanOrIntegerVariable> vars;
1324 std::vector<IntegerValue> values;
1328 BooleanOrIntegerVariable
var;
1329 if (mapping->IsBoolean(ref)) {
1330 var.bool_var = mapping->Literal(ref).Variable();
1332 var.int_var = mapping->Integer(ref);
1334 vars.push_back(
var);
1343 const std::string solution_info =
model->Name();
1345 shared_response_manager]() {
1348 response.set_solution_info(solution_info);
1352 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1353 CoreBasedOptimizer* core =
1354 new CoreBasedOptimizer(objective_var, objective.vars, objective.coeffs,
1355 solution_observer,
model);
1356 model->Register<CoreBasedOptimizer>(core);
1357 model->TakeOwnership(core);
1368 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1369 if (shared_response_manager->ProblemIsSolved())
return;
1371 const std::string& solution_info =
model->Name();
1373 &shared_response_manager]() {
1376 response.set_solution_info(solution_info);
1383 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1385 const SatParameters&
parameters = *
model->GetOrCreate<SatParameters>();
1387 std::vector<BooleanVariable> bool_vars;
1388 std::vector<IntegerVariable> int_vars;
1389 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1390 absl::flat_hash_set<BooleanVariable> visited;
1392 if (mapping.IsBoolean(v)) {
1393 const BooleanVariable bool_var = mapping.Literal(v).Variable();
1394 if (!visited.contains(bool_var)) {
1395 visited.insert(bool_var);
1396 bool_vars.push_back(bool_var);
1399 IntegerVariable
var = mapping.Integer(v);
1400 if (integer_trail->IsFixed(
var))
continue;
1401 int_vars.push_back(
var);
1410 solution_observer();
1415 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1419 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1424 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1425 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1427 std::vector<int> core_in_proto_format;
1428 for (
const Literal l : core) {
1429 core_in_proto_format.push_back(
1430 mapping.GetProtoVariableFromBooleanVariable(l.Variable()));
1431 if (!l.IsPositive()) {
1432 core_in_proto_format.back() =
NegatedRef(core_in_proto_format.back());
1435 shared_response_manager->AddUnsatCore(core_in_proto_format);
1439 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1440 const IntegerVariable objective_var = objective.objective_var;
1444 auto* search =
model->GetOrCreate<LbTreeSearch>();
1445 status = search->Search(solution_observer);
1451 objective, solution_observer,
model);
1453 status =
model->Mutable<CoreBasedOptimizer>()->Optimize();
1460 solution_observer,
model);
1463 objective_var, solution_observer,
model);
1471 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1478 shared_response_manager->SetStatsFromModel(
model);
1486 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1487 if (shared_response_manager->ProblemIsSolved())
return;
1500 const SatParameters saved_params = *
parameters;
1509 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1513 const std::string& solution_info =
model->Name();
1517 response.set_solution_info(absl::StrCat(solution_info,
" [hint]"));
1526 const IntegerVariable objective_var =
1527 model->GetOrCreate<ObjectiveDefinition>()->objective_var;
1528 model->GetOrCreate<SatSolver>()->Backtrack(0);
1529 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1530 if (!integer_trail->Enqueue(
1533 shared_response_manager->GetInnerObjectiveUpperBound()),
1535 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1536 absl::StrCat(solution_info,
" [hint]"));
1537 shared_response_manager->SetStatsFromModel(
model);
1547 !
model->GetOrCreate<TimeLimit>()->LimitReached() &&
1549 LOG(
FATAL) <<
"QuickSolveWithHint() didn't find a feasible solution. "
1557void MinimizeL1DistanceWithHint(
const CpModelProto&
model_proto, Model*
model) {
1561 local_model.Register<ModelSharedTimeLimit>(
1562 model->GetOrCreate<ModelSharedTimeLimit>());
1567 auto* shared_response_manager =
model->GetOrCreate<SharedResponseManager>();
1568 if (shared_response_manager->ProblemIsSolved())
return;
1570 auto*
parameters = local_model.GetOrCreate<SatParameters>();
1577 const SatParameters saved_params = *
model->GetOrCreate<SatParameters>();
1592 const int new_var_index = updated_model_proto.variables_size();
1593 IntegerVariableProto* var_proto = updated_model_proto.add_variables();
1595 const int64_t max_domain =
1599 var_proto->add_domain(min_domain);
1600 var_proto->add_domain(max_domain);
1603 ConstraintProto*
const linear_constraint_proto =
1604 updated_model_proto.add_constraints();
1605 LinearConstraintProto* linear = linear_constraint_proto->mutable_linear();
1606 linear->add_vars(new_var_index);
1607 linear->add_coeffs(1);
1608 linear->add_vars(
var);
1609 linear->add_coeffs(-1);
1610 linear->add_domain(-
value);
1611 linear->add_domain(-
value);
1614 const int abs_var_index = updated_model_proto.variables_size();
1615 IntegerVariableProto* abs_var_proto = updated_model_proto.add_variables();
1616 const int64_t abs_min_domain = 0;
1617 const int64_t abs_max_domain =
1618 std::max(std::abs(min_domain), std::abs(max_domain));
1619 abs_var_proto->add_domain(abs_min_domain);
1620 abs_var_proto->add_domain(abs_max_domain);
1621 auto* abs_ct = updated_model_proto.add_constraints()->mutable_lin_max();
1622 abs_ct->mutable_target()->add_vars(abs_var_index);
1623 abs_ct->mutable_target()->add_coeffs(1);
1624 LinearExpressionProto* left = abs_ct->add_exprs();
1625 left->add_vars(new_var_index);
1626 left->add_coeffs(1);
1627 LinearExpressionProto* right = abs_ct->add_exprs();
1628 right->add_vars(new_var_index);
1629 right->add_coeffs(-1);
1631 updated_model_proto.mutable_objective()->add_vars(abs_var_index);
1632 updated_model_proto.mutable_objective()->add_coeffs(1);
1635 auto* local_response_manager =
1636 local_model.GetOrCreate<SharedResponseManager>();
1637 local_response_manager->InitializeObjective(updated_model_proto);
1640 LoadCpModel(updated_model_proto, &local_model);
1643 const auto& mapping = *local_model.GetOrCreate<CpModelMapping>();
1645 mapping.Literals(updated_model_proto.assumptions()), &local_model);
1647 const std::string& solution_info =
model->Name();
1652 CpSolverResponse updated_response;
1653 FillSolutionInResponse(updated_model_proto, local_model,
1655 LOG(
INFO) <<
"Found solution with repaired hint penalty = "
1659 response.set_solution_info(absl::StrCat(solution_info,
" [repaired]"));
1668void PostsolveResponseWithFullSolver(
int num_variables_in_original_model,
1669 CpModelProto mapping_proto,
1670 const std::vector<int>& postsolve_mapping,
1671 std::vector<int64_t>* solution) {
1676 for (
int i = 0; i < solution->size(); ++i) {
1677 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1678 var_proto->clear_domain();
1679 var_proto->add_domain((*solution)[i]);
1680 var_proto->add_domain((*solution)[i]);
1686 Model postsolve_model;
1689 SatParameters& params = *postsolve_model.GetOrCreate<SatParameters>();
1690 params.set_linearization_level(0);
1691 params.set_cp_model_probing_level(0);
1694 LoadCpModel(mapping_proto, &postsolve_model);
1695 SolveLoadedCpModel(mapping_proto, &postsolve_model);
1696 const CpSolverResponse postsolve_response =
1697 postsolve_model.GetOrCreate<SharedResponseManager>()->GetResponse();
1703 CHECK_LE(num_variables_in_original_model,
1704 postsolve_response.solution().size());
1706 postsolve_response.solution().begin(),
1707 postsolve_response.solution().begin() + num_variables_in_original_model);
1710void PostsolveResponseWrapper(
const SatParameters& params,
1711 int num_variable_in_original_model,
1712 const CpModelProto& mapping_proto,
1713 const std::vector<int>& postsolve_mapping,
1714 std::vector<int64_t>* solution) {
1715 if (params.debug_postsolve_with_full_solver()) {
1716 PostsolveResponseWithFullSolver(num_variable_in_original_model,
1717 mapping_proto, postsolve_mapping, solution);
1720 postsolve_mapping, solution);
1725CpSolverResponse SolvePureSatModel(
const CpModelProto&
model_proto,
1727 SolverLogger* logger) {
1728 std::unique_ptr<SatSolver> solver(
new SatSolver());
1731 model->GetOrCreate<TimeLimit>()->ResetLimitFromParameters(
parameters);
1734 std::unique_ptr<DratProofHandler> drat_proof_handler;
1735#if !defined(__PORTABLE_PLATFORM__)
1736 if (!absl::GetFlag(FLAGS_drat_output).empty() ||
1737 absl::GetFlag(FLAGS_drat_check)) {
1738 if (!absl::GetFlag(FLAGS_drat_output).empty()) {
1742 drat_proof_handler = absl::make_unique<DratProofHandler>(
1743 false, output, absl::GetFlag(FLAGS_drat_check));
1745 drat_proof_handler = absl::make_unique<DratProofHandler>();
1747 solver->SetDratProofHandler(drat_proof_handler.get());
1751 auto get_literal = [](
int ref) {
1752 if (ref >= 0)
return Literal(BooleanVariable(ref),
true);
1753 return Literal(BooleanVariable(
NegatedRef(ref)),
false);
1756 std::vector<Literal> temp;
1758 solver->SetNumVariables(num_variables);
1759 if (drat_proof_handler !=
nullptr) {
1760 drat_proof_handler->SetNumVariables(num_variables);
1764 for (
int ref = 0; ref < num_variables; ++ref) {
1766 if (domain.IsFixed()) {
1767 const Literal ref_literal =
1768 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
1769 drat_proof_handler->AddProblemClause({ref_literal});
1773 switch (
ct.constraint_case()) {
1774 case ConstraintProto::ConstraintCase::kBoolAnd: {
1775 if (
ct.enforcement_literal_size() == 0) {
1776 for (
const int ref :
ct.bool_and().literals()) {
1777 drat_proof_handler->AddProblemClause({get_literal(ref)});
1781 const Literal not_a =
1782 get_literal(
ct.enforcement_literal(0)).Negated();
1783 for (
const int ref :
ct.bool_and().literals()) {
1784 drat_proof_handler->AddProblemClause({not_a, get_literal(ref)});
1789 case ConstraintProto::ConstraintCase::kBoolOr:
1791 for (
const int ref :
ct.bool_or().literals()) {
1792 temp.push_back(get_literal(ref));
1794 for (
const int ref :
ct.enforcement_literal()) {
1795 temp.push_back(get_literal(ref).Negated());
1797 drat_proof_handler->AddProblemClause(temp);
1806 switch (
ct.constraint_case()) {
1807 case ConstraintProto::ConstraintCase::kBoolAnd: {
1808 if (
ct.enforcement_literal_size() == 0) {
1809 for (
const int ref :
ct.bool_and().literals()) {
1810 const Literal
b = get_literal(ref);
1811 solver->AddUnitClause(
b);
1815 const Literal not_a =
1816 get_literal(
ct.enforcement_literal(0)).Negated();
1817 for (
const int ref :
ct.bool_and().literals()) {
1818 const Literal
b = get_literal(ref);
1819 solver->AddProblemClause({not_a,
b});
1824 case ConstraintProto::ConstraintCase::kBoolOr:
1826 for (
const int ref :
ct.bool_or().literals()) {
1827 temp.push_back(get_literal(ref));
1829 for (
const int ref :
ct.enforcement_literal()) {
1830 temp.push_back(get_literal(ref).Negated());
1832 solver->AddProblemClause(temp);
1840 for (
int ref = 0; ref < num_variables; ++ref) {
1842 if (domain.Min() == domain.Max()) {
1843 const Literal ref_literal =
1844 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
1845 solver->AddUnitClause(ref_literal);
1852 std::vector<bool> solution;
1854 &solution, drat_proof_handler.get(), logger);
1857 for (
int ref = 0; ref < num_variables; ++ref) {
1858 response.add_solution(solution[ref]);
1862 status = solver->SolveWithTimeLimit(
model->GetOrCreate<TimeLimit>());
1865 for (
int ref = 0; ref < num_variables; ++ref) {
1867 solver->Assignment().LiteralIsTrue(get_literal(ref)) ? 1 : 0);
1874 model->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
1875 solver->model()->GetOrCreate<TimeLimit>()->GetElapsedDeterministicTime());
1894 LOG(
FATAL) <<
"Unexpected SatSolver::Status " << status;
1896 response.set_num_booleans(solver->NumVariables());
1897 response.set_num_branches(solver->num_branches());
1898 response.set_num_conflicts(solver->num_failures());
1899 response.set_num_binary_propagations(solver->num_propagations());
1900 response.set_num_integer_propagations(0);
1903 model->Get<TimeLimit>()->GetElapsedDeterministicTime());
1909 absl::GetFlag(FLAGS_max_drat_time_in_seconds));
1910 switch (drat_status) {
1912 LOG(
INFO) <<
"DRAT status: UNKNOWN";
1915 LOG(
INFO) <<
"DRAT status: VALID";
1918 LOG(ERROR) <<
"DRAT status: INVALID";
1924 LOG(
INFO) <<
"DRAT wall time: " << drat_timer.
Get();
1925 }
else if (drat_proof_handler !=
nullptr) {
1928 LOG(
INFO) <<
"DRAT status: NA";
1929 LOG(
INFO) <<
"DRAT wall time: NA";
1930 LOG(
INFO) <<
"DRAT user time: NA";
1935#if !defined(__PORTABLE_PLATFORM__)
1938struct SharedClasses {
1949 bool SearchIsDone() {
1950 if (
response->ProblemIsSolved())
return true;
1957class FullProblemSolver :
public SubSolver {
1959 FullProblemSolver(
const std::string&
name,
1960 const SatParameters& local_parameters,
bool split_in_chunks,
1961 SharedClasses* shared)
1964 split_in_chunks_(split_in_chunks),
1965 local_model_(
absl::make_unique<Model>(
name)) {
1967 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
1968 shared_->time_limit->UpdateLocalLimit(
1969 local_model_->GetOrCreate<TimeLimit>());
1971 if (shared->response !=
nullptr) {
1972 local_model_->Register<SharedResponseManager>(shared->response);
1975 if (shared->relaxation_solutions !=
nullptr) {
1976 local_model_->Register<SharedRelaxationSolutionRepository>(
1977 shared->relaxation_solutions);
1980 if (shared->lp_solutions !=
nullptr) {
1981 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
1984 if (shared->incomplete_solutions !=
nullptr) {
1985 local_model_->Register<SharedIncompleteSolutionManager>(
1986 shared->incomplete_solutions);
1990 bool TaskIsAvailable()
override {
1991 if (shared_->SearchIsDone())
return false;
1993 absl::MutexLock mutex_lock(&mutex_);
1994 return previous_task_is_completed_;
1997 std::function<void()> GenerateTask(int64_t task_id)
override {
1999 absl::MutexLock mutex_lock(&mutex_);
2000 previous_task_is_completed_ =
false;
2003 if (solving_first_chunk_) {
2004 LoadCpModel(*shared_->model_proto, local_model_.get());
2010 if (shared_->bounds !=
nullptr) {
2011 RegisterVariableBoundsLevelZeroExport(
2012 *shared_->model_proto, shared_->bounds, local_model_.get());
2013 RegisterVariableBoundsLevelZeroImport(
2014 *shared_->model_proto, shared_->bounds, local_model_.get());
2017 if (local_model_->GetOrCreate<SatParameters>()->repair_hint()) {
2018 MinimizeL1DistanceWithHint(*shared_->model_proto, local_model_.get());
2020 QuickSolveWithHint(*shared_->model_proto, local_model_.get());
2024 solving_first_chunk_ =
false;
2026 if (split_in_chunks_) {
2028 absl::MutexLock mutex_lock(&mutex_);
2029 previous_task_is_completed_ =
true;
2034 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2035 if (split_in_chunks_) {
2038 auto* params = local_model_->GetOrCreate<SatParameters>();
2039 params->set_max_deterministic_time(1);
2040 time_limit->ResetLimitFromParameters(*params);
2041 shared_->time_limit->UpdateLocalLimit(
time_limit);
2044 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2045 SolveLoadedCpModel(*shared_->model_proto, local_model_.get());
2047 absl::MutexLock mutex_lock(&mutex_);
2048 deterministic_time_since_last_synchronize_ +=
2049 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2053 if (shared_->SearchIsDone()) {
2054 shared_->time_limit->Stop();
2059 if (split_in_chunks_) {
2060 absl::MutexLock mutex_lock(&mutex_);
2061 previous_task_is_completed_ =
true;
2069 local_model_.reset();
2076 void Synchronize()
override {
2077 absl::MutexLock mutex_lock(&mutex_);
2078 deterministic_time_ += deterministic_time_since_last_synchronize_;
2079 shared_->time_limit->AdvanceDeterministicTime(
2080 deterministic_time_since_last_synchronize_);
2081 deterministic_time_since_last_synchronize_ = 0.0;
2084 std::string StatisticsString()
const override {
2088 if (local_model_ ==
nullptr)
return std::string();
2091 *local_model_->GetOrCreate<LinearProgrammingConstraintCollection>();
2092 std::string lp_stats;
2094 local_model_->GetOrCreate<SatParameters>()->linearization_level() >=
2096 for (
const auto* lp : lps) {
2097 const std::string raw_statistics = lp->Statistics();
2098 const std::vector<absl::string_view> lines =
2099 absl::StrSplit(raw_statistics,
'\n', absl::SkipEmpty());
2100 for (
const absl::string_view& line : lines) {
2101 absl::StrAppend(&lp_stats,
" ", line,
"\n");
2109 SharedClasses* shared_;
2110 const bool split_in_chunks_;
2111 std::unique_ptr<Model> local_model_;
2115 bool solving_first_chunk_ =
true;
2118 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2120 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2123class FeasibilityPumpSolver :
public SubSolver {
2125 FeasibilityPumpSolver(
const SatParameters& local_parameters,
2126 SharedClasses* shared)
2127 : SubSolver(
"feasibility_pump"),
2129 local_model_(
absl::make_unique<Model>(name_)) {
2131 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
2132 shared_->time_limit->UpdateLocalLimit(
2133 local_model_->GetOrCreate<TimeLimit>());
2135 if (shared->response !=
nullptr) {
2136 local_model_->Register<SharedResponseManager>(shared->response);
2139 if (shared->relaxation_solutions !=
nullptr) {
2140 local_model_->Register<SharedRelaxationSolutionRepository>(
2141 shared->relaxation_solutions);
2144 if (shared->lp_solutions !=
nullptr) {
2145 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
2148 if (shared->incomplete_solutions !=
nullptr) {
2149 local_model_->Register<SharedIncompleteSolutionManager>(
2150 shared->incomplete_solutions);
2154 if (shared_->bounds !=
nullptr) {
2155 RegisterVariableBoundsLevelZeroImport(
2156 *shared_->model_proto, shared_->bounds, local_model_.get());
2160 bool TaskIsAvailable()
override {
2161 if (shared_->SearchIsDone())
return false;
2162 absl::MutexLock mutex_lock(&mutex_);
2163 return previous_task_is_completed_;
2166 std::function<void()> GenerateTask(int64_t task_id)
override {
2169 absl::MutexLock mutex_lock(&mutex_);
2170 if (!previous_task_is_completed_)
return;
2171 previous_task_is_completed_ =
false;
2174 absl::MutexLock mutex_lock(&mutex_);
2175 if (solving_first_chunk_) {
2176 LoadFeasibilityPump(*shared_->model_proto, local_model_.get());
2179 if (local_model_->Get<FeasibilityPump>() ==
nullptr)
return;
2180 solving_first_chunk_ =
false;
2182 previous_task_is_completed_ =
true;
2187 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2188 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2189 auto* feasibility_pump = local_model_->Mutable<FeasibilityPump>();
2190 if (!feasibility_pump->Solve()) {
2191 shared_->response->NotifyThatImprovingProblemIsInfeasible(name_);
2195 absl::MutexLock mutex_lock(&mutex_);
2196 deterministic_time_since_last_synchronize_ +=
2197 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2201 if (shared_->SearchIsDone()) {
2202 shared_->time_limit->Stop();
2206 absl::MutexLock mutex_lock(&mutex_);
2207 previous_task_is_completed_ =
true;
2211 void Synchronize()
override {
2212 absl::MutexLock mutex_lock(&mutex_);
2213 deterministic_time_ += deterministic_time_since_last_synchronize_;
2214 shared_->time_limit->AdvanceDeterministicTime(
2215 deterministic_time_since_last_synchronize_);
2216 deterministic_time_since_last_synchronize_ = 0.0;
2222 SharedClasses* shared_;
2223 std::unique_ptr<Model> local_model_;
2229 bool solving_first_chunk_ ABSL_GUARDED_BY(mutex_) =
true;
2231 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2233 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2237class LnsSolver :
public SubSolver {
2239 LnsSolver(std::unique_ptr<NeighborhoodGenerator> generator,
2241 NeighborhoodGeneratorHelper* helper, SharedClasses* shared)
2242 : SubSolver(generator->
name()),
2243 generator_(
std::move(generator)),
2248 bool TaskIsAvailable()
override {
2249 if (shared_->SearchIsDone())
return false;
2250 return generator_->ReadyToGenerate();
2253 std::function<void()> GenerateTask(int64_t task_id)
override {
2254 return [task_id,
this]() {
2255 if (shared_->SearchIsDone())
return;
2260 const int32_t low =
static_cast<int32_t
>(task_id);
2261 const int32_t high =
static_cast<int32_t
>(task_id >> 32);
2262 std::seed_seq seed{low, high, parameters_.random_seed()};
2265 NeighborhoodGenerator::SolveData data;
2266 data.difficulty = generator_->difficulty();
2267 data.deterministic_limit = generator_->deterministic_limit();
2270 CpSolverResponse base_response;
2272 const SharedSolutionRepository<int64_t>& repo =
2273 shared_->response->SolutionsRepository();
2274 if (repo.NumSolutions() > 0) {
2276 const SharedSolutionRepository<int64_t>::Solution solution =
2277 repo.GetRandomBiasedSolution(random);
2278 for (
const int64_t
value : solution.variable_values) {
2279 base_response.add_solution(
value);
2284 data.initial_best_objective = repo.GetSolution(0).rank;
2285 data.base_objective = solution.rank;
2294 data.initial_best_objective =
2295 shared_->response->GetInnerObjectiveUpperBound();
2296 data.base_objective = data.initial_best_objective;
2300 Neighborhood neighborhood =
2301 generator_->Generate(base_response, data.difficulty, random);
2303 if (!neighborhood.is_generated)
return;
2305 data.neighborhood_id = neighborhood.id;
2307 const int64_t num_calls =
std::max(int64_t{1}, generator_->num_calls());
2308 const double fully_solved_proportion =
2309 static_cast<double>(generator_->num_fully_solved_calls()) /
2310 static_cast<double>(num_calls);
2311 std::string source_info =
name();
2312 if (!neighborhood.source_info.empty()) {
2313 absl::StrAppend(&source_info,
"_", neighborhood.source_info);
2315 const std::string solution_info = absl::StrFormat(
2316 "%s(d=%0.2f s=%i t=%0.2f p=%0.2f)", source_info, data.difficulty,
2317 task_id, data.deterministic_limit, fully_solved_proportion);
2319 SatParameters local_params(parameters_);
2320 local_params.set_max_deterministic_time(data.deterministic_limit);
2321 local_params.set_stop_after_first_solution(
false);
2322 local_params.set_log_search_progress(
false);
2323 local_params.set_cp_model_probing_level(0);
2324 local_params.set_symmetry_level(0);
2325 local_params.set_solution_pool_size(0);
2327 Model local_model(solution_info);
2328 *(local_model.GetOrCreate<SatParameters>()) = local_params;
2329 TimeLimit* local_time_limit = local_model.GetOrCreate<TimeLimit>();
2330 local_time_limit->ResetLimitFromParameters(local_params);
2331 shared_->time_limit->UpdateLocalLimit(local_time_limit);
2334 CpModelProto lns_fragment;
2335 CpModelProto mapping_proto;
2336 auto context = absl::make_unique<PresolveContext>(
2337 &local_model, &lns_fragment, &mapping_proto);
2339 *lns_fragment.mutable_variables() = neighborhood.delta.variables();
2341 ModelCopy copier(
context.get());
2344 if (!copier.ImportAndSimplifyConstraints(
2345 helper_->ModelProto(), neighborhood.constraints_to_ignore)) {
2350 if (!neighborhood.delta.constraints().empty() &&
2351 !copier.ImportAndSimplifyConstraints(neighborhood.delta, {})) {
2358 helper_->ModelProto(),
context.get());
2359 lns_fragment.set_name(absl::StrCat(
"lns_", task_id));
2362 if (neighborhood.delta.has_solution_hint()) {
2363 *lns_fragment.mutable_solution_hint() =
2364 neighborhood.delta.solution_hint();
2367 CpModelProto debug_copy;
2368 if (absl::GetFlag(FLAGS_cp_model_dump_problematic_lns)) {
2371 debug_copy = lns_fragment;
2374#if !defined(__PORTABLE_PLATFORM__)
2377 if (absl::GetFlag(FLAGS_cp_model_dump_lns)) {
2379 const std::string lns_name =
2380 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2381 lns_fragment.name(),
".pb.txt");
2382 LOG(
INFO) <<
"Dumping LNS model to '" << lns_name <<
"'.";
2386 std::vector<int> postsolve_mapping;
2392 neighborhood.delta.Clear();
2397 auto* local_response_manager =
2398 local_model.GetOrCreate<SharedResponseManager>();
2399 local_response_manager->InitializeObjective(lns_fragment);
2402 LoadCpModel(lns_fragment, &local_model);
2403 QuickSolveWithHint(lns_fragment, &local_model);
2404 SolveLoadedCpModel(lns_fragment, &local_model);
2406 local_response_manager->MutableResponse()->set_status(presolve_status);
2408 CpSolverResponse local_response = local_response_manager->GetResponse();
2412 if (local_params.cp_model_presolve() &&
2415 std::vector<int64_t> solution(local_response.solution().begin(),
2416 local_response.solution().end());
2417 PostsolveResponseWrapper(local_params,
2418 helper_->ModelProto().variables_size(),
2419 mapping_proto, postsolve_mapping, &solution);
2420 local_response.mutable_solution()->Assign(solution.begin(),
2424 data.status = local_response.status();
2425 data.deterministic_time = local_time_limit->GetElapsedDeterministicTime();
2427 bool new_solution =
false;
2428 bool display_lns_info =
false;
2429 if (generator_->IsRelaxationGenerator()) {
2430 bool has_feasible_solution =
false;
2433 has_feasible_solution =
true;
2437 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2438 local_response.solution_info());
2441 if (shared_->model_proto->has_objective()) {
2444 const IntegerValue current_obj_lb =
2445 shared_->response->GetInnerObjectiveLowerBound();
2447 const IntegerValue local_obj_lb =
2448 local_response_manager->GetInnerObjectiveLowerBound();
2451 lns_fragment.objective(), local_obj_lb.value());
2454 const IntegerValue new_inner_obj_lb = IntegerValue(
2456 scaled_local_obj_bound) -
2458 data.new_objective_bound = new_inner_obj_lb;
2459 data.initial_best_objective_bound = current_obj_lb;
2460 if (new_inner_obj_lb > current_obj_lb) {
2461 shared_->response->UpdateInnerObjectiveBounds(
2468 if (has_feasible_solution) {
2470 *shared_->model_proto,
2471 std::vector<int64_t>(local_response.solution().begin(),
2472 local_response.solution().end()))) {
2473 shared_->response->NewSolution(local_response,
2478 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2479 local_response.solution_info());
2480 shared_->time_limit->Stop();
2483 shared_->relaxation_solutions->NewRelaxationSolution(local_response);
2486 const std::vector<int64_t> solution(local_response.solution().begin(),
2487 local_response.solution().end());
2489 if (!solution.empty()) {
2495 const bool feasible =
2498 if (absl::GetFlag(FLAGS_cp_model_dump_problematic_lns)) {
2499 const std::string
name =
2500 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2501 debug_copy.name(),
".pb.txt");
2502 LOG(
INFO) <<
"Dumping problematic LNS model to '" <<
name <<
"'.";
2505 LOG(
FATAL) <<
"Infeasible LNS solution! " << solution_info
2506 <<
" solved with params "
2507 << local_params.ShortDebugString();
2523 !shared_->model_proto->has_symmetry() && !solution.empty() &&
2524 neighborhood.is_simple &&
2525 !neighborhood.variables_that_can_be_fixed_to_local_optimum
2527 display_lns_info =
true;
2528 shared_->bounds->FixVariablesFromPartialSolution(
2530 neighborhood.variables_that_can_be_fixed_to_local_optimum);
2534 data.new_objective = data.base_objective;
2538 shared_->model_proto->objective(), local_response));
2545 const std::vector<int64_t> base_solution(
2546 base_response.solution().begin(), base_response.solution().end());
2547 if (solution != base_solution) {
2548 new_solution =
true;
2549 shared_->response->NewSolution(local_response,
nullptr);
2552 if (!neighborhood.is_reduced &&
2555 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2556 local_response.solution_info());
2557 shared_->time_limit->Stop();
2561 generator_->AddSolveData(data);
2564 auto* logger = shared_->global_model->GetOrCreate<SolverLogger>();
2565 std::string s = absl::StrCat(
" LNS ",
name(),
":");
2568 shared_->model_proto->objective(),
2572 shared_->model_proto->objective(),
2575 absl::StrAppend(&s,
" [new_sol:", base_obj,
" -> ", new_obj,
"]");
2577 if (neighborhood.is_simple) {
2579 &s,
" [",
"relaxed:", neighborhood.num_relaxed_variables,
2580 " in_obj:", neighborhood.num_relaxed_variables_in_objective,
2582 neighborhood.variables_that_can_be_fixed_to_local_optimum.size(),
2585 SOLVER_LOG(logger, s,
" [d:", data.difficulty,
", id:", task_id,
2586 ", dtime:", data.deterministic_time,
"/",
2587 data.deterministic_limit,
2588 ", status:", ProtoEnumToString<CpSolverStatus>(data.status),
2589 ", #calls:", generator_->num_calls(),
2590 ", p:", fully_solved_proportion,
"]");
2595 void Synchronize()
override {
2596 generator_->Synchronize();
2597 const double old = deterministic_time_;
2598 deterministic_time_ = generator_->deterministic_time();
2599 shared_->time_limit->AdvanceDeterministicTime(deterministic_time_ - old);
2605 std::unique_ptr<NeighborhoodGenerator> generator_;
2606 NeighborhoodGeneratorHelper* helper_;
2607 const SatParameters parameters_;
2608 SharedClasses* shared_;
2611void SolveCpModelParallel(
const CpModelProto&
model_proto,
2616 <<
"Enumerating all solutions in parallel is not supported.";
2618 std::unique_ptr<SharedBoundsManager> shared_bounds_manager;
2620 shared_bounds_manager = absl::make_unique<SharedBoundsManager>(
model_proto);
2623 std::unique_ptr<SharedRelaxationSolutionRepository>
2624 shared_relaxation_solutions;
2626 shared_relaxation_solutions =
2627 absl::make_unique<SharedRelaxationSolutionRepository>(
2630 shared_relaxation_solutions.get());
2633 auto shared_lp_solutions = absl::make_unique<SharedLPSolutionRepository>(
2639 std::unique_ptr<SharedIncompleteSolutionManager> shared_incomplete_solutions;
2644 if (use_feasibility_pump) {
2645 shared_incomplete_solutions =
2646 absl::make_unique<SharedIncompleteSolutionManager>();
2648 shared_incomplete_solutions.get());
2651 SharedClasses shared;
2655 shared.bounds = shared_bounds_manager.get();
2657 shared.relaxation_solutions = shared_relaxation_solutions.get();
2658 shared.lp_solutions = shared_lp_solutions.get();
2659 shared.incomplete_solutions = shared_incomplete_solutions.get();
2663 std::vector<std::unique_ptr<SubSolver>> subsolvers;
2666 subsolvers.push_back(absl::make_unique<SynchronizationPoint>([&shared]() {
2667 shared.response->Synchronize();
2668 shared.response->MutableSolutionsRepository()->Synchronize();
2669 if (shared.bounds !=
nullptr) {
2670 shared.bounds->Synchronize();
2672 if (shared.relaxation_solutions !=
nullptr) {
2673 shared.relaxation_solutions->Synchronize();
2675 if (shared.lp_solutions !=
nullptr) {
2676 shared.lp_solutions->Synchronize();
2686 local_params.set_linearization_level(0);
2687 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2688 "first_solution", local_params,
2696 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2697 local_params.name(), local_params,
2703 if (use_feasibility_pump) {
2704 subsolvers.push_back(
2705 absl::make_unique<FeasibilityPumpSolver>(
parameters, &shared));
2712 auto unique_helper = absl::make_unique<NeighborhoodGeneratorHelper>(
2715 NeighborhoodGeneratorHelper* helper = unique_helper.get();
2716 subsolvers.push_back(std::move(unique_helper));
2719 std::vector<SatParameters> lns_params = {
parameters};
2720 lns_params.back().
set_name(
"default");
2722 std::vector<SatParameters> lns_params =
2725 for (
const SatParameters& local_params : lns_params) {
2730 subsolvers.push_back(absl::make_unique<LnsSolver>(
2731 absl::make_unique<RelaxRandomVariablesGenerator>(
2732 helper, absl::StrCat(
"rnd_var_lns_", local_params.name())),
2733 local_params, helper, &shared));
2734 subsolvers.push_back(absl::make_unique<LnsSolver>(
2735 absl::make_unique<RelaxRandomConstraintsGenerator>(
2736 helper, absl::StrCat(
"rnd_cst_lns_", local_params.name())),
2737 local_params, helper, &shared));
2738 subsolvers.push_back(absl::make_unique<LnsSolver>(
2739 absl::make_unique<VariableGraphNeighborhoodGenerator>(
2740 helper, absl::StrCat(
"graph_var_lns_", local_params.name())),
2741 local_params, helper, &shared));
2742 subsolvers.push_back(absl::make_unique<LnsSolver>(
2743 absl::make_unique<ConstraintGraphNeighborhoodGenerator>(
2744 helper, absl::StrCat(
"graph_cst_lns_", local_params.name())),
2745 local_params, helper, &shared));
2752 subsolvers.push_back(absl::make_unique<LnsSolver>(
2753 absl::make_unique<SchedulingTimeWindowNeighborhoodGenerator>(
2754 helper, absl::StrCat(
"scheduling_time_window_lns_",
2755 local_params.name())),
2756 local_params, helper, &shared));
2757 subsolvers.push_back(absl::make_unique<LnsSolver>(
2758 absl::make_unique<SchedulingNeighborhoodGenerator>(
2760 absl::StrCat(
"scheduling_random_lns_", local_params.name())),
2761 local_params, helper, &shared));
2765 const int num_circuit =
2767 const int num_routes =
2769 if (num_circuit + num_routes > 0) {
2770 subsolvers.push_back(absl::make_unique<LnsSolver>(
2771 absl::make_unique<RoutingRandomNeighborhoodGenerator>(
2772 helper, absl::StrCat(
"routing_random_lns_", local_params.name())),
2773 local_params, helper, &shared));
2775 subsolvers.push_back(absl::make_unique<LnsSolver>(
2776 absl::make_unique<RoutingPathNeighborhoodGenerator>(
2777 helper, absl::StrCat(
"routing_path_lns_", local_params.name())),
2778 local_params, helper, &shared));
2780 if (num_routes > 0 || num_circuit > 1) {
2781 subsolvers.push_back(absl::make_unique<LnsSolver>(
2782 absl::make_unique<RoutingFullPathNeighborhoodGenerator>(
2784 absl::StrCat(
"routing_full_path_lns_", local_params.name())),
2785 local_params, helper, &shared));
2797 subsolvers.push_back(absl::make_unique<LnsSolver>(
2798 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2799 helper, shared.response, shared.relaxation_solutions,
2800 shared.lp_solutions,
nullptr,
2801 absl::StrCat(
"rins_lns_", local_params.name())),
2802 local_params, helper, &shared));
2805 subsolvers.push_back(absl::make_unique<LnsSolver>(
2806 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2807 helper,
nullptr, shared.relaxation_solutions,
2808 shared.lp_solutions, shared.incomplete_solutions,
2809 absl::StrCat(
"rens_lns_", local_params.name())),
2810 local_params, helper, &shared));
2814 subsolvers.push_back(absl::make_unique<LnsSolver>(
2816 ConsecutiveConstraintsRelaxationNeighborhoodGenerator>(
2817 helper, absl::StrCat(
"rnd_rel_lns_", local_params.name())),
2818 local_params, helper, &shared));
2820 subsolvers.push_back(absl::make_unique<LnsSolver>(
2821 absl::make_unique<WeightedRandomRelaxationNeighborhoodGenerator>(
2822 helper, absl::StrCat(
"wgt_rel_lns_", local_params.name())),
2823 local_params, helper, &shared));
2830 subsolvers.push_back(absl::make_unique<SynchronizationPoint>(
2831 [&shared]() { shared.response->UpdateGapIntegral(); }));
2835 if (logger->LoggingIsEnabled()) {
2836 std::vector<std::string> names;
2837 for (
const auto& subsolver : subsolvers) {
2838 if (!subsolver->name().empty()) names.push_back(subsolver->name());
2842 absl::StrFormat(
"Starting Search at %.2fs with %i "
2843 "workers and subsolvers: [ %s ]",
2844 shared.wall_timer->Get(), num_search_workers,
2845 absl::StrJoin(names,
", ")));
2858 SOLVER_LOG(logger,
"Sub-solver search statistics:");
2859 for (
const auto& subsolver : subsolvers) {
2860 const std::string stats = subsolver->StatisticsString();
2861 if (stats.empty())
continue;
2862 SOLVER_LOG(logger, absl::StrCat(
" '", subsolver->name(),
"':\n", stats));
2872void AddPostsolveClauses(
const std::vector<int>& postsolve_mapping,
2873 Model*
model, CpModelProto* mapping_proto) {
2874 auto* mapping =
model->GetOrCreate<CpModelMapping>();
2875 auto* postsolve =
model->GetOrCreate<PostsolveClauses>();
2876 for (
const auto& clause : postsolve->clauses) {
2877 auto*
ct = mapping_proto->add_constraints()->mutable_bool_or();
2878 for (
const Literal l : clause) {
2879 int var = mapping->GetProtoVariableFromBooleanVariable(l.Variable());
2881 var = postsolve_mapping[
var];
2885 postsolve->clauses.clear();
2894 user_timer->
Start();
2896#if !defined(__PORTABLE_PLATFORM__)
2899#if !defined(__PORTABLE_PLATFORM__)
2901 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
2902 const std::string
file =
2903 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
"model.pb.txt");
2904 LOG(
INFO) <<
"Dumping cp model proto to '" <<
file <<
"'.";
2909#if !defined(__PORTABLE_PLATFORM__)
2911 if (!absl::GetFlag(FLAGS_cp_model_params).empty()) {
2914 CHECK(google::protobuf::TextFormat::ParseFromString(
2915 absl::GetFlag(FLAGS_cp_model_params), &flag_params));
2926 std::string log_string;
2928 logger->AddInfoLoggingCallback([&log_string](
const std::string&
message) {
2929 absl::StrAppend(&log_string,
message,
"\n");
2935 absl::GetFlag(FLAGS_cp_model_dump_prefix));
2937#if !defined(__PORTABLE_PLATFORM__)
2941 if (absl::GetFlag(FLAGS_cp_model_dump_response)) {
2942 shared_response_manager->AddFinalResponsePostprocessor(
2944 const std::string
file = absl::StrCat(
2945 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"response.pb.txt");
2946 LOG(
INFO) <<
"Dumping response proto to '" <<
file <<
"'.";
2954 shared_response_manager->AddFinalResponsePostprocessor(
2961 if (!log_string.empty()) {
2962 response->set_solve_log(log_string);
2970 shared_response_manager->AddResponsePostprocessor(
2976 shared_time_limit->GetElapsedDeterministicTime());
2985 if (!error.empty()) {
2986 SOLVER_LOG(logger,
"Invalid parameters: ", error);
2991 shared_response_manager->MutableResponse()->set_status(
2993 shared_response_manager->MutableResponse()->set_solution_info(error);
2994 return shared_response_manager->GetResponse();
2999 model->GetOrCreate<
TimeLimit>()->ResetLimitFromParameters(params);
3001#if !defined(__PORTABLE_PLATFORM__)
3005 [&shared_time_limit]() { shared_time_limit->Stop(); });
3015#if !defined(__PORTABLE_PLATFORM__)
3017 const int num_cores =
3020 : std::max<int>(std::thread::hardware_concurrency(), 1);
3022 const int num_cores = 1;
3024 SOLVER_LOG(logger,
"Setting number of workers to ", num_cores);
3028 SOLVER_LOG(logger,
"Parameters: ", params.ShortDebugString());
3037 if (!error.empty()) {
3038 SOLVER_LOG(logger,
"Invalid model: ", error);
3039 shared_response_manager->MutableResponse()->set_status(
3041 shared_response_manager->MutableResponse()->set_solution_info(error);
3042 return shared_response_manager->GetResponse();
3058 bool is_pure_sat =
true;
3060 if (
var.domain_size() != 2 ||
var.domain(0) < 0 ||
var.domain(1) > 1) {
3061 is_pure_sat =
false;
3067 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolOr &&
3068 ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolAnd) {
3069 is_pure_sat =
false;
3077 *shared_response_manager->MutableResponse() =
3080 *shared_response_manager->MutableResponse()
3083 return shared_response_manager->GetResponse();
3090 absl::StrFormat(
"Starting presolve at %.2fs",
wall_timer->
Get()));
3093 auto context = absl::make_unique<PresolveContext>(
model, &new_cp_model_proto,
3099 VLOG(1) <<
"Model found infeasible during copy";
3111 " variables to their value in the solution hints.");
3118 const std::string var_name = var_proto.
name().empty()
3119 ? absl::StrCat(
"var(",
var,
")")
3124 "Hint found infeasible when assigning variable '", var_name,
3125 "' with domain", var_domain.
ToString(),
" the value ",
3149 "The solution hint is complete and is feasible.");
3154 "The solution hint is complete, but it is infeasible! we "
3155 "will try to repair it.");
3162 shared_response_manager->AddFinalResponsePostprocessor(
3165 if (
response->solution().empty())
return;
3169 double value = float_obj.offset();
3170 const int num_terms = float_obj.vars().size();
3171 for (
int i = 0; i < num_terms; ++i) {
3172 value += float_obj.coeffs(i) *
3173 static_cast<double>(
response->solution(float_obj.vars(i)));
3182 *
response->mutable_integer_objective() = integer_obj;
3188 !integer_obj.scaling_was_exact()) {
3189 const int64_t integer_lb = response->inner_objective_lower_bound();
3190 const double lb = ComputeTrueObjectiveLowerBound(
3191 model_proto, integer_obj, integer_lb);
3192 SOLVER_LOG(logger,
"[Scaling] scaled_objective_bound: ",
3193 response->best_objective_bound(),
3194 " corrected_bound: ", lb,
3195 " delta: ", response->best_objective_bound() - lb);
3199 if (float_obj.maximize()) {
3200 response->set_best_objective_bound(
3201 std::max(lb, response->objective_value()));
3203 response->set_best_objective_bound(
3204 std::min(lb, response->objective_value()));
3211 const double gap = std::abs(response->objective_value() -
3212 response->best_objective_bound());
3213 if (gap > params.absolute_gap_limit()) {
3215 "[Scaling] Warning: OPTIMAL was reported, yet the "
3217 gap,
") is greater than requested absolute limit (",
3218 params.absolute_gap_limit(),
").");
3224 if (params.num_search_workers() > 1 ||
model_proto.has_objective()) {
3231 shared_response_manager->AddFinalResponsePostprocessor(
3236 *
response->mutable_sufficient_assumptions_for_infeasibility() =
3240 context->InitializeNewDomains();
3242 if (!
context->SetLiteralToTrue(ref)) {
3243 shared_response_manager->MutableResponse()->set_status(
3245 shared_response_manager->MutableResponse()
3246 ->add_sufficient_assumptions_for_infeasibility(ref);
3247 return shared_response_manager->GetResponse();
3253 std::vector<int> postsolve_mapping;
3257 SOLVER_LOG(logger,
"Problem closed by presolve.");
3258 shared_response_manager->MutableResponse()->set_status(presolve_status);
3259 return shared_response_manager->GetResponse();
3267 if (params.cp_model_presolve()) {
3268 shared_response_manager->AddSolutionPostprocessor(
3270 &postsolve_mapping](std::vector<int64_t>* solution) {
3271 AddPostsolveClauses(postsolve_mapping,
model, &mapping_proto);
3272 PostsolveResponseWrapper(params,
model_proto.variables_size(),
3273 mapping_proto, postsolve_mapping, solution);
3275 shared_response_manager->AddResponsePostprocessor(
3281 ->mutable_sufficient_assumptions_for_infeasibility())) {
3283 ? postsolve_mapping[ref]
3286 if (!
response->solution().empty()) {
3289 std::vector<int64_t>(
response->solution().begin(),
3291 &mapping_proto, &postsolve_mapping))
3292 <<
"postsolved solution";
3294 if (params.fill_tightened_domains_in_response()) {
3297 if (mapping_proto.variables().size() >=
3299 for (
int i = 0; i <
model_proto.variables().size(); ++i) {
3300 *
response->add_tightened_variables() =
3301 mapping_proto.variables(i);
3307 shared_response_manager->AddFinalResponsePostprocessor(
3309 if (!
response->solution().empty()) {
3315 shared_response_manager->AddResponsePostprocessor(
3318 const int initial_size =
model_proto.variables_size();
3319 if (
response->solution_size() > 0) {
3320 response->mutable_solution()->Truncate(initial_size);
3322 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
3325 std::vector<int64_t>(
response->solution().begin(),
3329 if (params.fill_tightened_domains_in_response()) {
3338 if (params.symmetry_level() > 1) {
3342 const auto& observers =
model->GetOrCreate<SolutionObservers>()->observers;
3343 if (!observers.empty()) {
3344 shared_response_manager->AddSolutionCallback(
3345 [&observers](
const CpSolverResponse&
response) {
3346 for (
const auto& observer : observers) {
3356 if (new_cp_model_proto.has_objective()) {
3357 shared_response_manager->InitializeObjective(new_cp_model_proto);
3358 shared_response_manager->SetGapLimitsFromParameters(params);
3363 shared_response_manager->UpdateGapIntegral();
3365#if !defined(__PORTABLE_PLATFORM__)
3366 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
3367 const std::string presolved_file = absl::StrCat(
3368 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"presolved_model.pb.txt");
3369 LOG(
INFO) <<
"Dumping presolved cp model proto to '" << presolved_file
3374 const std::string mapping_file = absl::StrCat(
3375 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"mapping_model.pb.txt");
3376 LOG(
INFO) <<
"Dumping mapping cp model proto to '" << mapping_file <<
"'.";
3381 if (params.stop_after_presolve() || shared_time_limit->LimitReached()) {
3382 int64_t num_terms = 0;
3383 for (
const ConstraintProto&
ct : new_cp_model_proto.constraints()) {
3387 logger,
"Stopped after presolve.",
3388 "\nPresolvedNumVariables: ", new_cp_model_proto.variables().size(),
3389 "\nPresolvedNumConstraints: ", new_cp_model_proto.constraints().size(),
3390 "\nPresolvedNumTerms: ", num_terms);
3392 shared_response_manager->SetStatsFromModel(
model);
3393 return shared_response_manager->GetResponse();
3397 if (params.stop_after_first_solution()) {
3398 shared_response_manager->AddSolutionCallback(
3399 [shared_time_limit](
const CpSolverResponse&
response) {
3400 shared_time_limit->Stop();
3404#if defined(__PORTABLE_PLATFORM__)
3408 if (params.num_search_workers() > 1 || params.interleave_search()) {
3409 SolveCpModelParallel(new_cp_model_proto,
model);
3413 SOLVER_LOG(logger, absl::StrFormat(
"Starting to load the model at %.2fs",
3415 shared_response_manager->SetUpdateGapIntegralOnEachChange(
true);
3416 LoadCpModel(new_cp_model_proto,
model);
3417 shared_response_manager->LoadDebugSolution(
model);
3420 SOLVER_LOG(logger, absl::StrFormat(
"Starting sequential search at %.2fs",
3422 if (params.repair_hint()) {
3423 MinimizeL1DistanceWithHint(new_cp_model_proto,
model);
3425 QuickSolveWithHint(new_cp_model_proto,
model);
3427 SolveLoadedCpModel(new_cp_model_proto,
model);
3430 if (logger->LoggingIsEnabled()) {
3431 if (params.num_search_workers() <= 1) {
3433 *
model->GetOrCreate<LinearProgrammingConstraintCollection>();
3436 for (
const auto* lp : lps) {
3442 if (params.num_search_workers() > 1) {
3444 shared_response_manager->DisplayImprovementStatistics();
3448 return shared_response_manager->GetResponse();
3463#if !defined(__PORTABLE_PLATFORM__)
3465 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)
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::string ValidateCpModel(const CpModelProto &model)
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)