31 #if !defined(__PORTABLE_PLATFORM__)
32 #include "absl/synchronization/notification.h"
33 #include "google/protobuf/text_format.h"
38 #include "absl/container/flat_hash_set.h"
39 #include "absl/memory/memory.h"
40 #include "absl/status/status.h"
41 #include "absl/strings/str_cat.h"
42 #include "absl/strings/str_format.h"
43 #include "absl/strings/str_join.h"
44 #include "absl/synchronization/mutex.h"
89 ABSL_FLAG(std::string, cp_model_dump_prefix,
".\\",
90 "Prefix filename for all dumped files");
92 ABSL_FLAG(std::string, cp_model_dump_prefix,
"/tmp/",
93 "Prefix filename for all dumped files");
96 "DEBUG ONLY. When set to true, SolveCpModel() will dump its model "
97 "protos (original model, presolved model, mapping model) in text "
98 "format to 'FLAGS_cp_model_dump_prefix'{model|presolved_model|"
99 "mapping_model}.pbtxt.");
102 "DEBUG ONLY. When set to true, solve will dump all "
103 "lns models proto in text format to "
104 "'FLAGS_cp_model_dump_prefix'lns_xxx.pbtxt.");
107 "DEBUG ONLY. If true, the final response of each solve will be "
108 "dumped to 'FLAGS_cp_model_dump_prefix'response.pbtxt");
111 "This is interpreted as a text SatParameters proto. The "
112 "specified fields will override the normal ones for all solves.");
115 "If non-empty, a proof in DRAT format will be written to this file. "
116 "This will only be used for pure-SAT problems.");
119 "If true, a proof in DRAT format will be stored in memory and "
120 "checked if the problem is UNSAT. This will only be used for "
121 "pure-SAT problems.");
124 std::numeric_limits<double>::infinity(),
125 "Maximum time in seconds to check the DRAT proof. This will only "
126 "be used is the drat_check flag is enabled.");
128 ABSL_FLAG(
bool, cp_model_check_intermediate_solutions,
false,
129 "When true, all intermediate solutions found by the solver will be "
130 "checked. This can be expensive, therefore it is off by default.");
138 std::string Summarize(
const std::string&
input) {
141 return absl::StrCat(
input.substr(0, half),
" ... ",
152 std::map<std::string, int> num_constraints_by_name;
153 std::map<std::string, int> num_reif_constraints_by_name;
154 std::map<std::string, int> name_to_num_literals;
155 std::map<std::string, int> name_to_num_terms;
156 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
161 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) {
162 if (
ct.linear().vars_size() == 1)
name +=
"1";
163 if (
ct.linear().vars_size() == 2)
name +=
"2";
164 if (
ct.linear().vars_size() == 3)
name +=
"3";
165 if (
ct.linear().vars_size() > 3)
name +=
"N";
168 num_constraints_by_name[
name]++;
169 if (!
ct.enforcement_literal().empty()) {
170 num_reif_constraints_by_name[
name]++;
175 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) {
176 name_to_num_literals[
name] +=
ct.bool_or().literals().size();
177 }
else if (
ct.constraint_case() ==
178 ConstraintProto::ConstraintCase::kBoolAnd) {
179 name_to_num_literals[
name] +=
ct.bool_and().literals().size();
180 }
else if (
ct.constraint_case() ==
181 ConstraintProto::ConstraintCase::kAtMostOne) {
182 name_to_num_literals[
name] +=
ct.at_most_one().literals().size();
183 }
else if (
ct.constraint_case() ==
184 ConstraintProto::ConstraintCase::kExactlyOne) {
185 name_to_num_literals[
name] +=
ct.exactly_one().literals().size();
188 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear &&
189 ct.linear().vars_size() > 3) {
190 name_to_num_terms[
name] +=
ct.linear().vars_size();
194 int num_constants = 0;
195 std::set<int64> constant_values;
196 std::map<Domain, int> num_vars_per_domains;
198 if (
var.domain_size() == 2 &&
var.domain(0) ==
var.domain(1)) {
200 constant_values.insert(
var.domain(0));
208 absl::StrAppend(&result,
"Optimization model '",
model_proto.name(),
211 absl::StrAppend(&result,
"Satisfaction model '",
model_proto.name(),
215 for (
const DecisionStrategyProto& strategy :
model_proto.search_strategy()) {
217 &result,
"Search strategy: on ", strategy.variables_size(),
219 ProtoEnumToString<DecisionStrategyProto::VariableSelectionStrategy>(
220 strategy.variable_selection_strategy()),
222 ProtoEnumToString<DecisionStrategyProto::DomainReductionStrategy>(
223 strategy.domain_reduction_strategy()),
227 const std::string objective_string =
229 ? absl::StrCat(
" (",
model_proto.objective().vars_size(),
232 absl::StrAppend(&result,
"#Variables: ",
model_proto.variables_size(),
233 objective_string,
"\n");
234 if (num_vars_per_domains.size() < 100) {
235 for (
const auto& entry : num_vars_per_domains) {
236 const std::string temp = absl::StrCat(
" - ", entry.second,
" in ",
237 entry.first.ToString(),
"\n");
238 absl::StrAppend(&result, Summarize(temp));
241 int64 max_complexity = 0;
244 for (
const auto& entry : num_vars_per_domains) {
247 max_complexity =
std::max(max_complexity,
248 static_cast<int64>(entry.first.NumIntervals()));
250 absl::StrAppend(&result,
" - ", num_vars_per_domains.size(),
251 " different domains in [",
min,
",",
max,
252 "] with a largest complexity of ", max_complexity,
".\n");
255 if (num_constants > 0) {
256 const std::string temp =
257 absl::StrCat(
" - ", num_constants,
" constants in {",
258 absl::StrJoin(constant_values,
","),
"} \n");
259 absl::StrAppend(&result, Summarize(temp));
262 std::vector<std::string> constraints;
263 constraints.reserve(num_constraints_by_name.size());
264 for (
const auto& entry : num_constraints_by_name) {
265 const std::string&
name = entry.first;
266 constraints.push_back(absl::StrCat(
"#",
name,
": ", entry.second));
268 absl::StrAppend(&constraints.back(),
269 " (#enforced: ", num_reif_constraints_by_name[
name],
")");
272 absl::StrAppend(&constraints.back(),
273 " (#literals: ", name_to_num_literals[
name],
")");
276 absl::StrAppend(&constraints.back(),
277 " (#terms: ", name_to_num_terms[
name],
")");
280 std::sort(constraints.begin(), constraints.end());
281 absl::StrAppend(&result, absl::StrJoin(constraints,
"\n"));
287 bool has_objective) {
289 absl::StrAppend(&result,
"CpSolverResponse:");
290 absl::StrAppend(&result,
"\nstatus: ",
291 ProtoEnumToString<CpSolverStatus>(
response.status()));
294 absl::StrAppendFormat(&result,
"\nobjective: %.16g",
296 absl::StrAppendFormat(&result,
"\nbest_bound: %.16g",
299 absl::StrAppend(&result,
"\nobjective: NA");
300 absl::StrAppend(&result,
"\nbest_bound: NA");
303 absl::StrAppend(&result,
"\nbooleans: ",
response.num_booleans());
304 absl::StrAppend(&result,
"\nconflicts: ",
response.num_conflicts());
305 absl::StrAppend(&result,
"\nbranches: ",
response.num_branches());
309 absl::StrAppend(&result,
310 "\npropagations: ",
response.num_binary_propagations());
312 &result,
"\ninteger_propagations: ",
response.num_integer_propagations());
314 absl::StrAppend(&result,
"\nrestarts: ",
response.num_restarts());
315 absl::StrAppend(&result,
"\nlp_iterations: ",
response.num_lp_iterations());
316 absl::StrAppend(&result,
"\nwalltime: ",
response.wall_time());
317 absl::StrAppend(&result,
"\nusertime: ",
response.user_time());
318 absl::StrAppend(&result,
319 "\ndeterministic_time: ",
response.deterministic_time());
320 absl::StrAppend(&result,
"\nprimal_integral: ",
response.primal_integral());
321 absl::StrAppend(&result,
"\n");
327 void FillSolutionInResponse(
const CpModelProto&
model_proto,
const Model&
model,
330 response->clear_solution_lower_bounds();
331 response->clear_solution_upper_bounds();
333 auto* mapping =
model.Get<CpModelMapping>();
335 auto* integer_trail =
model.Get<IntegerTrail>();
337 std::vector<int64> solution;
338 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
339 if (mapping->IsInteger(i)) {
340 const IntegerVariable
var = mapping->Integer(i);
341 if (integer_trail->IsCurrentlyIgnored(
var)) {
354 DCHECK(mapping->IsBoolean(i));
356 if (trail->Assignment().LiteralIsAssigned(
literal)) {
365 if (!solution.empty()) {
367 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
375 const auto& assignment = trail->Assignment();
376 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
377 if (mapping->IsBoolean(i)) {
378 if (assignment.VariableIsAssigned(mapping->Literal(i).Variable())) {
383 response->add_solution_lower_bounds(0);
384 response->add_solution_upper_bounds(1);
387 response->add_solution_lower_bounds(
389 response->add_solution_upper_bounds(
398 IntegerVariable GetOrCreateVariableWithTightBound(
399 const std::vector<std::pair<IntegerVariable, int64>>& terms, Model*
model) {
401 if (terms.size() == 1 && terms.front().second == 1) {
402 return terms.front().first;
404 if (terms.size() == 1 && terms.front().second == -1) {
410 for (
const std::pair<IntegerVariable, int64> var_coeff : terms) {
413 const int64 coeff = var_coeff.second;
414 const int64 prod1 = min_domain * coeff;
415 const int64 prod2 = max_domain * coeff;
422 IntegerVariable GetOrCreateVariableGreaterOrEqualToSumOf(
423 const std::vector<std::pair<IntegerVariable, int64>>& terms, Model*
model) {
425 if (terms.size() == 1 && terms.front().second == 1) {
426 return terms.front().first;
428 if (terms.size() == 1 && terms.front().second == -1) {
433 const IntegerVariable new_var =
434 GetOrCreateVariableWithTightBound(terms,
model);
435 std::vector<IntegerVariable> vars;
436 std::vector<int64> coeffs;
437 for (
const auto& term : terms) {
438 vars.push_back(term.first);
439 coeffs.push_back(term.second);
441 vars.push_back(new_var);
442 coeffs.push_back(-1);
447 void TryToAddCutGenerators(
const CpModelProto&
model_proto,
448 const ConstraintProto&
ct, Model* m,
449 LinearRelaxation* relaxation) {
450 const int linearization_level =
451 m->GetOrCreate<SatParameters>()->linearization_level();
452 auto* mapping = m->GetOrCreate<CpModelMapping>();
453 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCircuit &&
454 linearization_level > 1) {
455 std::vector<int> tails(
ct.circuit().tails().begin(),
456 ct.circuit().tails().end());
457 std::vector<int> heads(
ct.circuit().heads().begin(),
458 ct.circuit().heads().end());
459 std::vector<Literal> literals = mapping->Literals(
ct.circuit().literals());
462 relaxation->cut_generators.push_back(
466 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kRoutes &&
467 linearization_level > 1) {
468 std::vector<int> tails(
ct.routes().tails().begin(),
469 ct.routes().tails().end());
470 std::vector<int> heads(
ct.routes().heads().begin(),
471 ct.routes().heads().end());
472 std::vector<Literal> literals = mapping->Literals(
ct.routes().literals());
475 for (
int i = 0; i <
ct.routes().tails_size(); ++i) {
476 num_nodes =
std::max(num_nodes, 1 +
ct.routes().tails(i));
477 num_nodes =
std::max(num_nodes, 1 +
ct.routes().heads(i));
479 if (
ct.routes().demands().empty() ||
ct.routes().capacity() == 0) {
480 relaxation->cut_generators.push_back(
484 const std::vector<int64> demands(
ct.routes().demands().begin(),
485 ct.routes().demands().end());
486 relaxation->cut_generators.push_back(
488 ct.routes().capacity(), m));
491 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kIntProd) {
493 if (
ct.int_prod().vars_size() != 2)
return;
497 IntegerVariable z = mapping->Integer(
ct.int_prod().target());
498 IntegerVariable x = mapping->Integer(
ct.int_prod().vars(0));
499 IntegerVariable y = mapping->Integer(
ct.int_prod().vars(1));
501 IntegerTrail*
const integer_trail = m->GetOrCreate<IntegerTrail>();
502 IntegerValue x_lb = integer_trail->LowerBound(x);
503 IntegerValue x_ub = integer_trail->UpperBound(x);
504 IntegerValue y_lb = integer_trail->LowerBound(y);
505 IntegerValue y_ub = integer_trail->UpperBound(y);
509 if (x_lb < 0 && x_ub > 0)
return;
519 if (x_lb < 0 && x_ub > 0)
return;
520 if (y_lb < 0 && y_ub > 0)
return;
533 relaxation->cut_generators.push_back(
537 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kAllDiff) {
538 if (linearization_level < 2)
return;
540 const int num_vars =
ct.all_diff().vars_size();
541 if (num_vars <= m->GetOrCreate<SatParameters>()->max_all_diff_cut_size()) {
542 std::vector<IntegerVariable> vars =
543 mapping->Integers(
ct.all_diff().vars());
544 relaxation->cut_generators.push_back(
549 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCumulative) {
550 if (linearization_level < 2)
return;
553 std::vector<IntegerVariable> demands =
554 mapping->Integers(
ct.cumulative().demands());
555 std::vector<IntervalVariable> intervals =
556 mapping->Intervals(
ct.cumulative().intervals());
558 mapping->Integer(
ct.cumulative().capacity());
559 relaxation->cut_generators.push_back(
562 relaxation->cut_generators.push_back(
566 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kNoOverlap) {
567 if (linearization_level < 2)
return;
569 std::vector<IntervalVariable> intervals =
570 mapping->Intervals(
ct.no_overlap().intervals());
571 relaxation->cut_generators.push_back(
573 relaxation->cut_generators.push_back(
577 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinMax) {
578 if (!m->GetOrCreate<SatParameters>()->add_lin_max_cuts())
return;
582 if (
ct.lin_max().target().vars_size() != 1)
return;
583 if (
ct.lin_max().target().coeffs(0) != 1)
return;
585 const IntegerVariable target =
586 mapping->Integer(
ct.lin_max().target().vars(0));
587 std::vector<LinearExpression> exprs;
588 exprs.reserve(
ct.lin_max().exprs_size());
589 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
598 const std::vector<IntegerVariable> z_vars =
601 if (linearization_level >= 2) {
602 relaxation->cut_generators.push_back(
610 LinearRelaxation ComputeLinearRelaxation(
const CpModelProto&
model_proto,
611 int linearization_level, Model* m) {
612 LinearRelaxation relaxation;
615 absl::flat_hash_set<int> used_integer_variable;
617 auto* mapping = m->GetOrCreate<CpModelMapping>();
618 auto* encoder = m->GetOrCreate<IntegerEncoder>();
619 auto* trail = m->GetOrCreate<Trail>();
622 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCircuit) {
623 for (
const int ref :
ct.circuit().literals()) {
624 const Literal l = mapping->Literal(ref);
625 if (!encoder->LiteralOrNegationHasView(l)) {
638 for (
const int literal_ref : refs.literals) {
640 if (trail->Assignment().LiteralIsAssigned(
literal)) {
643 }
else if (!encoder->LiteralOrNegationHasView(
literal)) {
656 int num_full_encoding_relaxations = 0;
657 int num_partial_encoding_relaxations = 0;
658 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
659 if (mapping->IsBoolean(i))
continue;
661 const IntegerVariable
var = mapping->Integer(i);
672 if (encoder->VariableIsFullyEncoded(
var)) {
674 ++num_full_encoding_relaxations;
685 const int old = relaxation.linear_constraints.size();
687 if (relaxation.linear_constraints.size() > old) {
688 ++num_partial_encoding_relaxations;
694 m->GetOrCreate<BinaryImplicationGraph>()->TransformIntoMaxCliques(
695 &relaxation.at_most_ones);
696 for (
const std::vector<Literal>& at_most_one : relaxation.at_most_ones) {
697 if (at_most_one.empty())
continue;
700 for (
const Literal
literal : at_most_one) {
703 const bool unused ABSL_ATTRIBUTE_UNUSED =
704 lc.AddLiteralTerm(
literal, IntegerValue(1));
706 relaxation.linear_constraints.push_back(lc.Build());
711 relaxation.at_most_ones.clear();
716 for (
int i = 0; i < relaxation.linear_constraints.size(); ++i) {
717 if (relaxation.linear_constraints[i].vars.size() <= 1)
continue;
718 std::swap(relaxation.linear_constraints[new_size++],
719 relaxation.linear_constraints[i]);
721 relaxation.linear_constraints.resize(new_size);
724 VLOG(3) <<
"num_full_encoding_relaxations: " << num_full_encoding_relaxations;
725 VLOG(3) <<
"num_partial_encoding_relaxations: "
726 << num_partial_encoding_relaxations;
727 VLOG(3) << relaxation.linear_constraints.size()
728 <<
" constraints in the LP relaxation.";
729 VLOG(3) << relaxation.cut_generators.size() <<
" cuts generators.";
734 IntegerVariable AddLPConstraints(
const CpModelProto&
model_proto,
735 int linearization_level, Model* m) {
736 const LinearRelaxation relaxation =
737 ComputeLinearRelaxation(
model_proto, linearization_level, m);
745 const int num_lp_constraints = relaxation.linear_constraints.size();
746 const int num_lp_cut_generators = relaxation.cut_generators.size();
747 const int num_integer_variables =
748 m->GetOrCreate<IntegerTrail>()->NumIntegerVariables().value();
751 num_integer_variables);
752 auto get_constraint_index = [](
int ct_index) {
return ct_index; };
753 auto get_cut_generator_index = [num_lp_constraints](
int cut_index) {
754 return num_lp_constraints + cut_index;
756 auto get_var_index = [num_lp_constraints,
757 num_lp_cut_generators](IntegerVariable
var) {
758 return num_lp_constraints + num_lp_cut_generators +
var.value();
760 for (
int i = 0; i < num_lp_constraints; i++) {
761 for (
const IntegerVariable
var : relaxation.linear_constraints[i].vars) {
762 components.
AddEdge(get_constraint_index(i), get_var_index(
var));
765 for (
int i = 0; i < num_lp_cut_generators; ++i) {
766 for (
const IntegerVariable
var : relaxation.cut_generators[i].vars) {
767 components.
AddEdge(get_cut_generator_index(i), get_var_index(
var));
775 for (
const std::vector<Literal>& at_most_one : relaxation.at_most_ones) {
777 for (
const Literal
literal : at_most_one) {
780 const bool unused ABSL_ATTRIBUTE_UNUSED =
781 builder.AddLiteralTerm(
literal, IntegerValue(1));
783 LinearConstraint lc = builder.Build();
784 for (
int i = 1; i < lc.vars.size(); ++i) {
785 components.
AddEdge(get_var_index(lc.vars[0]), get_var_index(lc.vars[i]));
790 std::vector<int> component_sizes(num_components, 0);
791 const std::vector<int> index_to_component = components.
GetComponentIds();
792 for (
int i = 0; i < num_lp_constraints; i++) {
793 ++component_sizes[index_to_component[get_constraint_index(i)]];
795 for (
int i = 0; i < num_lp_cut_generators; i++) {
796 ++component_sizes[index_to_component[get_cut_generator_index(i)]];
804 auto* mapping = m->GetOrCreate<CpModelMapping>();
805 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
806 const IntegerVariable
var =
808 ++component_sizes[index_to_component[get_var_index(
var)]];
812 std::vector<LinearProgrammingConstraint*> lp_constraints(num_components,
814 std::vector<std::vector<LinearConstraint>> component_to_constraints(
816 for (
int i = 0; i < num_lp_constraints; i++) {
817 const int c = index_to_component[get_constraint_index(i)];
818 if (component_sizes[c] <= 1)
continue;
819 component_to_constraints[c].push_back(relaxation.linear_constraints[i]);
820 if (lp_constraints[c] ==
nullptr) {
821 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
824 lp_constraints[c]->AddLinearConstraint(relaxation.linear_constraints[i]);
828 for (
int i = 0; i < num_lp_cut_generators; i++) {
829 const int c = index_to_component[get_cut_generator_index(i)];
830 if (lp_constraints[c] ==
nullptr) {
831 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
833 lp_constraints[c]->AddCutGenerator(std::move(relaxation.cut_generators[i]));
837 const SatParameters& params = *(m->GetOrCreate<SatParameters>());
838 if (params.add_clique_cuts() && params.linearization_level() > 1) {
839 for (LinearProgrammingConstraint* lp : lp_constraints) {
840 if (lp ==
nullptr)
continue;
845 if (params.add_knapsack_cuts() && params.linearization_level() > 1) {
846 for (
int c = 0; c < num_components; ++c) {
847 if (component_to_constraints[c].empty())
continue;
849 component_to_constraints[c], lp_constraints[c]->integer_variables(),
855 std::vector<std::vector<std::pair<IntegerVariable, int64>>>
856 component_to_cp_terms(num_components);
857 std::vector<std::pair<IntegerVariable, int64>> top_level_cp_terms;
858 int num_components_containing_objective = 0;
862 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
863 const IntegerVariable
var =
866 const int c = index_to_component[get_var_index(
var)];
867 if (lp_constraints[c] !=
nullptr) {
868 lp_constraints[c]->SetObjectiveCoefficient(
var, IntegerValue(coeff));
869 component_to_cp_terms[c].push_back(std::make_pair(
var, coeff));
872 top_level_cp_terms.push_back(std::make_pair(
var, coeff));
876 for (
int c = 0; c < num_components; ++c) {
877 if (component_to_cp_terms[c].empty())
continue;
878 const IntegerVariable sub_obj_var =
879 GetOrCreateVariableGreaterOrEqualToSumOf(component_to_cp_terms[c], m);
880 top_level_cp_terms.push_back(std::make_pair(sub_obj_var, 1));
881 lp_constraints[c]->SetMainObjectiveVariable(sub_obj_var);
882 num_components_containing_objective++;
886 const IntegerVariable main_objective_var =
888 ? GetOrCreateVariableGreaterOrEqualToSumOf(top_level_cp_terms, m)
893 for (LinearProgrammingConstraint* lp_constraint : lp_constraints) {
894 if (lp_constraint ==
nullptr)
continue;
895 lp_constraint->RegisterWith(m);
896 VLOG(3) <<
"LP constraint: " << lp_constraint->DimensionString() <<
".";
899 VLOG(3) << top_level_cp_terms.size()
900 <<
" terms in the main objective linear equation ("
901 << num_components_containing_objective <<
" from LP constraints).";
902 return main_objective_var;
914 const std::function<
void(
const CpSolverResponse&
response)>& observer) {
920 #if !defined(__PORTABLE_PLATFORM__)
923 const std::string& params) {
925 if (!params.empty()) {
926 CHECK(google::protobuf::TextFormat::ParseFromString(params, &
parameters))
953 void RegisterVariableBoundsLevelZeroExport(
954 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
956 CHECK(shared_bounds_manager !=
nullptr);
957 int saved_trail_index = 0;
958 const auto broadcast_level_zero_bounds =
960 const std::vector<IntegerVariable>& modified_vars)
mutable {
961 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
963 std::vector<int> model_variables;
964 std::vector<int64> new_lower_bounds;
965 std::vector<int64> new_upper_bounds;
966 absl::flat_hash_set<int> visited_variables;
969 auto* integer_trail =
model->Get<IntegerTrail>();
970 for (
const IntegerVariable&
var : modified_vars) {
972 const int model_var =
973 mapping->GetProtoVariableFromIntegerVariable(positive_var);
974 if (model_var == -1 || visited_variables.contains(model_var)) {
981 visited_variables.insert(model_var);
983 integer_trail->LevelZeroLowerBound(positive_var).value();
985 integer_trail->LevelZeroUpperBound(positive_var).value();
988 model_variables.push_back(model_var);
989 new_lower_bounds.push_back(new_lb);
990 new_upper_bounds.push_back(new_ub);
994 auto* trail =
model->Get<Trail>();
995 for (; saved_trail_index < trail->Index(); ++saved_trail_index) {
996 const Literal fixed_literal = (*trail)[saved_trail_index];
997 const int model_var = mapping->GetProtoVariableFromBooleanVariable(
998 fixed_literal.Variable());
999 if (model_var == -1 || visited_variables.contains(model_var)) {
1006 visited_variables.insert(model_var);
1007 model_variables.push_back(model_var);
1008 if (fixed_literal.IsPositive()) {
1009 new_lower_bounds.push_back(1);
1010 new_upper_bounds.push_back(1);
1012 new_lower_bounds.push_back(0);
1013 new_upper_bounds.push_back(0);
1017 if (!model_variables.empty()) {
1018 shared_bounds_manager->ReportPotentialNewBounds(
1024 if (!
model->Get<SatParameters>()->interleave_search()) {
1025 shared_bounds_manager->Synchronize();
1029 model->GetOrCreate<GenericLiteralWatcher>()
1030 ->RegisterLevelZeroModifiedVariablesCallback(broadcast_level_zero_bounds);
1036 void RegisterVariableBoundsLevelZeroImport(
1037 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
1039 CHECK(shared_bounds_manager !=
nullptr);
1040 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1041 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
1042 const int id = shared_bounds_manager->RegisterNewId();
1044 const auto& import_level_zero_bounds = [&
model_proto, shared_bounds_manager,
1045 model, integer_trail, id, mapping]() {
1046 std::vector<int> model_variables;
1047 std::vector<int64> new_lower_bounds;
1048 std::vector<int64> new_upper_bounds;
1049 shared_bounds_manager->GetChangedBounds(
1050 id, &model_variables, &new_lower_bounds, &new_upper_bounds);
1051 bool new_bounds_have_been_imported =
false;
1052 for (
int i = 0; i < model_variables.size(); ++i) {
1053 const int model_var = model_variables[i];
1056 if (!mapping->IsInteger(model_var))
continue;
1057 const IntegerVariable
var = mapping->Integer(model_var);
1058 const IntegerValue new_lb(new_lower_bounds[i]);
1059 const IntegerValue new_ub(new_upper_bounds[i]);
1060 const IntegerValue old_lb = integer_trail->LowerBound(
var);
1061 const IntegerValue old_ub = integer_trail->UpperBound(
var);
1062 const bool changed_lb = new_lb > old_lb;
1063 const bool changed_ub = new_ub < old_ub;
1064 if (!changed_lb && !changed_ub)
continue;
1066 new_bounds_have_been_imported =
true;
1068 const IntegerVariableProto& var_proto =
1070 const std::string& var_name =
1071 var_proto.name().empty()
1072 ? absl::StrCat(
"anonymous_var(", model_var,
")")
1074 LOG(
INFO) <<
" '" <<
model->Name() <<
"' imports new bounds for "
1075 << var_name <<
": from [" << old_lb <<
", " << old_ub
1076 <<
"] to [" << new_lb <<
", " << new_ub <<
"]";
1090 if (new_bounds_have_been_imported &&
1091 !
model->GetOrCreate<SatSolver>()->FinishPropagation()) {
1096 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
1097 import_level_zero_bounds);
1102 void RegisterObjectiveBestBoundExport(
1103 IntegerVariable objective_var,
1104 SharedResponseManager* shared_response_manager, Model*
model) {
1105 auto* integer_trail =
model->Get<IntegerTrail>();
1106 const auto broadcast_objective_lower_bound =
1107 [objective_var, integer_trail, shared_response_manager,
1108 model](
const std::vector<IntegerVariable>& unused) {
1109 shared_response_manager->UpdateInnerObjectiveBounds(
1110 model->Name(), integer_trail->LevelZeroLowerBound(objective_var),
1111 integer_trail->LevelZeroUpperBound(objective_var));
1113 if (!
model->Get<SatParameters>()->interleave_search()) {
1114 shared_response_manager->Synchronize();
1117 model->GetOrCreate<GenericLiteralWatcher>()
1118 ->RegisterLevelZeroModifiedVariablesCallback(
1119 broadcast_objective_lower_bound);
1125 void RegisterObjectiveBoundsImport(
1126 SharedResponseManager* shared_response_manager, Model*
model) {
1127 auto* solver =
model->GetOrCreate<SatSolver>();
1128 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1129 auto* objective =
model->GetOrCreate<ObjectiveDefinition>();
1131 const auto import_objective_bounds = [
name, solver, integer_trail, objective,
1132 shared_response_manager]() {
1133 if (solver->AssumptionLevel() != 0)
return true;
1134 bool propagate =
false;
1136 const IntegerValue external_lb =
1137 shared_response_manager->SynchronizedInnerObjectiveLowerBound();
1138 const IntegerValue current_lb =
1139 integer_trail->LowerBound(objective->objective_var);
1140 if (external_lb > current_lb) {
1142 objective->objective_var, external_lb),
1149 const IntegerValue external_ub =
1150 shared_response_manager->SynchronizedInnerObjectiveUpperBound();
1151 const IntegerValue current_ub =
1152 integer_trail->UpperBound(objective->objective_var);
1153 if (external_ub < current_ub) {
1155 objective->objective_var, external_ub),
1162 if (!propagate)
return true;
1164 VLOG(2) <<
"'" <<
name <<
"' imports objective bounds: external ["
1165 << objective->ScaleIntegerObjective(external_lb) <<
", "
1166 << objective->ScaleIntegerObjective(external_ub) <<
"], current ["
1167 << objective->ScaleIntegerObjective(current_lb) <<
", "
1168 << objective->ScaleIntegerObjective(current_ub) <<
"]";
1170 return solver->FinishPropagation();
1173 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
1174 import_objective_bounds);
1177 void LoadBaseModel(
const CpModelProto&
model_proto,
1178 SharedResponseManager* shared_response_manager,
1180 CHECK(shared_response_manager !=
nullptr);
1181 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1184 const auto unsat = [shared_response_manager, sat_solver,
model] {
1185 sat_solver->NotifyThatModelIsUnsat();
1186 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1187 absl::StrCat(
model->Name(),
" [loading]"));
1191 model->GetOrCreate<IntegerEncoder>()->DisableImplicationBetweenLiteral();
1193 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1194 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1195 const bool view_all_booleans_as_integers =
1197 (
parameters.search_branching() == SatParameters::FIXED_SEARCH &&
1199 mapping->CreateVariables(
model_proto, view_all_booleans_as_integers,
model);
1214 if (sat_solver->IsModelUnsat())
return unsat();
1220 std::set<std::string> unsupported_types;
1221 int num_ignored_constraints = 0;
1222 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1223 if (mapping->ConstraintIsAlreadyLoaded(&
ct)) {
1224 ++num_ignored_constraints;
1239 if (sat_solver->FinishPropagation()) {
1240 Trail* trail =
model->GetOrCreate<Trail>();
1241 const int old_num_fixed = trail->Index();
1242 if (trail->Index() > old_num_fixed) {
1243 VLOG(3) <<
"Constraint fixed " << trail->Index() - old_num_fixed
1248 if (sat_solver->IsModelUnsat()) {
1249 VLOG(2) <<
"UNSAT during extraction (after adding '"
1255 if (num_ignored_constraints > 0) {
1256 VLOG(3) << num_ignored_constraints <<
" constraints were skipped.";
1258 if (!unsupported_types.empty()) {
1259 VLOG(1) <<
"There is unsupported constraints types in this model: ";
1260 for (
const std::string& type : unsupported_types) {
1261 VLOG(1) <<
" - " << type;
1266 model->GetOrCreate<IntegerEncoder>()
1267 ->AddAllImplicationsBetweenAssociatedLiterals();
1268 if (!sat_solver->FinishPropagation())
return unsat();
1271 void LoadFeasibilityPump(
const CpModelProto&
model_proto,
1272 SharedResponseManager* shared_response_manager,
1274 CHECK(shared_response_manager !=
nullptr);
1278 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1279 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1280 if (
parameters.linearization_level() == 0)
return;
1283 const LinearRelaxation relaxation = ComputeLinearRelaxation(
1285 const int num_lp_constraints = relaxation.linear_constraints.size();
1286 if (num_lp_constraints == 0)
return;
1287 auto* feasibility_pump =
model->GetOrCreate<FeasibilityPump>();
1288 for (
int i = 0; i < num_lp_constraints; i++) {
1289 feasibility_pump->AddLinearConstraint(relaxation.linear_constraints[i]);
1293 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
1294 const IntegerVariable
var =
1295 mapping->Integer(
model_proto.objective().vars(i));
1297 feasibility_pump->SetObjectiveCoefficient(
var, IntegerValue(coeff));
1307 SharedResponseManager* shared_response_manager, Model*
model) {
1308 CHECK(shared_response_manager !=
nullptr);
1309 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1314 const auto unsat = [shared_response_manager, sat_solver,
model] {
1315 sat_solver->NotifyThatModelIsUnsat();
1316 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1317 absl::StrCat(
model->Name(),
" [loading]"));
1320 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1321 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1327 if (
model->Mutable<PrecedencesPropagator>() !=
nullptr &&
1328 parameters.auto_detect_greater_than_at_least_one_of()) {
1329 model->Mutable<PrecedencesPropagator>()
1330 ->AddGreaterThanAtLeastOneOfConstraints(
model);
1331 if (!sat_solver->FinishPropagation())
return unsat();
1337 if (
parameters.cp_model_probing_level() > 1) {
1338 Prober* prober =
model->GetOrCreate<Prober>();
1339 prober->ProbeBooleanVariables(1.0);
1340 if (
model->GetOrCreate<SatSolver>()->IsModelUnsat()) {
1343 if (!
model->GetOrCreate<BinaryImplicationGraph>()
1344 ->ComputeTransitiveReduction()) {
1357 const CpObjectiveProto& obj =
model_proto.objective();
1358 std::vector<std::pair<IntegerVariable, int64>> terms;
1359 terms.reserve(obj.vars_size());
1360 for (
int i = 0; i < obj.vars_size(); ++i) {
1362 std::make_pair(mapping->Integer(obj.vars(i)), obj.coeffs(i)));
1365 objective_var = GetOrCreateVariableWithTightBound(terms,
model);
1367 objective_var = GetOrCreateVariableGreaterOrEqualToSumOf(terms,
model);
1374 const CpObjectiveProto& objective_proto =
model_proto.objective();
1375 auto* objective_definition =
model->GetOrCreate<ObjectiveDefinition>();
1377 objective_definition->scaling_factor = objective_proto.scaling_factor();
1378 if (objective_definition->scaling_factor == 0.0) {
1379 objective_definition->scaling_factor = 1.0;
1381 objective_definition->offset = objective_proto.offset();
1382 objective_definition->objective_var = objective_var;
1384 const int size = objective_proto.vars_size();
1385 objective_definition->vars.resize(size);
1386 objective_definition->coeffs.resize(size);
1387 for (
int i = 0; i < objective_proto.vars_size(); ++i) {
1390 objective_definition->vars[i] = mapping->Integer(objective_proto.vars(i));
1391 objective_definition->coeffs[i] = IntegerValue(objective_proto.coeffs(i));
1394 const int ref = objective_proto.vars(i);
1395 if (mapping->IsInteger(ref)) {
1396 const IntegerVariable
var = mapping->Integer(objective_proto.vars(i));
1397 objective_definition->objective_impacting_variables.insert(
1403 model->TakeOwnership(
1404 new LevelZeroEquality(objective_var, objective_definition->vars,
1405 objective_definition->coeffs,
model));
1411 const Domain automatic_domain =
1412 model->GetOrCreate<IntegerTrail>()->InitialVariableDomain(
1415 <<
" scaling_factor:" <<
model_proto.objective().scaling_factor();
1416 VLOG(3) <<
"Automatic internal objective domain: " << automatic_domain;
1417 VLOG(3) <<
"User specified internal objective domain: " << user_domain;
1419 const bool ok =
model->GetOrCreate<IntegerTrail>()->UpdateInitialDomain(
1420 objective_var, user_domain);
1422 VLOG(2) <<
"UNSAT due to the objective domain.";
1433 if (!automatic_domain.IsIncludedIn(user_domain)) {
1434 std::vector<IntegerVariable> vars;
1435 std::vector<int64> coeffs;
1436 const CpObjectiveProto& obj =
model_proto.objective();
1437 for (
int i = 0; i < obj.vars_size(); ++i) {
1438 vars.push_back(mapping->Integer(obj.vars(i)));
1439 coeffs.push_back(obj.coeffs(i));
1441 vars.push_back(objective_var);
1442 coeffs.push_back(-1);
1449 if (!sat_solver->FinishPropagation())
return unsat();
1453 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1454 shared_response_manager->UpdateInnerObjectiveBounds(
1455 "init", integer_trail->LowerBound(objective_var),
1456 integer_trail->UpperBound(objective_var));
1459 RegisterObjectiveBestBoundExport(objective_var, shared_response_manager,
1465 if (
model->GetOrCreate<SatParameters>()->share_objective_bounds()) {
1466 RegisterObjectiveBoundsImport(shared_response_manager,
model);
1472 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1473 auto* lp_dispatcher =
model->GetOrCreate<LinearProgrammingDispatcher>();
1474 auto* lp_vars =
model->GetOrCreate<LPVariables>();
1475 IntegerVariable size = integer_trail->NumIntegerVariables();
1476 for (IntegerVariable positive_var(0); positive_var < size;
1477 positive_var += 2) {
1479 lp_var.positive_var = positive_var;
1481 mapping->GetProtoVariableFromIntegerVariable(positive_var);
1484 if (lp_var.model_var >= 0) {
1485 lp_vars->vars.push_back(lp_var);
1486 lp_vars->model_vars_size =
1487 std::max(lp_vars->model_vars_size, lp_var.model_var + 1);
1492 auto* search_heuristics =
model->GetOrCreate<SearchHeuristics>();
1496 search_heuristics->fixed_search =
1498 search_heuristics->fixed_search,
model);
1502 std::vector<BooleanOrIntegerVariable> vars;
1503 std::vector<IntegerValue> values;
1504 for (
int i = 0; i <
model_proto.solution_hint().vars_size(); ++i) {
1505 const int ref =
model_proto.solution_hint().vars(i);
1507 BooleanOrIntegerVariable
var;
1508 if (mapping->IsBoolean(ref)) {
1509 var.bool_var = mapping->Literal(ref).Variable();
1511 var.int_var = mapping->Integer(ref);
1513 vars.push_back(
var);
1514 values.push_back(IntegerValue(
model_proto.solution_hint().values(i)));
1522 const std::string solution_info =
model->Name();
1524 shared_response_manager]() {
1527 response.set_solution_info(solution_info);
1531 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1532 CoreBasedOptimizer* core =
1533 new CoreBasedOptimizer(objective_var, objective.vars, objective.coeffs,
1534 solution_observer,
model);
1535 model->Register<CoreBasedOptimizer>(core);
1536 model->TakeOwnership(core);
1546 void SolveLoadedCpModel(
const CpModelProto&
model_proto,
1547 SharedResponseManager* shared_response_manager,
1549 if (shared_response_manager->ProblemIsSolved())
return;
1551 const std::string& solution_info =
model->Name();
1553 &shared_response_manager]() {
1556 response.set_solution_info(solution_info);
1563 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1565 const SatParameters&
parameters = *
model->GetOrCreate<SatParameters>();
1567 std::vector<BooleanVariable> bool_vars;
1568 std::vector<IntegerVariable> int_vars;
1569 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1570 absl::flat_hash_set<BooleanVariable> visited;
1571 for (
int v = 0; v <
model_proto.variables_size(); ++v) {
1572 if (mapping.IsBoolean(v)) {
1573 const BooleanVariable bool_var = mapping.Literal(v).Variable();
1574 if (!visited.contains(bool_var)) {
1575 visited.insert(bool_var);
1576 bool_vars.push_back(bool_var);
1579 IntegerVariable
var = mapping.Integer(v);
1580 if (integer_trail->IsFixed(
var))
continue;
1581 int_vars.push_back(
var);
1590 solution_observer();
1591 if (!
parameters.enumerate_all_solutions())
break;
1595 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1599 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1603 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1604 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1606 std::vector<int> core_in_proto_format;
1607 for (
const Literal l : core) {
1608 core_in_proto_format.push_back(
1609 mapping.GetProtoVariableFromBooleanVariable(l.Variable()));
1610 if (!l.IsPositive()) {
1611 core_in_proto_format.back() =
NegatedRef(core_in_proto_format.back());
1614 shared_response_manager->AddUnsatCore(core_in_proto_format);
1618 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1619 const IntegerVariable objective_var = objective.objective_var;
1627 objective, solution_observer,
model);
1629 status =
model->Mutable<CoreBasedOptimizer>()->Optimize();
1634 if (
parameters.binary_search_num_conflicts() >= 0) {
1636 solution_observer,
model);
1639 objective_var, solution_observer,
model);
1647 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1654 shared_response_manager->SetStatsFromModel(
model);
1659 void QuickSolveWithHint(
const CpModelProto&
model_proto,
1660 SharedResponseManager* shared_response_manager,
1663 if (shared_response_manager->ProblemIsSolved())
return;
1667 const SatParameters saved_params = *
parameters;
1669 parameters->set_search_branching(SatParameters::HINT_SEARCH);
1676 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1680 const std::string& solution_info =
model->Name();
1684 response.set_solution_info(absl::StrCat(solution_info,
" [hint]"));
1693 const IntegerVariable objective_var =
1694 model->GetOrCreate<ObjectiveDefinition>()->objective_var;
1695 model->GetOrCreate<SatSolver>()->Backtrack(0);
1696 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1697 if (!integer_trail->Enqueue(
1700 shared_response_manager->GetInnerObjectiveUpperBound()),
1702 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1703 absl::StrCat(solution_info,
" [hint]"));
1704 shared_response_manager->SetStatsFromModel(
model);
1714 void MinimizeL1DistanceWithHint(
const CpModelProto&
model_proto,
1715 SharedResponseManager* shared_response_manager,
1717 SharedTimeLimit* shared_time_limit,
1721 if (shared_response_manager->ProblemIsSolved())
return;
1723 auto*
parameters = local_model.GetOrCreate<SatParameters>();
1727 if (
parameters->enumerate_all_solutions())
return;
1730 const SatParameters saved_params = *
model->GetOrCreate<SatParameters>();
1737 updated_model_proto.clear_objective();
1740 for (
int i = 0; i <
model_proto.solution_hint().vars_size(); ++i) {
1745 const int new_var_index = updated_model_proto.variables_size();
1746 IntegerVariableProto* var_proto = updated_model_proto.add_variables();
1751 var_proto->add_domain(min_domain);
1752 var_proto->add_domain(max_domain);
1755 ConstraintProto*
const linear_constraint_proto =
1756 updated_model_proto.add_constraints();
1757 LinearConstraintProto* linear = linear_constraint_proto->mutable_linear();
1758 linear->add_vars(new_var_index);
1759 linear->add_coeffs(1);
1760 linear->add_vars(
var);
1761 linear->add_coeffs(-1);
1762 linear->add_domain(-
value);
1763 linear->add_domain(-
value);
1766 const int abs_var_index = updated_model_proto.variables_size();
1767 IntegerVariableProto* abs_var_proto = updated_model_proto.add_variables();
1768 const int64 abs_min_domain = 0;
1769 const int64 abs_max_domain =
1770 std::max(std::abs(min_domain), std::abs(max_domain));
1771 abs_var_proto->add_domain(abs_min_domain);
1772 abs_var_proto->add_domain(abs_max_domain);
1773 ConstraintProto*
const abs_constraint_proto =
1774 updated_model_proto.add_constraints();
1775 abs_constraint_proto->mutable_int_max()->set_target(abs_var_index);
1776 abs_constraint_proto->mutable_int_max()->add_vars(new_var_index);
1777 abs_constraint_proto->mutable_int_max()->add_vars(
1780 updated_model_proto.mutable_objective()->add_vars(abs_var_index);
1781 updated_model_proto.mutable_objective()->add_coeffs(1);
1784 SharedResponseManager local_response_manager(
1785 false,
parameters->enumerate_all_solutions(),
1786 &updated_model_proto,
wall_timer, shared_time_limit);
1788 local_model.Register<SharedResponseManager>(&local_response_manager);
1791 LoadCpModel(updated_model_proto, &local_response_manager, &local_model);
1794 const auto& mapping = *local_model.GetOrCreate<CpModelMapping>();
1796 mapping.Literals(updated_model_proto.assumptions()), &local_model);
1798 const std::string& solution_info =
model->Name();
1803 CpSolverResponse updated_response;
1804 FillSolutionInResponse(updated_model_proto, local_model,
1806 LOG(
INFO) <<
"Found solution with repaired hint penalty = "
1810 response.set_solution_info(absl::StrCat(solution_info,
" [repaired]"));
1819 void PostsolveResponseWithFullSolver(
1820 const int64 num_variables_in_original_model, CpModelProto mapping_proto,
1829 if (mapping_proto.variables_size() == 0) {
1834 for (
int i = 0; i <
response->solution_size(); ++i) {
1835 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1836 var_proto->clear_domain();
1837 var_proto->add_domain(
response->solution(i));
1838 var_proto->add_domain(
response->solution(i));
1840 for (
int i = 0; i <
response->solution_lower_bounds_size(); ++i) {
1841 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1844 .IntersectionWith({
response->solution_lower_bounds(i),
1845 response->solution_upper_bounds(i)}),
1852 Model postsolve_model;
1854 SatParameters& params = *postsolve_model.GetOrCreate<SatParameters>();
1855 params.set_linearization_level(0);
1856 params.set_cp_model_probing_level(0);
1860 SharedTimeLimit shared_time_limit(
time_limit.get());
1861 SharedResponseManager local_response_manager(
1862 false,
false, &mapping_proto,
1864 LoadCpModel(mapping_proto, &local_response_manager, &postsolve_model);
1865 SolveLoadedCpModel(mapping_proto, &local_response_manager, &postsolve_model);
1866 const CpSolverResponse postsolve_response =
1867 local_response_manager.GetResponse();
1873 response->clear_solution_lower_bounds();
1874 response->clear_solution_upper_bounds();
1875 if (!postsolve_response.solution().empty()) {
1876 for (
int i = 0; i < num_variables_in_original_model; ++i) {
1877 response->add_solution(postsolve_response.solution(i));
1880 for (
int i = 0; i < num_variables_in_original_model; ++i) {
1881 response->add_solution_lower_bounds(
1882 postsolve_response.solution_lower_bounds(i));
1883 response->add_solution_upper_bounds(
1884 postsolve_response.solution_upper_bounds(i));
1889 void PostsolveResponseWrapper(
const SatParameters& params,
1890 const int64 num_variables_in_original_model,
1891 const CpModelProto& mapping_proto,
1892 const std::vector<int>& postsolve_mapping,
1895 if (params.cp_model_postsolve_with_full_solver()) {
1896 PostsolveResponseWithFullSolver(num_variables_in_original_model,
1897 mapping_proto, postsolve_mapping,
1906 CpSolverResponse SolvePureSatModel(
const CpModelProto&
model_proto,
1908 std::unique_ptr<SatSolver> solver(
new SatSolver());
1911 model->GetOrCreate<TimeLimit>()->ResetLimitFromParameters(
parameters);
1914 std::unique_ptr<DratProofHandler> drat_proof_handler;
1915 #if !defined(__PORTABLE_PLATFORM__)
1916 if (!absl::GetFlag(FLAGS_drat_output).empty() ||
1917 absl::GetFlag(FLAGS_drat_check)) {
1918 if (!absl::GetFlag(FLAGS_drat_output).empty()) {
1922 drat_proof_handler = absl::make_unique<DratProofHandler>(
1923 false, output, absl::GetFlag(FLAGS_drat_check));
1925 drat_proof_handler = absl::make_unique<DratProofHandler>();
1927 solver->SetDratProofHandler(drat_proof_handler.get());
1931 auto get_literal = [](
int ref) {
1932 if (ref >= 0)
return Literal(BooleanVariable(ref),
true);
1933 return Literal(BooleanVariable(
NegatedRef(ref)),
false);
1936 std::vector<Literal> temp;
1937 const int num_variables =
model_proto.variables_size();
1938 solver->SetNumVariables(num_variables);
1939 if (drat_proof_handler !=
nullptr) {
1940 drat_proof_handler->SetNumVariables(num_variables);
1944 for (
int ref = 0; ref < num_variables; ++ref) {
1946 if (domain.IsFixed()) {
1947 const Literal ref_literal =
1948 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
1949 drat_proof_handler->AddProblemClause({ref_literal});
1952 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1953 switch (
ct.constraint_case()) {
1954 case ConstraintProto::ConstraintCase::kBoolAnd: {
1955 if (
ct.enforcement_literal_size() == 0) {
1956 for (
const int ref :
ct.bool_and().literals()) {
1957 drat_proof_handler->AddProblemClause({get_literal(ref)});
1961 const Literal not_a =
1962 get_literal(
ct.enforcement_literal(0)).Negated();
1963 for (
const int ref :
ct.bool_and().literals()) {
1964 drat_proof_handler->AddProblemClause({not_a, get_literal(ref)});
1969 case ConstraintProto::ConstraintCase::kBoolOr:
1971 for (
const int ref :
ct.bool_or().literals()) {
1972 temp.push_back(get_literal(ref));
1974 drat_proof_handler->AddProblemClause(temp);
1982 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1983 switch (
ct.constraint_case()) {
1984 case ConstraintProto::ConstraintCase::kBoolAnd: {
1985 if (
ct.enforcement_literal_size() == 0) {
1986 for (
const int ref :
ct.bool_and().literals()) {
1987 const Literal
b = get_literal(ref);
1988 solver->AddUnitClause(
b);
1992 const Literal not_a =
1993 get_literal(
ct.enforcement_literal(0)).Negated();
1994 for (
const int ref :
ct.bool_and().literals()) {
1995 const Literal
b = get_literal(ref);
1996 solver->AddProblemClause({not_a,
b});
2001 case ConstraintProto::ConstraintCase::kBoolOr:
2003 for (
const int ref :
ct.bool_or().literals()) {
2004 temp.push_back(get_literal(ref));
2006 solver->AddProblemClause(temp);
2014 for (
int ref = 0; ref < num_variables; ++ref) {
2016 if (domain.Min() == domain.Max()) {
2017 const Literal ref_literal =
2018 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
2019 solver->AddUnitClause(ref_literal);
2026 std::vector<bool> solution;
2028 &solution, drat_proof_handler.get());
2031 for (
int ref = 0; ref < num_variables; ++ref) {
2032 response.add_solution(solution[ref]);
2036 status = solver->SolveWithTimeLimit(
model->GetOrCreate<TimeLimit>());
2039 for (
int ref = 0; ref < num_variables; ++ref) {
2041 solver->Assignment().LiteralIsTrue(get_literal(ref)) ? 1 : 0);
2048 model->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
2049 solver->model()->GetOrCreate<TimeLimit>()->GetElapsedDeterministicTime());
2058 std::vector<int64>(
response.solution().begin(),
2068 LOG(
FATAL) <<
"Unexpected SatSolver::Status " << status;
2070 response.set_num_booleans(solver->NumVariables());
2071 response.set_num_branches(solver->num_branches());
2072 response.set_num_conflicts(solver->num_failures());
2073 response.set_num_binary_propagations(solver->num_propagations());
2074 response.set_num_integer_propagations(0);
2077 model->Get<TimeLimit>()->GetElapsedDeterministicTime());
2083 absl::GetFlag(FLAGS_max_drat_time_in_seconds));
2084 switch (drat_status) {
2086 LOG(
INFO) <<
"DRAT status: UNKNOWN";
2089 LOG(
INFO) <<
"DRAT status: VALID";
2092 LOG(
ERROR) <<
"DRAT status: INVALID";
2098 LOG(
INFO) <<
"DRAT wall time: " << drat_timer.
Get();
2099 }
else if (drat_proof_handler !=
nullptr) {
2102 LOG(
INFO) <<
"DRAT status: NA";
2103 LOG(
INFO) <<
"DRAT wall time: NA";
2104 LOG(
INFO) <<
"DRAT user time: NA";
2109 #if !defined(__PORTABLE_PLATFORM__)
2112 struct SharedClasses {
2122 bool SearchIsDone() {
2123 if (
response->ProblemIsSolved())
return true;
2130 class FullProblemSolver :
public SubSolver {
2132 FullProblemSolver(
const std::string&
name,
2133 const SatParameters& local_parameters,
bool split_in_chunks,
2134 SharedClasses* shared)
2137 split_in_chunks_(split_in_chunks),
2138 local_model_(
absl::make_unique<Model>(
name)) {
2140 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
2141 shared_->time_limit->UpdateLocalLimit(
2142 local_model_->GetOrCreate<TimeLimit>());
2144 if (shared->response !=
nullptr) {
2145 local_model_->Register<SharedResponseManager>(shared->response);
2148 if (shared->relaxation_solutions !=
nullptr) {
2149 local_model_->Register<SharedRelaxationSolutionRepository>(
2150 shared->relaxation_solutions);
2153 if (shared->lp_solutions !=
nullptr) {
2154 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
2157 if (shared->incomplete_solutions !=
nullptr) {
2158 local_model_->Register<SharedIncompleteSolutionManager>(
2159 shared->incomplete_solutions);
2163 if (shared_->bounds !=
nullptr) {
2164 RegisterVariableBoundsLevelZeroExport(
2165 *shared_->model_proto, shared_->bounds, local_model_.get());
2166 RegisterVariableBoundsLevelZeroImport(
2167 *shared_->model_proto, shared_->bounds, local_model_.get());
2171 bool TaskIsAvailable()
override {
2172 if (shared_->SearchIsDone())
return false;
2174 absl::MutexLock mutex_lock(&mutex_);
2175 return previous_task_is_completed_;
2178 std::function<void()> GenerateTask(
int64 task_id)
override {
2180 absl::MutexLock mutex_lock(&mutex_);
2181 previous_task_is_completed_ =
false;
2184 if (solving_first_chunk_) {
2185 LoadCpModel(*shared_->model_proto, shared_->response,
2186 local_model_.get());
2187 if (local_model_->GetOrCreate<SatParameters>()->repair_hint()) {
2188 MinimizeL1DistanceWithHint(*shared_->model_proto, shared_->response,
2189 shared_->wall_timer, shared_->time_limit,
2190 local_model_.get());
2192 QuickSolveWithHint(*shared_->model_proto, shared_->response,
2193 local_model_.get());
2197 solving_first_chunk_ =
false;
2199 if (split_in_chunks_) {
2201 absl::MutexLock mutex_lock(&mutex_);
2202 previous_task_is_completed_ =
true;
2207 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2208 if (split_in_chunks_) {
2211 auto* params = local_model_->GetOrCreate<SatParameters>();
2212 params->set_max_deterministic_time(1);
2213 time_limit->ResetLimitFromParameters(*params);
2214 shared_->time_limit->UpdateLocalLimit(
time_limit);
2217 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2218 SolveLoadedCpModel(*shared_->model_proto, shared_->response,
2219 local_model_.get());
2221 absl::MutexLock mutex_lock(&mutex_);
2222 deterministic_time_since_last_synchronize_ +=
2223 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2227 if (shared_->SearchIsDone()) {
2228 shared_->time_limit->Stop();
2233 if (split_in_chunks_) {
2234 absl::MutexLock mutex_lock(&mutex_);
2235 previous_task_is_completed_ =
true;
2243 local_model_.reset();
2250 void Synchronize()
override {
2251 absl::MutexLock mutex_lock(&mutex_);
2252 deterministic_time_ += deterministic_time_since_last_synchronize_;
2253 shared_->time_limit->AdvanceDeterministicTime(
2254 deterministic_time_since_last_synchronize_);
2255 deterministic_time_since_last_synchronize_ = 0.0;
2259 SharedClasses* shared_;
2260 const bool split_in_chunks_;
2261 std::unique_ptr<Model> local_model_;
2265 bool solving_first_chunk_ =
true;
2268 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2270 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2273 class FeasibilityPumpSolver :
public SubSolver {
2275 FeasibilityPumpSolver(
const SatParameters& local_parameters,
2276 SharedClasses* shared)
2277 : SubSolver(
"feasibility_pump"),
2279 local_model_(
absl::make_unique<Model>(name_)) {
2281 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
2282 shared_->time_limit->UpdateLocalLimit(
2283 local_model_->GetOrCreate<TimeLimit>());
2285 if (shared->response !=
nullptr) {
2286 local_model_->Register<SharedResponseManager>(shared->response);
2289 if (shared->relaxation_solutions !=
nullptr) {
2290 local_model_->Register<SharedRelaxationSolutionRepository>(
2291 shared->relaxation_solutions);
2294 if (shared->lp_solutions !=
nullptr) {
2295 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
2298 if (shared->incomplete_solutions !=
nullptr) {
2299 local_model_->Register<SharedIncompleteSolutionManager>(
2300 shared->incomplete_solutions);
2304 if (shared_->bounds !=
nullptr) {
2305 RegisterVariableBoundsLevelZeroImport(
2306 *shared_->model_proto, shared_->bounds, local_model_.get());
2310 bool TaskIsAvailable()
override {
2311 if (shared_->SearchIsDone())
return false;
2312 absl::MutexLock mutex_lock(&mutex_);
2313 return previous_task_is_completed_;
2316 std::function<void()> GenerateTask(
int64 task_id)
override {
2319 absl::MutexLock mutex_lock(&mutex_);
2320 if (!previous_task_is_completed_)
return;
2321 previous_task_is_completed_ =
false;
2324 absl::MutexLock mutex_lock(&mutex_);
2325 if (solving_first_chunk_) {
2326 LoadFeasibilityPump(*shared_->model_proto, shared_->response,
2327 local_model_.get());
2330 if (local_model_->Get<FeasibilityPump>() ==
nullptr)
return;
2331 solving_first_chunk_ =
false;
2333 previous_task_is_completed_ =
true;
2338 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2339 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2340 auto* feasibility_pump = local_model_->Mutable<FeasibilityPump>();
2341 if (!feasibility_pump->Solve()) {
2342 shared_->response->NotifyThatImprovingProblemIsInfeasible(name_);
2346 absl::MutexLock mutex_lock(&mutex_);
2347 deterministic_time_since_last_synchronize_ +=
2348 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2352 if (shared_->SearchIsDone()) {
2353 shared_->time_limit->Stop();
2357 absl::MutexLock mutex_lock(&mutex_);
2358 previous_task_is_completed_ =
true;
2362 void Synchronize()
override {
2363 absl::MutexLock mutex_lock(&mutex_);
2364 deterministic_time_ += deterministic_time_since_last_synchronize_;
2365 shared_->time_limit->AdvanceDeterministicTime(
2366 deterministic_time_since_last_synchronize_);
2367 deterministic_time_since_last_synchronize_ = 0.0;
2371 SharedClasses* shared_;
2372 std::unique_ptr<Model> local_model_;
2378 bool solving_first_chunk_ ABSL_GUARDED_BY(mutex_) =
true;
2380 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2382 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2386 class LnsSolver :
public SubSolver {
2388 LnsSolver(std::unique_ptr<NeighborhoodGenerator> generator,
2390 NeighborhoodGeneratorHelper* helper, SharedClasses* shared)
2391 : SubSolver(generator->
name()),
2392 generator_(std::move(generator)),
2397 bool TaskIsAvailable()
override {
2398 if (shared_->SearchIsDone())
return false;
2399 return generator_->ReadyToGenerate();
2402 std::function<void()> GenerateTask(
int64 task_id)
override {
2403 return [task_id,
this]() {
2404 if (shared_->SearchIsDone())
return;
2409 const int32 low =
static_cast<int32>(task_id);
2410 const int32 high = task_id >> 32;
2411 std::seed_seq seed{low, high, parameters_.random_seed()};
2414 NeighborhoodGenerator::SolveData data;
2415 data.difficulty = generator_->difficulty();
2416 data.deterministic_limit = generator_->deterministic_limit();
2419 CpSolverResponse base_response;
2421 const SharedSolutionRepository<int64>& repo =
2422 shared_->response->SolutionsRepository();
2423 if (repo.NumSolutions() > 0) {
2425 const SharedSolutionRepository<int64>::Solution solution =
2426 repo.GetRandomBiasedSolution(random);
2427 for (
const int64 value : solution.variable_values) {
2428 base_response.add_solution(
value);
2432 data.initial_best_objective = repo.GetSolution(0).rank;
2433 data.base_objective = solution.rank;
2442 data.initial_best_objective =
2443 shared_->response->GetInnerObjectiveUpperBound();
2444 data.base_objective = data.initial_best_objective;
2448 Neighborhood neighborhood;
2450 absl::MutexLock mutex_lock(helper_->MutableMutex());
2452 generator_->Generate(base_response, data.difficulty, random);
2454 neighborhood.cp_model.set_name(absl::StrCat(
"lns_", task_id));
2455 if (!neighborhood.is_generated)
return;
2456 data.neighborhood_id = neighborhood.id;
2458 const double fully_solved_proportion =
2459 static_cast<double>(generator_->num_fully_solved_calls()) /
2461 std::string source_info =
name();
2462 if (!neighborhood.source_info.empty()) {
2463 absl::StrAppend(&source_info,
"_", neighborhood.source_info);
2465 const std::string solution_info = absl::StrFormat(
2466 "%s(d=%0.2f s=%i t=%0.2f p=%0.2f)", source_info, data.difficulty,
2467 task_id, data.deterministic_limit, fully_solved_proportion);
2469 SatParameters local_params(parameters_);
2470 local_params.set_max_deterministic_time(data.deterministic_limit);
2471 local_params.set_stop_after_first_solution(
false);
2472 local_params.set_log_search_progress(
false);
2473 local_params.set_cp_model_probing_level(0);
2474 local_params.set_symmetry_level(0);
2476 if (absl::GetFlag(FLAGS_cp_model_dump_lns)) {
2477 const std::string
name =
2478 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2479 neighborhood.cp_model.name(),
".pbtxt");
2480 LOG(
INFO) <<
"Dumping LNS model to '" <<
name <<
"'.";
2485 Model local_model(solution_info);
2486 *(local_model.GetOrCreate<SatParameters>()) = local_params;
2487 TimeLimit* local_time_limit = local_model.GetOrCreate<TimeLimit>();
2488 local_time_limit->ResetLimitFromParameters(local_params);
2489 shared_->time_limit->UpdateLocalLimit(local_time_limit);
2491 const int64 num_neighborhood_model_vars =
2492 neighborhood.cp_model.variables_size();
2494 CpModelProto mapping_proto;
2495 std::vector<int> postsolve_mapping;
2496 auto context = absl::make_unique<PresolveContext>(
2497 VLOG_IS_ON(3), &local_model, &neighborhood.cp_model, &mapping_proto);
2506 SharedResponseManager local_response_manager(
2508 &neighborhood.cp_model, shared_->wall_timer, shared_->time_limit);
2509 LoadCpModel(neighborhood.cp_model, &local_response_manager, &local_model);
2510 QuickSolveWithHint(neighborhood.cp_model, &local_response_manager,
2512 SolveLoadedCpModel(neighborhood.cp_model, &local_response_manager,
2514 CpSolverResponse local_response = local_response_manager.GetResponse();
2518 PostsolveResponseWrapper(local_params, num_neighborhood_model_vars,
2519 mapping_proto, postsolve_mapping,
2520 shared_->wall_timer, &local_response);
2521 data.status = local_response.status();
2522 data.deterministic_time = local_time_limit->GetElapsedDeterministicTime();
2524 if (generator_->IsRelaxationGenerator()) {
2525 bool has_feasible_solution =
false;
2528 has_feasible_solution =
true;
2532 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2533 local_response.solution_info());
2536 if (shared_->model_proto->has_objective()) {
2539 const IntegerValue current_obj_lb =
2540 shared_->response->GetInnerObjectiveLowerBound();
2542 const IntegerValue local_obj_lb =
2543 local_response_manager.GetInnerObjectiveLowerBound();
2546 neighborhood.cp_model.objective(), local_obj_lb.value());
2549 const IntegerValue new_inner_obj_lb = IntegerValue(
2551 scaled_local_obj_bound) -
2553 data.new_objective_bound = new_inner_obj_lb;
2554 data.initial_best_objective_bound = current_obj_lb;
2555 if (new_inner_obj_lb > current_obj_lb) {
2556 shared_->response->UpdateInnerObjectiveBounds(
2563 if (has_feasible_solution) {
2565 *shared_->model_proto,
2566 std::vector<int64>(local_response.solution().begin(),
2567 local_response.solution().end()))) {
2568 shared_->response->NewSolution(local_response,
2573 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2574 local_response.solution_info());
2575 shared_->time_limit->Stop();
2578 shared_->relaxation_solutions->NewRelaxationSolution(local_response);
2581 if (!local_response.solution().empty()) {
2583 *shared_->model_proto,
2584 std::vector<int64>(local_response.solution().begin(),
2585 local_response.solution().end())))
2590 data.new_objective = data.base_objective;
2594 shared_->model_proto->objective(), local_response));
2600 shared_->response->NewSolution(local_response,
2603 if (!neighborhood.is_reduced &&
2606 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2607 local_response.solution_info());
2608 shared_->time_limit->Stop();
2612 generator_->AddSolveData(data);
2615 const int total_num_calls = task_id;
2616 VLOG(2) <<
name() <<
": [difficulty: " << data.difficulty
2617 <<
", id: " << task_id
2618 <<
", deterministic_time: " << data.deterministic_time <<
" / "
2619 << data.deterministic_limit
2620 <<
", status: " << ProtoEnumToString<CpSolverStatus>(data.status)
2621 <<
", num calls: " << generator_->num_calls()
2622 <<
", UCB1 Score: " << generator_->GetUCBScore(total_num_calls)
2623 <<
", p: " << fully_solved_proportion <<
"]";
2627 void Synchronize()
override {
2628 generator_->Synchronize();
2629 const double old = deterministic_time_;
2630 deterministic_time_ = generator_->deterministic_time();
2631 shared_->time_limit->AdvanceDeterministicTime(deterministic_time_ - old);
2635 std::unique_ptr<NeighborhoodGenerator> generator_;
2636 NeighborhoodGeneratorHelper* helper_;
2637 const SatParameters parameters_;
2638 SharedClasses* shared_;
2641 void SolveCpModelParallel(
const CpModelProto&
model_proto,
2642 SharedResponseManager* shared_response_manager,
2643 SharedTimeLimit* shared_time_limit,
2645 CHECK(shared_response_manager !=
nullptr);
2646 const SatParameters&
parameters = *global_model->GetOrCreate<SatParameters>();
2647 const int num_search_workers =
parameters.num_search_workers();
2650 <<
"Enumerating all solutions in parallel is not supported.";
2652 std::unique_ptr<SharedBoundsManager> shared_bounds_manager;
2654 shared_bounds_manager = absl::make_unique<SharedBoundsManager>(
model_proto);
2657 std::unique_ptr<SharedRelaxationSolutionRepository>
2658 shared_relaxation_solutions;
2660 shared_relaxation_solutions =
2661 absl::make_unique<SharedRelaxationSolutionRepository>(
2663 global_model->Register<SharedRelaxationSolutionRepository>(
2664 shared_relaxation_solutions.get());
2667 auto shared_lp_solutions = absl::make_unique<SharedLPSolutionRepository>(
2669 global_model->Register<SharedLPSolutionRepository>(shared_lp_solutions.get());
2673 std::unique_ptr<SharedIncompleteSolutionManager> shared_incomplete_solutions;
2674 const bool use_feasibility_pump =
parameters.use_feasibility_pump() &&
2678 if (use_feasibility_pump) {
2679 shared_incomplete_solutions =
2680 absl::make_unique<SharedIncompleteSolutionManager>();
2681 global_model->Register<SharedIncompleteSolutionManager>(
2682 shared_incomplete_solutions.get());
2685 SharedClasses shared;
2688 shared.time_limit = shared_time_limit;
2689 shared.bounds = shared_bounds_manager.get();
2690 shared.response = shared_response_manager;
2691 shared.relaxation_solutions = shared_relaxation_solutions.get();
2692 shared.lp_solutions = shared_lp_solutions.get();
2693 shared.incomplete_solutions = shared_incomplete_solutions.get();
2696 std::vector<std::unique_ptr<SubSolver>> subsolvers;
2699 subsolvers.push_back(absl::make_unique<SynchronizationPoint>(
2700 [shared_response_manager, &shared_bounds_manager,
2701 &shared_relaxation_solutions, &shared_lp_solutions]() {
2702 shared_response_manager->Synchronize();
2703 shared_response_manager->MutableSolutionsRepository()->Synchronize();
2704 if (shared_bounds_manager !=
nullptr) {
2705 shared_bounds_manager->Synchronize();
2707 if (shared_relaxation_solutions !=
nullptr) {
2708 shared_relaxation_solutions->Synchronize();
2710 if (shared_lp_solutions !=
nullptr) {
2711 shared_lp_solutions->Synchronize();
2720 local_params.set_stop_after_first_solution(
true);
2721 local_params.set_linearization_level(0);
2722 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2723 "first_solution", local_params,
2729 if (
parameters.optimize_with_max_hs())
continue;
2731 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2732 local_params.name(), local_params,
2738 if (use_feasibility_pump) {
2739 subsolvers.push_back(
2740 absl::make_unique<FeasibilityPumpSolver>(
parameters, &shared));
2747 auto unique_helper = absl::make_unique<NeighborhoodGeneratorHelper>(
2749 shared_bounds_manager.get());
2750 NeighborhoodGeneratorHelper* helper = unique_helper.get();
2751 subsolvers.push_back(std::move(unique_helper));
2754 std::vector<SatParameters> lns_params = {
parameters};
2755 lns_params.back().set_name(
"default");
2757 std::vector<SatParameters> lns_params =
2760 for (
const SatParameters& local_params : lns_params) {
2765 subsolvers.push_back(absl::make_unique<LnsSolver>(
2766 absl::make_unique<SimpleNeighborhoodGenerator>(
2767 helper, absl::StrCat(
"rnd_var_lns_", local_params.name())),
2768 local_params, helper, &shared));
2769 subsolvers.push_back(absl::make_unique<LnsSolver>(
2770 absl::make_unique<SimpleConstraintNeighborhoodGenerator>(
2771 helper, absl::StrCat(
"rnd_cst_lns_", local_params.name())),
2772 local_params, helper, &shared));
2773 subsolvers.push_back(absl::make_unique<LnsSolver>(
2774 absl::make_unique<VariableGraphNeighborhoodGenerator>(
2775 helper, absl::StrCat(
"graph_var_lns_", local_params.name())),
2776 local_params, helper, &shared));
2777 subsolvers.push_back(absl::make_unique<LnsSolver>(
2778 absl::make_unique<ConstraintGraphNeighborhoodGenerator>(
2779 helper, absl::StrCat(
"graph_cst_lns_", local_params.name())),
2780 local_params, helper, &shared));
2782 if (!helper->TypeToConstraints(ConstraintProto::kNoOverlap).empty()) {
2783 subsolvers.push_back(absl::make_unique<LnsSolver>(
2784 absl::make_unique<SchedulingTimeWindowNeighborhoodGenerator>(
2785 helper, absl::StrCat(
"scheduling_time_window_lns_",
2786 local_params.name())),
2787 local_params, helper, &shared));
2788 subsolvers.push_back(absl::make_unique<LnsSolver>(
2789 absl::make_unique<SchedulingNeighborhoodGenerator>(
2791 absl::StrCat(
"scheduling_random_lns_", local_params.name())),
2792 local_params, helper, &shared));
2805 subsolvers.push_back(absl::make_unique<LnsSolver>(
2806 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2807 helper, shared.response, shared.relaxation_solutions,
2808 shared.lp_solutions,
nullptr,
2809 absl::StrCat(
"rins_lns_", local_params.name())),
2810 local_params, helper, &shared));
2813 subsolvers.push_back(absl::make_unique<LnsSolver>(
2814 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2815 helper,
nullptr, shared.relaxation_solutions,
2816 shared.lp_solutions, shared.incomplete_solutions,
2817 absl::StrCat(
"rens_lns_", local_params.name())),
2818 local_params, helper, &shared));
2822 subsolvers.push_back(absl::make_unique<LnsSolver>(
2824 ConsecutiveConstraintsRelaxationNeighborhoodGenerator>(
2825 helper, absl::StrCat(
"rnd_rel_lns_", local_params.name())),
2826 local_params, helper, &shared));
2828 subsolvers.push_back(absl::make_unique<LnsSolver>(
2829 absl::make_unique<WeightedRandomRelaxationNeighborhoodGenerator>(
2830 helper, absl::StrCat(
"wgt_rel_lns_", local_params.name())),
2831 local_params, helper, &shared));
2838 subsolvers.push_back(
2839 absl::make_unique<SynchronizationPoint>([shared_response_manager]() {
2840 shared_response_manager->UpdatePrimalIntegral();
2845 std::vector<std::string> names;
2846 for (
const auto& subsolver : subsolvers) {
2847 if (!subsolver->name().empty()) names.push_back(subsolver->name());
2850 "*** starting Search at %.2fs with %i workers and subsolvers: [ %s ]",
2851 wall_timer->
Get(), num_search_workers, absl::StrJoin(names,
", "));
2868 void AddPostsolveClauses(
const std::vector<int>& postsolve_mapping,
2869 Model*
model, CpModelProto* mapping_proto) {
2870 auto* mapping =
model->GetOrCreate<CpModelMapping>();
2871 auto* postsolve =
model->GetOrCreate<PostsolveClauses>();
2872 for (
const auto& clause : postsolve->clauses) {
2873 auto*
ct = mapping_proto->add_constraints()->mutable_bool_or();
2874 for (
const Literal l : clause) {
2875 int var = mapping->GetProtoVariableFromBooleanVariable(l.Variable());
2877 var = postsolve_mapping[
var];
2881 postsolve->clauses.clear();
2892 #if defined(_MSC_VER)
2896 std::unique_ptr<CpSolverResponse> final_response_ptr(
new CpSolverResponse());
2897 CpSolverResponse& final_response = *final_response_ptr.get();
2899 CpSolverResponse final_response;
2902 #if !defined(__PORTABLE_PLATFORM__)
2904 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
2905 const std::string
file =
2906 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
"model.pbtxt");
2907 LOG(
INFO) <<
"Dumping cp model proto to '" <<
file <<
"'.";
2912 if (absl::GetFlag(FLAGS_cp_model_dump_response)) {
2913 const std::string
file = absl::StrCat(
2914 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"response.pbtxt");
2915 LOG(
INFO) <<
"Dumping response proto to '" <<
file <<
"'.";
2921 if (!absl::GetFlag(FLAGS_cp_model_params).empty()) {
2922 SatParameters params = *
model->GetOrCreate<SatParameters>();
2923 SatParameters flag_params;
2924 CHECK(google::protobuf::TextFormat::ParseFromString(
2925 absl::GetFlag(FLAGS_cp_model_params), &flag_params));
2926 params.MergeFrom(flag_params);
2927 *(
model->GetOrCreate<SatParameters>()) = params;
2933 *
model->GetOrCreate<SatParameters>());
2936 #if !defined(__PORTABLE_PLATFORM__)
2939 if (
model->GetOrCreate<SatParameters>()->catch_sigint_signal()) {
2940 handler.
Register([&shared_time_limit]() { shared_time_limit.Stop(); });
2944 const SatParameters& params = *
model->GetOrCreate<SatParameters>();
2945 const bool log_search = params.log_search_progress() ||
VLOG_IS_ON(1);
2946 LOG_IF(
INFO, log_search) <<
"Parameters: " << params.ShortDebugString();
2947 if (log_search && params.use_absl_random()) {
2952 auto display_response_cleanup =
2964 if (!error.empty()) {
2967 return final_response;
2976 if (!params.use_sat_inprocessing() && !
model_proto.has_objective() &&
2977 !
model_proto.has_solution_hint() && !params.enumerate_all_solutions() &&
2978 !params.use_lns_only() && params.num_search_workers() <= 1 &&
2980 bool is_pure_sat =
true;
2981 for (
const IntegerVariableProto&
var :
model_proto.variables()) {
2982 if (
var.domain_size() != 2 ||
var.domain(0) < 0 ||
var.domain(1) > 1) {
2983 is_pure_sat =
false;
2988 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
2989 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolOr &&
2990 ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolAnd) {
2991 is_pure_sat =
false;
3001 final_response.set_user_time(user_timer.
Get());
3002 final_response.set_deterministic_time(
3003 shared_time_limit.GetElapsedDeterministicTime());
3004 const SatParameters& params = *
model->GetOrCreate<SatParameters>();
3005 if (params.fill_tightened_domains_in_response()) {
3006 *final_response.mutable_tightened_variables() =
model_proto.variables();
3008 return final_response;
3017 CpModelProto mapping_proto;
3018 auto context = absl::make_unique<PresolveContext>(
3019 log_search,
model, &new_cp_model_proto, &mapping_proto);
3021 bool degraded_assumptions_support =
false;
3022 if (params.num_search_workers() > 1 ||
model_proto.has_objective()) {
3029 degraded_assumptions_support =
true;
3030 context->InitializeNewDomains();
3032 if (!
context->SetLiteralToTrue(ref)) {
3034 final_response.add_sufficient_assumptions_for_infeasibility(ref);
3035 return final_response;
3042 std::function<void(CpSolverResponse *
response)> postprocess_solution;
3045 std::vector<int> postsolve_mapping;
3048 LOG(
ERROR) <<
"Error while presolving, likely due to integer overflow.";
3050 return final_response;
3053 if (params.cp_model_presolve()) {
3054 postprocess_solution = [&
model_proto, ¶ms, &mapping_proto,
3055 &shared_time_limit, &postsolve_mapping, &
wall_timer,
3057 AddPostsolveClauses(postsolve_mapping,
model, &mapping_proto);
3058 PostsolveResponseWrapper(params,
model_proto.variables_size(),
3059 mapping_proto, postsolve_mapping, &
wall_timer,
3061 if (!
response->solution().empty()) {
3064 std::vector<int64>(
response->solution().begin(),
3066 &mapping_proto, &postsolve_mapping))
3067 <<
"final postsolved solution";
3069 if (params.fill_tightened_domains_in_response()) {
3071 if (mapping_proto.variables().size() >=
3073 for (
int i = 0; i <
model_proto.variables().size(); ++i) {
3074 *
response->add_tightened_variables() = mapping_proto.variables(i);
3079 response->set_user_time(user_timer.Get());
3081 shared_time_limit.GetElapsedDeterministicTime());
3086 &user_timer](CpSolverResponse*
response) {
3088 const int initial_size =
model_proto.variables_size();
3089 if (
response->solution_size() > 0) {
3090 response->mutable_solution()->Truncate(initial_size);
3091 }
else if (
response->solution_lower_bounds_size() > 0) {
3092 response->mutable_solution_lower_bounds()->Truncate(initial_size);
3093 response->mutable_solution_upper_bounds()->Truncate(initial_size);
3095 if (params.fill_tightened_domains_in_response()) {
3101 shared_time_limit.GetElapsedDeterministicTime());
3108 if (params.symmetry_level() > 1) {
3113 log_search, params.enumerate_all_solutions(), &new_cp_model_proto,
3116 absl::GetFlag(FLAGS_cp_model_dump_prefix));
3120 if (!observers.empty()) {
3122 [&
model_proto, &observers, &postprocess_solution](
3123 const CpSolverResponse& response_of_presolved_problem) {
3124 CpSolverResponse
response = response_of_presolved_problem;
3126 if (!
response.solution().empty()) {
3128 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
3135 for (
const auto& observer : observers) {
3145 if (new_cp_model_proto.has_objective()) {
3149 "initial domain", IntegerValue(domain.
Min()),
3150 IntegerValue(domain.
Max()));
3158 #if !defined(__PORTABLE_PLATFORM__)
3159 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
3160 const std::string presolved_file = absl::StrCat(
3161 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"presolved_model.pbtxt");
3162 LOG(
INFO) <<
"Dumping presolved cp model proto to '" << presolved_file
3167 const std::string mapping_file = absl::StrCat(
3168 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"mapping_model.pbtxt");
3169 LOG(
INFO) <<
"Dumping mapping cp model proto to '" << mapping_file <<
"'.";
3174 if (params.stop_after_presolve() || shared_time_limit.LimitReached()) {
3175 int64 num_terms = 0;
3176 for (
const ConstraintProto&
ct : new_cp_model_proto.constraints()) {
3180 <<
"Stopped after presolve."
3181 <<
"\nPresolvedNumVariables: " << new_cp_model_proto.variables().size()
3182 <<
"\nPresolvedNumConstraints: "
3183 << new_cp_model_proto.constraints().size()
3184 <<
"\nPresolvedNumTerms: " << num_terms;
3188 final_response = shared_response_manager.
GetResponse();
3189 postprocess_solution(&final_response);
3190 return final_response;
3194 if (params.stop_after_first_solution()) {
3196 [&shared_time_limit](
3197 const CpSolverResponse& response_of_presolved_problem) {
3198 shared_time_limit.Stop();
3202 #if defined(__PORTABLE_PLATFORM__)
3206 if (params.num_search_workers() > 1 || params.interleave_search()) {
3207 SolveCpModelParallel(new_cp_model_proto, &shared_response_manager,
3212 LOG(
INFO) << absl::StrFormat(
"*** starting to load the model at %.2fs",
3216 LoadCpModel(new_cp_model_proto, &shared_response_manager,
model);
3219 LOG(
INFO) << absl::StrFormat(
"*** starting sequential search at %.2fs",
3221 LOG(
INFO) <<
"Initial num_bool: "
3224 if (params.repair_hint()) {
3225 MinimizeL1DistanceWithHint(new_cp_model_proto, &shared_response_manager,
3228 QuickSolveWithHint(new_cp_model_proto, &shared_response_manager,
model);
3230 SolveLoadedCpModel(new_cp_model_proto, &shared_response_manager,
model);
3233 final_response = shared_response_manager.
GetResponse();
3234 postprocess_solution(&final_response);
3235 if (!final_response.solution().empty()) {
3237 model_proto, std::vector<int64>(final_response.solution().begin(),
3238 final_response.solution().end())));
3240 if (degraded_assumptions_support &&
3243 *final_response.mutable_sufficient_assumptions_for_infeasibility() =
3246 if (log_search && params.num_search_workers() > 1) {
3249 return final_response;
3258 const SatParameters& params) {
3264 #if !defined(__PORTABLE_PLATFORM__)
3266 const std::string& params) {
#define LOG_IF(severity, condition)
#define CHECK_NE(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
void 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].
int64 Min() const
Returns the min value of the domain.
int64 Max() const
Returns the max value of the domain.
bool IsEmpty() const
Returns true if this is the empty set.
void Register(const std::function< void()> &f)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
static std::unique_ptr< TimeLimit > Infinite()
Creates a time limit object that uses infinite time for wall time, deterministic time and instruction...
Literal(int signed_value)
Class that owns everything related to a particular optimization model.
CpSolverResponse GetResponse()
void SetStatsFromModel(Model *model)
void set_dump_prefix(const std::string &dump_prefix)
void UpdatePrimalIntegral()
void NewSolution(const CpSolverResponse &response, Model *model)
void DisplayImprovementStatistics()
void SetGapLimitsFromParameters(const SatParameters ¶meters)
int AddSolutionCallback(std::function< void(const CpSolverResponse &)> callback)
void SetUpdatePrimalIntegralOnEachChange(bool set)
void LoadDebugSolution(Model *)
void UpdateInnerObjectiveBounds(const std::string &update_info, IntegerValue lb, IntegerValue ub)
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
SharedTimeLimit * time_limit
GurobiMPCallbackContext * context
static const int64 kint64max
static const int64 kint64min
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)
bool ContainsKey(const Collection &collection, const Key &key)
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)
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){....
std::function< int64(const Model &)> LowerBound(IntegerVariable v)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::vector< IntegerVariable > AppendLinMaxRelaxation(IntegerVariable target, const std::vector< LinearExpression > &exprs, Model *model, LinearRelaxation *relaxation)
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)
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64 lower_bound)
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)
void MinimizeCoreWithPropagation(SatSolver *solver, std::vector< Literal > *core)
std::vector< int > UsedVariables(const ConstraintProto &ct)
double UnscaleObjectiveValue(const CpObjectiveProto &proto, double value)
bool RefIsPositive(int ref)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
void MaybeFullyEncodeMoreVariables(const CpModelProto &model_proto, Model *m)
std::function< IntegerVariable(Model *)> ConstantIntegerVariable(int64 value)
bool SolutionIsFeasible(const CpModelProto &model, const std::vector< int64 > &variable_values, const CpModelProto *mapping_proto, const std::vector< int > *postsolve_mapping)
CutGenerator CreateCumulativeCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, Model *model)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
SatSolver::Status SolveWithPresolve(std::unique_ptr< SatSolver > *solver, TimeLimit *time_limit, std::vector< bool > *solution, DratProofHandler *drat_proof_handler)
CutGenerator CreateNoOverlapCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
std::function< int64(const Model &)> Value(IntegerVariable v)
bool HasEnforcementLiteral(const ConstraintProto &ct)
int64 ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response)
LinearExpression PositiveVarExpr(const LinearExpression &expr)
CutGenerator CreateOverlappingCumulativeCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, Model *model)
void DeterministicLoop(const std::vector< std::unique_ptr< SubSolver >> &subsolvers, int num_threads, int batch_size)
bool AppendFullEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
CutGenerator CreateSquareCutGenerator(IntegerVariable y, IntegerVariable x, Model *model)
bool PresolveCpModel(PresolveContext *context, std::vector< int > *postsolve_mapping)
void PostsolveResponse(const int64 num_variables_in_original_model, const CpModelProto &mapping_proto, const std::vector< int > &postsolve_mapping, CpSolverResponse *response)
LinearExpression GetExprFromProto(const LinearExpressionProto &expr_proto, const CpModelMapping &mapping)
const IntegerVariable kNoIntegerVariable(-1)
std::function< BooleanOrIntegerLiteral()> FollowHint(const std::vector< BooleanOrIntegerVariable > &vars, const std::vector< IntegerValue > &values, Model *model)
double ScaleObjectiveValue(const CpObjectiveProto &proto, int64 value)
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64 lb, int64 ub)
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 NonDeterministicLoop(const std::vector< std::unique_ptr< SubSolver >> &subsolvers, int num_threads)
CutGenerator CreateLinMaxCutGenerator(const IntegerVariable target, const std::vector< LinearExpression > &exprs, const std::vector< IntegerVariable > &z_vars, Model *model)
CutGenerator CreateAllDifferentCutGenerator(const std::vector< IntegerVariable > &vars, Model *model)
CutGenerator CreateCVRPCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, const std::vector< int64 > &demands, int64 capacity, Model *model)
void DetectAndAddSymmetryToProto(const SatParameters ¶ms, CpModelProto *proto)
int ReindexArcs(IntContainer *tails, IntContainer *heads)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
void TryToLinearizeConstraint(const CpModelProto &model_proto, const ConstraintProto &ct, Model *model, int linearization_level, LinearRelaxation *relaxation)
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64 upper_bound)
std::function< int64(const Model &)> UpperBound(IntegerVariable v)
std::string CpModelStats(const CpModelProto &model_proto)
Returns a string with some statistics on the given CpModelProto.
void AppendPartialEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
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)
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
SatSolver::Status ContinuousProbing(const std::vector< BooleanVariable > &bool_vars, const std::vector< IntegerVariable > &int_vars, const std::function< void()> &feasible_solution_observer, Model *model)
CutGenerator CreateKnapsackCoverCutGenerator(const std::vector< LinearConstraint > &base_constraints, const std::vector< IntegerVariable > &vars, Model *model)
std::vector< SatParameters > GetDiverseSetOfParameters(const SatParameters &base_params, const CpModelProto &cp_model, const int num_workers)
CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, IntegerVariable x, IntegerVariable y, Model *model)
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
std::string ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case)
CutGenerator CreateCliqueCutGenerator(const std::vector< IntegerVariable > &base_variables, Model *model)
CutGenerator CreateStronglyConnectedGraphCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, Model *model)
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)
CpSolverResponse SolveWithParameters(const CpModelProto &model_proto, const SatParameters ¶ms)
Solves the given CpModelProto with the given parameters.
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)
void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
std::mt19937 random_engine_t
std::string ProtobufDebugString(const P &message)
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 VLOG_IS_ON(verboselevel)