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"
88 ABSL_FLAG(std::string, cp_model_dump_prefix,
".\\",
89 "Prefix filename for all dumped files");
91 ABSL_FLAG(std::string, cp_model_dump_prefix,
"/tmp/",
92 "Prefix filename for all dumped files");
95 "DEBUG ONLY. When set to true, SolveCpModel() will dump its model "
96 "protos (original model, presolved model, mapping model) in text "
97 "format to 'FLAGS_cp_model_dump_prefix'{model|presolved_model|"
98 "mapping_model}.pbtxt.");
101 "DEBUG ONLY. When set to true, solve will dump all "
102 "lns models proto in text format to "
103 "'FLAGS_cp_model_dump_prefix'lns_xxx.pbtxt.");
106 "DEBUG ONLY. If true, the final response of each solve will be "
107 "dumped to 'FLAGS_cp_model_dump_prefix'response.pbtxt");
110 "This is interpreted as a text SatParameters proto. The "
111 "specified fields will override the normal ones for all solves.");
114 "If non-empty, a proof in DRAT format will be written to this file. "
115 "This will only be used for pure-SAT problems.");
118 "If true, a proof in DRAT format will be stored in memory and "
119 "checked if the problem is UNSAT. This will only be used for "
120 "pure-SAT problems.");
123 std::numeric_limits<double>::infinity(),
124 "Maximum time in seconds to check the DRAT proof. This will only "
125 "be used is the drat_check flag is enabled.");
127 ABSL_FLAG(
bool, cp_model_check_intermediate_solutions,
false,
128 "When true, all intermediate solutions found by the solver will be "
129 "checked. This can be expensive, therefore it is off by default.");
137 std::string Summarize(
const std::string&
input) {
140 return absl::StrCat(
input.substr(0, half),
" ... ",
151 std::map<std::string, int> num_constraints_by_name;
152 std::map<std::string, int> num_reif_constraints_by_name;
153 std::map<std::string, int> name_to_num_literals;
154 std::map<std::string, int> name_to_num_terms;
155 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
160 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) {
161 if (
ct.linear().vars_size() == 1)
name +=
"1";
162 if (
ct.linear().vars_size() == 2)
name +=
"2";
163 if (
ct.linear().vars_size() == 3)
name +=
"3";
164 if (
ct.linear().vars_size() > 3)
name +=
"N";
167 num_constraints_by_name[
name]++;
168 if (!
ct.enforcement_literal().empty()) {
169 num_reif_constraints_by_name[
name]++;
174 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) {
175 name_to_num_literals[
name] +=
ct.bool_or().literals().size();
176 }
else if (
ct.constraint_case() ==
177 ConstraintProto::ConstraintCase::kBoolAnd) {
178 name_to_num_literals[
name] +=
ct.bool_and().literals().size();
179 }
else if (
ct.constraint_case() ==
180 ConstraintProto::ConstraintCase::kAtMostOne) {
181 name_to_num_literals[
name] +=
ct.at_most_one().literals().size();
182 }
else if (
ct.constraint_case() ==
183 ConstraintProto::ConstraintCase::kExactlyOne) {
184 name_to_num_literals[
name] +=
ct.exactly_one().literals().size();
187 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear &&
188 ct.linear().vars_size() > 3) {
189 name_to_num_terms[
name] +=
ct.linear().vars_size();
193 int num_constants = 0;
194 std::set<int64> constant_values;
195 std::map<Domain, int> num_vars_per_domains;
197 if (
var.domain_size() == 2 &&
var.domain(0) ==
var.domain(1)) {
199 constant_values.insert(
var.domain(0));
207 absl::StrAppend(&result,
"Optimization model '",
model_proto.name(),
210 absl::StrAppend(&result,
"Satisfaction model '",
model_proto.name(),
214 for (
const DecisionStrategyProto& strategy :
model_proto.search_strategy()) {
216 &result,
"Search strategy: on ", strategy.variables_size(),
218 ProtoEnumToString<DecisionStrategyProto::VariableSelectionStrategy>(
219 strategy.variable_selection_strategy()),
221 ProtoEnumToString<DecisionStrategyProto::DomainReductionStrategy>(
222 strategy.domain_reduction_strategy()),
226 const std::string objective_string =
228 ? absl::StrCat(
" (",
model_proto.objective().vars_size(),
231 absl::StrAppend(&result,
"#Variables: ",
model_proto.variables_size(),
232 objective_string,
"\n");
233 if (num_vars_per_domains.size() < 100) {
234 for (
const auto& entry : num_vars_per_domains) {
235 const std::string temp = absl::StrCat(
" - ", entry.second,
" in ",
236 entry.first.ToString(),
"\n");
237 absl::StrAppend(&result, Summarize(temp));
240 int64 max_complexity = 0;
243 for (
const auto& entry : num_vars_per_domains) {
246 max_complexity =
std::max(max_complexity,
247 static_cast<int64>(entry.first.NumIntervals()));
249 absl::StrAppend(&result,
" - ", num_vars_per_domains.size(),
250 " different domains in [",
min,
",",
max,
251 "] with a largest complexity of ", max_complexity,
".\n");
254 if (num_constants > 0) {
255 const std::string temp =
256 absl::StrCat(
" - ", num_constants,
" constants in {",
257 absl::StrJoin(constant_values,
","),
"} \n");
258 absl::StrAppend(&result, Summarize(temp));
261 std::vector<std::string> constraints;
262 constraints.reserve(num_constraints_by_name.size());
263 for (
const auto& entry : num_constraints_by_name) {
264 const std::string&
name = entry.first;
265 constraints.push_back(absl::StrCat(
"#",
name,
": ", entry.second));
267 absl::StrAppend(&constraints.back(),
268 " (#enforced: ", num_reif_constraints_by_name[
name],
")");
271 absl::StrAppend(&constraints.back(),
272 " (#literals: ", name_to_num_literals[
name],
")");
275 absl::StrAppend(&constraints.back(),
276 " (#terms: ", name_to_num_terms[
name],
")");
279 std::sort(constraints.begin(), constraints.end());
280 absl::StrAppend(&result, absl::StrJoin(constraints,
"\n"));
286 bool has_objective) {
288 absl::StrAppend(&result,
"CpSolverResponse:");
289 absl::StrAppend(&result,
"\nstatus: ",
290 ProtoEnumToString<CpSolverStatus>(
response.status()));
293 absl::StrAppendFormat(&result,
"\nobjective: %.16g",
295 absl::StrAppendFormat(&result,
"\nbest_bound: %.16g",
298 absl::StrAppend(&result,
"\nobjective: NA");
299 absl::StrAppend(&result,
"\nbest_bound: NA");
302 absl::StrAppend(&result,
"\nbooleans: ",
response.num_booleans());
303 absl::StrAppend(&result,
"\nconflicts: ",
response.num_conflicts());
304 absl::StrAppend(&result,
"\nbranches: ",
response.num_branches());
308 absl::StrAppend(&result,
309 "\npropagations: ",
response.num_binary_propagations());
311 &result,
"\ninteger_propagations: ",
response.num_integer_propagations());
313 absl::StrAppend(&result,
"\nrestarts: ",
response.num_restarts());
314 absl::StrAppend(&result,
"\nlp_iterations: ",
response.num_lp_iterations());
315 absl::StrAppend(&result,
"\nwalltime: ",
response.wall_time());
316 absl::StrAppend(&result,
"\nusertime: ",
response.user_time());
317 absl::StrAppend(&result,
318 "\ndeterministic_time: ",
response.deterministic_time());
319 absl::StrAppend(&result,
"\nprimal_integral: ",
response.primal_integral());
320 absl::StrAppend(&result,
"\n");
326 void FillSolutionInResponse(
const CpModelProto&
model_proto,
const Model&
model,
329 response->clear_solution_lower_bounds();
330 response->clear_solution_upper_bounds();
332 auto* mapping =
model.Get<CpModelMapping>();
334 auto* integer_trail =
model.Get<IntegerTrail>();
336 std::vector<int64> solution;
337 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
338 if (mapping->IsInteger(i)) {
339 const IntegerVariable
var = mapping->Integer(i);
340 if (integer_trail->IsCurrentlyIgnored(
var)) {
353 DCHECK(mapping->IsBoolean(i));
355 if (trail->Assignment().LiteralIsAssigned(
literal)) {
364 if (!solution.empty()) {
366 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
374 const auto& assignment = trail->Assignment();
375 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
376 if (mapping->IsBoolean(i)) {
377 if (assignment.VariableIsAssigned(mapping->Literal(i).Variable())) {
382 response->add_solution_lower_bounds(0);
383 response->add_solution_upper_bounds(1);
386 response->add_solution_lower_bounds(
388 response->add_solution_upper_bounds(
397 IntegerVariable GetOrCreateVariableWithTightBound(
398 const std::vector<std::pair<IntegerVariable, int64>>& terms, Model*
model) {
400 if (terms.size() == 1 && terms.front().second == 1) {
401 return terms.front().first;
403 if (terms.size() == 1 && terms.front().second == -1) {
409 for (
const std::pair<IntegerVariable, int64> var_coeff : terms) {
412 const int64 coeff = var_coeff.second;
413 const int64 prod1 = min_domain * coeff;
414 const int64 prod2 = max_domain * coeff;
421 IntegerVariable GetOrCreateVariableGreaterOrEqualToSumOf(
422 const std::vector<std::pair<IntegerVariable, int64>>& terms, Model*
model) {
424 if (terms.size() == 1 && terms.front().second == 1) {
425 return terms.front().first;
427 if (terms.size() == 1 && terms.front().second == -1) {
432 const IntegerVariable new_var =
433 GetOrCreateVariableWithTightBound(terms,
model);
434 std::vector<IntegerVariable> vars;
435 std::vector<int64> coeffs;
436 for (
const auto& term : terms) {
437 vars.push_back(term.first);
438 coeffs.push_back(term.second);
440 vars.push_back(new_var);
441 coeffs.push_back(-1);
446 void TryToAddCutGenerators(
const CpModelProto&
model_proto,
447 const ConstraintProto&
ct, Model* m,
448 LinearRelaxation* relaxation) {
449 const int linearization_level =
450 m->GetOrCreate<SatParameters>()->linearization_level();
451 auto* mapping = m->GetOrCreate<CpModelMapping>();
452 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCircuit &&
453 linearization_level > 1) {
454 std::vector<int> tails(
ct.circuit().tails().begin(),
455 ct.circuit().tails().end());
456 std::vector<int> heads(
ct.circuit().heads().begin(),
457 ct.circuit().heads().end());
458 std::vector<Literal> literals = mapping->Literals(
ct.circuit().literals());
461 relaxation->cut_generators.push_back(
465 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kRoutes &&
466 linearization_level > 1) {
467 std::vector<int> tails(
ct.routes().tails().begin(),
468 ct.routes().tails().end());
469 std::vector<int> heads(
ct.routes().heads().begin(),
470 ct.routes().heads().end());
471 std::vector<Literal> literals = mapping->Literals(
ct.routes().literals());
474 for (
int i = 0; i <
ct.routes().tails_size(); ++i) {
475 num_nodes =
std::max(num_nodes, 1 +
ct.routes().tails(i));
476 num_nodes =
std::max(num_nodes, 1 +
ct.routes().heads(i));
478 if (
ct.routes().demands().empty() ||
ct.routes().capacity() == 0) {
479 relaxation->cut_generators.push_back(
483 const std::vector<int64> demands(
ct.routes().demands().begin(),
484 ct.routes().demands().end());
485 relaxation->cut_generators.push_back(
487 ct.routes().capacity(), m));
490 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kIntProd) {
492 if (
ct.int_prod().vars_size() != 2)
return;
496 IntegerVariable z = mapping->Integer(
ct.int_prod().target());
497 IntegerVariable x = mapping->Integer(
ct.int_prod().vars(0));
498 IntegerVariable y = mapping->Integer(
ct.int_prod().vars(1));
500 IntegerTrail*
const integer_trail = m->GetOrCreate<IntegerTrail>();
501 IntegerValue x_lb = integer_trail->LowerBound(x);
502 IntegerValue x_ub = integer_trail->UpperBound(x);
503 IntegerValue y_lb = integer_trail->LowerBound(y);
504 IntegerValue y_ub = integer_trail->UpperBound(y);
508 if (x_lb < 0 && x_ub > 0)
return;
518 if (x_lb < 0 && x_ub > 0)
return;
519 if (y_lb < 0 && y_ub > 0)
return;
532 relaxation->cut_generators.push_back(
536 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kAllDiff) {
537 if (linearization_level < 2)
return;
539 const int num_vars =
ct.all_diff().vars_size();
540 if (num_vars <= m->GetOrCreate<SatParameters>()->max_all_diff_cut_size()) {
541 std::vector<IntegerVariable> vars =
542 mapping->Integers(
ct.all_diff().vars());
543 relaxation->cut_generators.push_back(
548 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCumulative) {
549 if (linearization_level < 2)
return;
552 std::vector<IntegerVariable> demands =
553 mapping->Integers(
ct.cumulative().demands());
554 std::vector<IntervalVariable> intervals =
555 mapping->Intervals(
ct.cumulative().intervals());
557 mapping->Integer(
ct.cumulative().capacity());
558 relaxation->cut_generators.push_back(
561 relaxation->cut_generators.push_back(
565 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kNoOverlap) {
566 if (linearization_level < 2)
return;
568 std::vector<IntervalVariable> intervals =
569 mapping->Intervals(
ct.no_overlap().intervals());
570 relaxation->cut_generators.push_back(
572 relaxation->cut_generators.push_back(
576 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinMax) {
577 if (!m->GetOrCreate<SatParameters>()->add_lin_max_cuts())
return;
581 if (
ct.lin_max().target().vars_size() != 1)
return;
582 if (
ct.lin_max().target().coeffs(0) != 1)
return;
584 const IntegerVariable target =
585 mapping->Integer(
ct.lin_max().target().vars(0));
586 std::vector<LinearExpression> exprs;
587 exprs.reserve(
ct.lin_max().exprs_size());
588 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
597 const std::vector<IntegerVariable> z_vars =
600 if (linearization_level >= 2) {
601 relaxation->cut_generators.push_back(
609 LinearRelaxation ComputeLinearRelaxation(
const CpModelProto&
model_proto,
610 int linearization_level, Model* m) {
611 LinearRelaxation relaxation;
614 absl::flat_hash_set<int> used_integer_variable;
616 auto* mapping = m->GetOrCreate<CpModelMapping>();
617 auto* encoder = m->GetOrCreate<IntegerEncoder>();
618 auto* trail = m->GetOrCreate<Trail>();
621 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCircuit) {
622 for (
const int ref :
ct.circuit().literals()) {
623 const Literal l = mapping->Literal(ref);
624 if (!encoder->LiteralOrNegationHasView(l)) {
637 for (
const int literal_ref : refs.literals) {
639 if (trail->Assignment().LiteralIsAssigned(
literal)) {
642 }
else if (!encoder->LiteralOrNegationHasView(
literal)) {
655 int num_full_encoding_relaxations = 0;
656 int num_partial_encoding_relaxations = 0;
657 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
658 if (mapping->IsBoolean(i))
continue;
660 const IntegerVariable
var = mapping->Integer(i);
671 if (encoder->VariableIsFullyEncoded(
var)) {
673 ++num_full_encoding_relaxations;
684 const int old = relaxation.linear_constraints.size();
686 if (relaxation.linear_constraints.size() > old) {
687 ++num_partial_encoding_relaxations;
693 m->GetOrCreate<BinaryImplicationGraph>()->TransformIntoMaxCliques(
694 &relaxation.at_most_ones);
695 for (
const std::vector<Literal>& at_most_one : relaxation.at_most_ones) {
696 if (at_most_one.empty())
continue;
699 for (
const Literal
literal : at_most_one) {
702 const bool unused ABSL_ATTRIBUTE_UNUSED =
703 lc.AddLiteralTerm(
literal, IntegerValue(1));
705 relaxation.linear_constraints.push_back(lc.Build());
710 relaxation.at_most_ones.clear();
715 for (
int i = 0; i < relaxation.linear_constraints.size(); ++i) {
716 if (relaxation.linear_constraints[i].vars.size() <= 1)
continue;
717 std::swap(relaxation.linear_constraints[new_size++],
718 relaxation.linear_constraints[i]);
720 relaxation.linear_constraints.resize(new_size);
723 VLOG(3) <<
"num_full_encoding_relaxations: " << num_full_encoding_relaxations;
724 VLOG(3) <<
"num_partial_encoding_relaxations: "
725 << num_partial_encoding_relaxations;
726 VLOG(3) << relaxation.linear_constraints.size()
727 <<
" constraints in the LP relaxation.";
728 VLOG(3) << relaxation.cut_generators.size() <<
" cuts generators.";
733 IntegerVariable AddLPConstraints(
const CpModelProto&
model_proto,
734 int linearization_level, Model* m) {
735 const LinearRelaxation relaxation =
736 ComputeLinearRelaxation(
model_proto, linearization_level, m);
744 const int num_lp_constraints = relaxation.linear_constraints.size();
745 const int num_lp_cut_generators = relaxation.cut_generators.size();
746 const int num_integer_variables =
747 m->GetOrCreate<IntegerTrail>()->NumIntegerVariables().value();
750 num_integer_variables);
751 auto get_constraint_index = [](
int ct_index) {
return ct_index; };
752 auto get_cut_generator_index = [num_lp_constraints](
int cut_index) {
753 return num_lp_constraints + cut_index;
755 auto get_var_index = [num_lp_constraints,
756 num_lp_cut_generators](IntegerVariable
var) {
757 return num_lp_constraints + num_lp_cut_generators +
var.value();
759 for (
int i = 0; i < num_lp_constraints; i++) {
760 for (
const IntegerVariable
var : relaxation.linear_constraints[i].vars) {
761 components.
AddEdge(get_constraint_index(i), get_var_index(
var));
764 for (
int i = 0; i < num_lp_cut_generators; ++i) {
765 for (
const IntegerVariable
var : relaxation.cut_generators[i].vars) {
766 components.
AddEdge(get_cut_generator_index(i), get_var_index(
var));
774 for (
const std::vector<Literal>& at_most_one : relaxation.at_most_ones) {
776 for (
const Literal
literal : at_most_one) {
779 const bool unused ABSL_ATTRIBUTE_UNUSED =
780 builder.AddLiteralTerm(
literal, IntegerValue(1));
782 LinearConstraint lc = builder.Build();
783 for (
int i = 1; i < lc.vars.size(); ++i) {
784 components.
AddEdge(get_var_index(lc.vars[0]), get_var_index(lc.vars[i]));
789 std::vector<int> component_sizes(num_components, 0);
790 const std::vector<int> index_to_component = components.
GetComponentIds();
791 for (
int i = 0; i < num_lp_constraints; i++) {
792 ++component_sizes[index_to_component[get_constraint_index(i)]];
794 for (
int i = 0; i < num_lp_cut_generators; i++) {
795 ++component_sizes[index_to_component[get_cut_generator_index(i)]];
803 auto* mapping = m->GetOrCreate<CpModelMapping>();
804 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
805 const IntegerVariable
var =
807 ++component_sizes[index_to_component[get_var_index(
var)]];
811 std::vector<LinearProgrammingConstraint*> lp_constraints(num_components,
813 std::vector<std::vector<LinearConstraint>> component_to_constraints(
815 for (
int i = 0; i < num_lp_constraints; i++) {
816 const int c = index_to_component[get_constraint_index(i)];
817 if (component_sizes[c] <= 1)
continue;
818 component_to_constraints[c].push_back(relaxation.linear_constraints[i]);
819 if (lp_constraints[c] ==
nullptr) {
820 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
823 lp_constraints[c]->AddLinearConstraint(relaxation.linear_constraints[i]);
827 for (
int i = 0; i < num_lp_cut_generators; i++) {
828 const int c = index_to_component[get_cut_generator_index(i)];
829 if (lp_constraints[c] ==
nullptr) {
830 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
832 lp_constraints[c]->AddCutGenerator(std::move(relaxation.cut_generators[i]));
836 const SatParameters& params = *(m->GetOrCreate<SatParameters>());
837 if (params.add_clique_cuts() && params.linearization_level() > 1) {
838 for (LinearProgrammingConstraint* lp : lp_constraints) {
839 if (lp ==
nullptr)
continue;
844 if (params.add_knapsack_cuts() && params.linearization_level() > 1) {
845 for (
int c = 0; c < num_components; ++c) {
846 if (component_to_constraints[c].empty())
continue;
848 component_to_constraints[c], lp_constraints[c]->integer_variables(),
854 std::vector<std::vector<std::pair<IntegerVariable, int64>>>
855 component_to_cp_terms(num_components);
856 std::vector<std::pair<IntegerVariable, int64>> top_level_cp_terms;
857 int num_components_containing_objective = 0;
861 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
862 const IntegerVariable
var =
865 const int c = index_to_component[get_var_index(
var)];
866 if (lp_constraints[c] !=
nullptr) {
867 lp_constraints[c]->SetObjectiveCoefficient(
var, IntegerValue(coeff));
868 component_to_cp_terms[c].push_back(std::make_pair(
var, coeff));
871 top_level_cp_terms.push_back(std::make_pair(
var, coeff));
875 for (
int c = 0; c < num_components; ++c) {
876 if (component_to_cp_terms[c].empty())
continue;
877 const IntegerVariable sub_obj_var =
878 GetOrCreateVariableGreaterOrEqualToSumOf(component_to_cp_terms[c], m);
879 top_level_cp_terms.push_back(std::make_pair(sub_obj_var, 1));
880 lp_constraints[c]->SetMainObjectiveVariable(sub_obj_var);
881 num_components_containing_objective++;
885 const IntegerVariable main_objective_var =
887 ? GetOrCreateVariableGreaterOrEqualToSumOf(top_level_cp_terms, m)
892 for (LinearProgrammingConstraint* lp_constraint : lp_constraints) {
893 if (lp_constraint ==
nullptr)
continue;
894 lp_constraint->RegisterWith(m);
895 VLOG(3) <<
"LP constraint: " << lp_constraint->DimensionString() <<
".";
898 VLOG(3) << top_level_cp_terms.size()
899 <<
" terms in the main objective linear equation ("
900 << num_components_containing_objective <<
" from LP constraints).";
901 return main_objective_var;
913 const std::function<
void(
const CpSolverResponse&
response)>& observer) {
919 #if !defined(__PORTABLE_PLATFORM__)
922 const std::string& params) {
924 if (!params.empty()) {
925 CHECK(google::protobuf::TextFormat::ParseFromString(params, &
parameters))
952 void RegisterVariableBoundsLevelZeroExport(
953 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
955 CHECK(shared_bounds_manager !=
nullptr);
956 int saved_trail_index = 0;
957 const auto broadcast_level_zero_bounds =
959 const std::vector<IntegerVariable>& modified_vars)
mutable {
960 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
962 std::vector<int> model_variables;
963 std::vector<int64> new_lower_bounds;
964 std::vector<int64> new_upper_bounds;
965 absl::flat_hash_set<int> visited_variables;
968 auto* integer_trail =
model->Get<IntegerTrail>();
969 for (
const IntegerVariable&
var : modified_vars) {
971 const int model_var =
972 mapping->GetProtoVariableFromIntegerVariable(positive_var);
973 if (model_var == -1 || visited_variables.contains(model_var)) {
980 visited_variables.insert(model_var);
982 integer_trail->LevelZeroLowerBound(positive_var).value();
984 integer_trail->LevelZeroUpperBound(positive_var).value();
987 model_variables.push_back(model_var);
988 new_lower_bounds.push_back(new_lb);
989 new_upper_bounds.push_back(new_ub);
993 auto* trail =
model->Get<Trail>();
994 for (; saved_trail_index < trail->Index(); ++saved_trail_index) {
995 const Literal fixed_literal = (*trail)[saved_trail_index];
996 const int model_var = mapping->GetProtoVariableFromBooleanVariable(
997 fixed_literal.Variable());
998 if (model_var == -1 || visited_variables.contains(model_var)) {
1005 visited_variables.insert(model_var);
1006 model_variables.push_back(model_var);
1007 if (fixed_literal.IsPositive()) {
1008 new_lower_bounds.push_back(1);
1009 new_upper_bounds.push_back(1);
1011 new_lower_bounds.push_back(0);
1012 new_upper_bounds.push_back(0);
1016 if (!model_variables.empty()) {
1017 shared_bounds_manager->ReportPotentialNewBounds(
1023 if (!
model->Get<SatParameters>()->interleave_search()) {
1024 shared_bounds_manager->Synchronize();
1028 model->GetOrCreate<GenericLiteralWatcher>()
1029 ->RegisterLevelZeroModifiedVariablesCallback(broadcast_level_zero_bounds);
1035 void RegisterVariableBoundsLevelZeroImport(
1036 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
1038 CHECK(shared_bounds_manager !=
nullptr);
1039 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1040 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
1041 const int id = shared_bounds_manager->RegisterNewId();
1043 const auto& import_level_zero_bounds = [&
model_proto, shared_bounds_manager,
1044 model, integer_trail, id, mapping]() {
1045 std::vector<int> model_variables;
1046 std::vector<int64> new_lower_bounds;
1047 std::vector<int64> new_upper_bounds;
1048 shared_bounds_manager->GetChangedBounds(
1049 id, &model_variables, &new_lower_bounds, &new_upper_bounds);
1050 bool new_bounds_have_been_imported =
false;
1051 for (
int i = 0; i < model_variables.size(); ++i) {
1052 const int model_var = model_variables[i];
1055 if (!mapping->IsInteger(model_var))
continue;
1056 const IntegerVariable
var = mapping->Integer(model_var);
1057 const IntegerValue new_lb(new_lower_bounds[i]);
1058 const IntegerValue new_ub(new_upper_bounds[i]);
1059 const IntegerValue old_lb = integer_trail->LowerBound(
var);
1060 const IntegerValue old_ub = integer_trail->UpperBound(
var);
1061 const bool changed_lb = new_lb > old_lb;
1062 const bool changed_ub = new_ub < old_ub;
1063 if (!changed_lb && !changed_ub)
continue;
1065 new_bounds_have_been_imported =
true;
1067 const IntegerVariableProto& var_proto =
1069 const std::string& var_name =
1070 var_proto.name().empty()
1071 ? absl::StrCat(
"anonymous_var(", model_var,
")")
1073 LOG(
INFO) <<
" '" <<
model->Name() <<
"' imports new bounds for "
1074 << var_name <<
": from [" << old_lb <<
", " << old_ub
1075 <<
"] to [" << new_lb <<
", " << new_ub <<
"]";
1089 if (new_bounds_have_been_imported &&
1090 !
model->GetOrCreate<SatSolver>()->FinishPropagation()) {
1095 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
1096 import_level_zero_bounds);
1101 void RegisterObjectiveBestBoundExport(
1102 IntegerVariable objective_var,
1103 SharedResponseManager* shared_response_manager, Model*
model) {
1104 auto* integer_trail =
model->Get<IntegerTrail>();
1105 const auto broadcast_objective_lower_bound =
1106 [objective_var, integer_trail, shared_response_manager,
1107 model](
const std::vector<IntegerVariable>& unused) {
1108 shared_response_manager->UpdateInnerObjectiveBounds(
1109 model->Name(), integer_trail->LevelZeroLowerBound(objective_var),
1110 integer_trail->LevelZeroUpperBound(objective_var));
1112 if (!
model->Get<SatParameters>()->interleave_search()) {
1113 shared_response_manager->Synchronize();
1116 model->GetOrCreate<GenericLiteralWatcher>()
1117 ->RegisterLevelZeroModifiedVariablesCallback(
1118 broadcast_objective_lower_bound);
1124 void RegisterObjectiveBoundsImport(
1125 SharedResponseManager* shared_response_manager, Model*
model) {
1126 auto* solver =
model->GetOrCreate<SatSolver>();
1127 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1128 auto* objective =
model->GetOrCreate<ObjectiveDefinition>();
1130 const auto import_objective_bounds = [
name, solver, integer_trail, objective,
1131 shared_response_manager]() {
1132 if (solver->AssumptionLevel() != 0)
return true;
1133 bool propagate =
false;
1135 const IntegerValue external_lb =
1136 shared_response_manager->SynchronizedInnerObjectiveLowerBound();
1137 const IntegerValue current_lb =
1138 integer_trail->LowerBound(objective->objective_var);
1139 if (external_lb > current_lb) {
1141 objective->objective_var, external_lb),
1148 const IntegerValue external_ub =
1149 shared_response_manager->SynchronizedInnerObjectiveUpperBound();
1150 const IntegerValue current_ub =
1151 integer_trail->UpperBound(objective->objective_var);
1152 if (external_ub < current_ub) {
1154 objective->objective_var, external_ub),
1161 if (!propagate)
return true;
1163 VLOG(2) <<
"'" <<
name <<
"' imports objective bounds: external ["
1164 << objective->ScaleIntegerObjective(external_lb) <<
", "
1165 << objective->ScaleIntegerObjective(external_ub) <<
"], current ["
1166 << objective->ScaleIntegerObjective(current_lb) <<
", "
1167 << objective->ScaleIntegerObjective(current_ub) <<
"]";
1169 return solver->FinishPropagation();
1172 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
1173 import_objective_bounds);
1176 void LoadBaseModel(
const CpModelProto&
model_proto,
1177 SharedResponseManager* shared_response_manager,
1179 CHECK(shared_response_manager !=
nullptr);
1180 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1183 const auto unsat = [shared_response_manager, sat_solver,
model] {
1184 sat_solver->NotifyThatModelIsUnsat();
1185 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1186 absl::StrCat(
model->Name(),
" [loading]"));
1190 model->GetOrCreate<IntegerEncoder>()->DisableImplicationBetweenLiteral();
1192 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1193 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1194 const bool view_all_booleans_as_integers =
1196 (
parameters.search_branching() == SatParameters::FIXED_SEARCH &&
1198 mapping->CreateVariables(
model_proto, view_all_booleans_as_integers,
model);
1205 if (sat_solver->IsModelUnsat())
return unsat();
1211 std::set<std::string> unsupported_types;
1212 int num_ignored_constraints = 0;
1213 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1214 if (mapping->ConstraintIsAlreadyLoaded(&
ct)) {
1215 ++num_ignored_constraints;
1230 if (sat_solver->FinishPropagation()) {
1231 Trail* trail =
model->GetOrCreate<Trail>();
1232 const int old_num_fixed = trail->Index();
1233 if (trail->Index() > old_num_fixed) {
1234 VLOG(3) <<
"Constraint fixed " << trail->Index() - old_num_fixed
1239 if (sat_solver->IsModelUnsat()) {
1240 VLOG(2) <<
"UNSAT during extraction (after adding '"
1246 if (num_ignored_constraints > 0) {
1247 VLOG(3) << num_ignored_constraints <<
" constraints were skipped.";
1249 if (!unsupported_types.empty()) {
1250 VLOG(1) <<
"There is unsupported constraints types in this model: ";
1251 for (
const std::string& type : unsupported_types) {
1252 VLOG(1) <<
" - " << type;
1257 model->GetOrCreate<IntegerEncoder>()
1258 ->AddAllImplicationsBetweenAssociatedLiterals();
1259 if (!sat_solver->FinishPropagation())
return unsat();
1262 void LoadFeasibilityPump(
const CpModelProto&
model_proto,
1263 SharedResponseManager* shared_response_manager,
1265 CHECK(shared_response_manager !=
nullptr);
1269 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1270 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1271 if (
parameters.linearization_level() == 0)
return;
1274 const LinearRelaxation relaxation = ComputeLinearRelaxation(
1276 const int num_lp_constraints = relaxation.linear_constraints.size();
1277 if (num_lp_constraints == 0)
return;
1278 auto* feasibility_pump =
model->GetOrCreate<FeasibilityPump>();
1279 for (
int i = 0; i < num_lp_constraints; i++) {
1280 feasibility_pump->AddLinearConstraint(relaxation.linear_constraints[i]);
1284 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
1285 const IntegerVariable
var =
1286 mapping->Integer(
model_proto.objective().vars(i));
1288 feasibility_pump->SetObjectiveCoefficient(
var, IntegerValue(coeff));
1298 SharedResponseManager* shared_response_manager, Model*
model) {
1299 CHECK(shared_response_manager !=
nullptr);
1300 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1305 const auto unsat = [shared_response_manager, sat_solver,
model] {
1306 sat_solver->NotifyThatModelIsUnsat();
1307 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1308 absl::StrCat(
model->Name(),
" [loading]"));
1311 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1312 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1318 if (
model->Mutable<PrecedencesPropagator>() !=
nullptr &&
1319 parameters.auto_detect_greater_than_at_least_one_of()) {
1320 model->Mutable<PrecedencesPropagator>()
1321 ->AddGreaterThanAtLeastOneOfConstraints(
model);
1322 if (!sat_solver->FinishPropagation())
return unsat();
1328 if (
parameters.cp_model_probing_level() > 1) {
1329 Prober* prober =
model->GetOrCreate<Prober>();
1330 prober->ProbeBooleanVariables(1.0);
1331 if (
model->GetOrCreate<SatSolver>()->IsModelUnsat()) {
1334 if (!
model->GetOrCreate<BinaryImplicationGraph>()
1335 ->ComputeTransitiveReduction()) {
1348 const CpObjectiveProto& obj =
model_proto.objective();
1349 std::vector<std::pair<IntegerVariable, int64>> terms;
1350 terms.reserve(obj.vars_size());
1351 for (
int i = 0; i < obj.vars_size(); ++i) {
1353 std::make_pair(mapping->Integer(obj.vars(i)), obj.coeffs(i)));
1356 objective_var = GetOrCreateVariableWithTightBound(terms,
model);
1358 objective_var = GetOrCreateVariableGreaterOrEqualToSumOf(terms,
model);
1365 const CpObjectiveProto& objective_proto =
model_proto.objective();
1366 auto* objective_definition =
model->GetOrCreate<ObjectiveDefinition>();
1368 objective_definition->scaling_factor = objective_proto.scaling_factor();
1369 if (objective_definition->scaling_factor == 0.0) {
1370 objective_definition->scaling_factor = 1.0;
1372 objective_definition->offset = objective_proto.offset();
1373 objective_definition->objective_var = objective_var;
1375 const int size = objective_proto.vars_size();
1376 objective_definition->vars.resize(size);
1377 objective_definition->coeffs.resize(size);
1378 for (
int i = 0; i < objective_proto.vars_size(); ++i) {
1381 objective_definition->vars[i] = mapping->Integer(objective_proto.vars(i));
1382 objective_definition->coeffs[i] = IntegerValue(objective_proto.coeffs(i));
1385 const int ref = objective_proto.vars(i);
1386 if (mapping->IsInteger(ref)) {
1387 const IntegerVariable
var = mapping->Integer(objective_proto.vars(i));
1388 objective_definition->objective_impacting_variables.insert(
1394 model->TakeOwnership(
1395 new LevelZeroEquality(objective_var, objective_definition->vars,
1396 objective_definition->coeffs,
model));
1402 const Domain automatic_domain =
1403 model->GetOrCreate<IntegerTrail>()->InitialVariableDomain(
1406 <<
" scaling_factor:" <<
model_proto.objective().scaling_factor();
1407 VLOG(3) <<
"Automatic internal objective domain: " << automatic_domain;
1408 VLOG(3) <<
"User specified internal objective domain: " << user_domain;
1410 const bool ok =
model->GetOrCreate<IntegerTrail>()->UpdateInitialDomain(
1411 objective_var, user_domain);
1413 VLOG(2) <<
"UNSAT due to the objective domain.";
1424 if (!automatic_domain.IsIncludedIn(user_domain)) {
1425 std::vector<IntegerVariable> vars;
1426 std::vector<int64> coeffs;
1427 const CpObjectiveProto& obj =
model_proto.objective();
1428 for (
int i = 0; i < obj.vars_size(); ++i) {
1429 vars.push_back(mapping->Integer(obj.vars(i)));
1430 coeffs.push_back(obj.coeffs(i));
1432 vars.push_back(objective_var);
1433 coeffs.push_back(-1);
1440 if (!sat_solver->FinishPropagation())
return unsat();
1444 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1445 shared_response_manager->UpdateInnerObjectiveBounds(
1446 "init", integer_trail->LowerBound(objective_var),
1447 integer_trail->UpperBound(objective_var));
1450 RegisterObjectiveBestBoundExport(objective_var, shared_response_manager,
1456 if (
model->GetOrCreate<SatParameters>()->share_objective_bounds()) {
1457 RegisterObjectiveBoundsImport(shared_response_manager,
model);
1463 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1464 auto* lp_dispatcher =
model->GetOrCreate<LinearProgrammingDispatcher>();
1465 auto* lp_vars =
model->GetOrCreate<LPVariables>();
1466 IntegerVariable size = integer_trail->NumIntegerVariables();
1467 for (IntegerVariable positive_var(0); positive_var < size;
1468 positive_var += 2) {
1470 lp_var.positive_var = positive_var;
1472 mapping->GetProtoVariableFromIntegerVariable(positive_var);
1475 if (lp_var.model_var >= 0) {
1476 lp_vars->vars.push_back(lp_var);
1477 lp_vars->model_vars_size =
1478 std::max(lp_vars->model_vars_size, lp_var.model_var + 1);
1483 auto* search_heuristics =
model->GetOrCreate<SearchHeuristics>();
1487 search_heuristics->fixed_search =
1489 search_heuristics->fixed_search,
model);
1493 std::vector<BooleanOrIntegerVariable> vars;
1494 std::vector<IntegerValue> values;
1495 for (
int i = 0; i <
model_proto.solution_hint().vars_size(); ++i) {
1496 const int ref =
model_proto.solution_hint().vars(i);
1498 BooleanOrIntegerVariable
var;
1499 if (mapping->IsBoolean(ref)) {
1500 var.bool_var = mapping->Literal(ref).Variable();
1502 var.int_var = mapping->Integer(ref);
1504 vars.push_back(
var);
1505 values.push_back(IntegerValue(
model_proto.solution_hint().values(i)));
1513 const std::string solution_info =
model->Name();
1515 shared_response_manager]() {
1518 response.set_solution_info(solution_info);
1522 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1523 CoreBasedOptimizer* core =
1524 new CoreBasedOptimizer(objective_var, objective.vars, objective.coeffs,
1525 solution_observer,
model);
1526 model->Register<CoreBasedOptimizer>(core);
1527 model->TakeOwnership(core);
1537 void SolveLoadedCpModel(
const CpModelProto&
model_proto,
1538 SharedResponseManager* shared_response_manager,
1540 if (shared_response_manager->ProblemIsSolved())
return;
1542 const std::string& solution_info =
model->Name();
1544 &shared_response_manager]() {
1547 response.set_solution_info(solution_info);
1554 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1556 const SatParameters&
parameters = *
model->GetOrCreate<SatParameters>();
1558 std::vector<BooleanVariable> bool_vars;
1559 std::vector<IntegerVariable> int_vars;
1560 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1561 absl::flat_hash_set<BooleanVariable> visited;
1562 for (
int v = 0; v <
model_proto.variables_size(); ++v) {
1563 if (mapping.IsBoolean(v)) {
1564 const BooleanVariable bool_var = mapping.Literal(v).Variable();
1565 if (!visited.contains(bool_var)) {
1566 visited.insert(bool_var);
1567 bool_vars.push_back(bool_var);
1570 IntegerVariable
var = mapping.Integer(v);
1571 if (integer_trail->IsFixed(
var))
continue;
1572 int_vars.push_back(
var);
1581 solution_observer();
1582 if (!
parameters.enumerate_all_solutions())
break;
1586 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1590 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1594 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1595 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1597 std::vector<int> core_in_proto_format;
1598 for (
const Literal l : core) {
1599 core_in_proto_format.push_back(
1600 mapping.GetProtoVariableFromBooleanVariable(l.Variable()));
1601 if (!l.IsPositive()) {
1602 core_in_proto_format.back() =
NegatedRef(core_in_proto_format.back());
1605 shared_response_manager->AddUnsatCore(core_in_proto_format);
1609 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1610 const IntegerVariable objective_var = objective.objective_var;
1618 objective, solution_observer,
model);
1620 status =
model->Mutable<CoreBasedOptimizer>()->Optimize();
1625 if (
parameters.binary_search_num_conflicts() >= 0) {
1627 solution_observer,
model);
1630 objective_var, solution_observer,
model);
1638 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1645 shared_response_manager->SetStatsFromModel(
model);
1650 void QuickSolveWithHint(
const CpModelProto&
model_proto,
1651 SharedResponseManager* shared_response_manager,
1654 if (shared_response_manager->ProblemIsSolved())
return;
1658 const SatParameters saved_params = *
parameters;
1660 parameters->set_search_branching(SatParameters::HINT_SEARCH);
1667 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1671 const std::string& solution_info =
model->Name();
1675 response.set_solution_info(absl::StrCat(solution_info,
" [hint]"));
1684 const IntegerVariable objective_var =
1685 model->GetOrCreate<ObjectiveDefinition>()->objective_var;
1686 model->GetOrCreate<SatSolver>()->Backtrack(0);
1687 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1688 if (!integer_trail->Enqueue(
1691 shared_response_manager->GetInnerObjectiveUpperBound()),
1693 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1694 absl::StrCat(solution_info,
" [hint]"));
1695 shared_response_manager->SetStatsFromModel(
model);
1705 void MinimizeL1DistanceWithHint(
const CpModelProto&
model_proto,
1706 SharedResponseManager* shared_response_manager,
1708 SharedTimeLimit* shared_time_limit,
1712 if (shared_response_manager->ProblemIsSolved())
return;
1714 auto*
parameters = local_model.GetOrCreate<SatParameters>();
1718 if (
parameters->enumerate_all_solutions())
return;
1721 const SatParameters saved_params = *
model->GetOrCreate<SatParameters>();
1728 updated_model_proto.clear_objective();
1731 for (
int i = 0; i <
model_proto.solution_hint().vars_size(); ++i) {
1736 const int new_var_index = updated_model_proto.variables_size();
1737 IntegerVariableProto* var_proto = updated_model_proto.add_variables();
1742 var_proto->add_domain(min_domain);
1743 var_proto->add_domain(max_domain);
1746 ConstraintProto*
const linear_constraint_proto =
1747 updated_model_proto.add_constraints();
1748 LinearConstraintProto* linear = linear_constraint_proto->mutable_linear();
1749 linear->add_vars(new_var_index);
1750 linear->add_coeffs(1);
1751 linear->add_vars(
var);
1752 linear->add_coeffs(-1);
1753 linear->add_domain(-
value);
1754 linear->add_domain(-
value);
1757 const int abs_var_index = updated_model_proto.variables_size();
1758 IntegerVariableProto* abs_var_proto = updated_model_proto.add_variables();
1759 const int64 abs_min_domain = 0;
1760 const int64 abs_max_domain =
1761 std::max(std::abs(min_domain), std::abs(max_domain));
1762 abs_var_proto->add_domain(abs_min_domain);
1763 abs_var_proto->add_domain(abs_max_domain);
1764 ConstraintProto*
const abs_constraint_proto =
1765 updated_model_proto.add_constraints();
1766 abs_constraint_proto->mutable_int_max()->set_target(abs_var_index);
1767 abs_constraint_proto->mutable_int_max()->add_vars(new_var_index);
1768 abs_constraint_proto->mutable_int_max()->add_vars(
1771 updated_model_proto.mutable_objective()->add_vars(abs_var_index);
1772 updated_model_proto.mutable_objective()->add_coeffs(1);
1775 SharedResponseManager local_response_manager(
1776 false,
parameters->enumerate_all_solutions(),
1777 &updated_model_proto,
wall_timer, shared_time_limit);
1779 local_model.Register<SharedResponseManager>(&local_response_manager);
1782 LoadCpModel(updated_model_proto, &local_response_manager, &local_model);
1785 const auto& mapping = *local_model.GetOrCreate<CpModelMapping>();
1787 mapping.Literals(updated_model_proto.assumptions()), &local_model);
1789 const std::string& solution_info =
model->Name();
1794 CpSolverResponse updated_response;
1795 FillSolutionInResponse(updated_model_proto, local_model,
1797 LOG(
INFO) <<
"Found solution with repaired hint penalty = "
1801 response.set_solution_info(absl::StrCat(solution_info,
" [repaired]"));
1810 void PostsolveResponseWithFullSolver(
1811 const int64 num_variables_in_original_model, CpModelProto mapping_proto,
1820 if (mapping_proto.variables_size() == 0) {
1825 for (
int i = 0; i <
response->solution_size(); ++i) {
1826 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1827 var_proto->clear_domain();
1828 var_proto->add_domain(
response->solution(i));
1829 var_proto->add_domain(
response->solution(i));
1831 for (
int i = 0; i <
response->solution_lower_bounds_size(); ++i) {
1832 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1835 .IntersectionWith({
response->solution_lower_bounds(i),
1836 response->solution_upper_bounds(i)}),
1843 Model postsolve_model;
1845 SatParameters& params = *postsolve_model.GetOrCreate<SatParameters>();
1846 params.set_linearization_level(0);
1847 params.set_cp_model_probing_level(0);
1851 SharedTimeLimit shared_time_limit(
time_limit.get());
1852 SharedResponseManager local_response_manager(
1853 false,
false, &mapping_proto,
1855 LoadCpModel(mapping_proto, &local_response_manager, &postsolve_model);
1856 SolveLoadedCpModel(mapping_proto, &local_response_manager, &postsolve_model);
1857 const CpSolverResponse postsolve_response =
1858 local_response_manager.GetResponse();
1864 response->clear_solution_lower_bounds();
1865 response->clear_solution_upper_bounds();
1866 if (!postsolve_response.solution().empty()) {
1867 for (
int i = 0; i < num_variables_in_original_model; ++i) {
1868 response->add_solution(postsolve_response.solution(i));
1871 for (
int i = 0; i < num_variables_in_original_model; ++i) {
1872 response->add_solution_lower_bounds(
1873 postsolve_response.solution_lower_bounds(i));
1874 response->add_solution_upper_bounds(
1875 postsolve_response.solution_upper_bounds(i));
1880 void PostsolveResponseWrapper(
const SatParameters& params,
1881 const int64 num_variables_in_original_model,
1882 const CpModelProto& mapping_proto,
1883 const std::vector<int>& postsolve_mapping,
1886 if (params.cp_model_postsolve_with_full_solver()) {
1887 PostsolveResponseWithFullSolver(num_variables_in_original_model,
1888 mapping_proto, postsolve_mapping,
1897 CpSolverResponse SolvePureSatModel(
const CpModelProto&
model_proto,
1899 std::unique_ptr<SatSolver> solver(
new SatSolver());
1902 model->GetOrCreate<TimeLimit>()->ResetLimitFromParameters(
parameters);
1905 std::unique_ptr<DratProofHandler> drat_proof_handler;
1906 #if !defined(__PORTABLE_PLATFORM__)
1907 if (!absl::GetFlag(FLAGS_drat_output).empty() ||
1908 absl::GetFlag(FLAGS_drat_check)) {
1909 if (!absl::GetFlag(FLAGS_drat_output).empty()) {
1913 drat_proof_handler = absl::make_unique<DratProofHandler>(
1914 false, output, absl::GetFlag(FLAGS_drat_check));
1916 drat_proof_handler = absl::make_unique<DratProofHandler>();
1918 solver->SetDratProofHandler(drat_proof_handler.get());
1922 auto get_literal = [](
int ref) {
1923 if (ref >= 0)
return Literal(BooleanVariable(ref),
true);
1924 return Literal(BooleanVariable(
NegatedRef(ref)),
false);
1927 std::vector<Literal> temp;
1928 const int num_variables =
model_proto.variables_size();
1929 solver->SetNumVariables(num_variables);
1930 if (drat_proof_handler !=
nullptr) {
1931 drat_proof_handler->SetNumVariables(num_variables);
1935 for (
int ref = 0; ref < num_variables; ++ref) {
1937 if (domain.IsFixed()) {
1938 const Literal ref_literal =
1939 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
1940 drat_proof_handler->AddProblemClause({ref_literal});
1943 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1944 switch (
ct.constraint_case()) {
1945 case ConstraintProto::ConstraintCase::kBoolAnd: {
1946 if (
ct.enforcement_literal_size() == 0) {
1947 for (
const int ref :
ct.bool_and().literals()) {
1948 drat_proof_handler->AddProblemClause({get_literal(ref)});
1952 const Literal not_a =
1953 get_literal(
ct.enforcement_literal(0)).Negated();
1954 for (
const int ref :
ct.bool_and().literals()) {
1955 drat_proof_handler->AddProblemClause({not_a, get_literal(ref)});
1960 case ConstraintProto::ConstraintCase::kBoolOr:
1962 for (
const int ref :
ct.bool_or().literals()) {
1963 temp.push_back(get_literal(ref));
1965 drat_proof_handler->AddProblemClause(temp);
1973 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1974 switch (
ct.constraint_case()) {
1975 case ConstraintProto::ConstraintCase::kBoolAnd: {
1976 if (
ct.enforcement_literal_size() == 0) {
1977 for (
const int ref :
ct.bool_and().literals()) {
1978 const Literal
b = get_literal(ref);
1979 solver->AddUnitClause(
b);
1983 const Literal not_a =
1984 get_literal(
ct.enforcement_literal(0)).Negated();
1985 for (
const int ref :
ct.bool_and().literals()) {
1986 const Literal
b = get_literal(ref);
1987 solver->AddProblemClause({not_a,
b});
1992 case ConstraintProto::ConstraintCase::kBoolOr:
1994 for (
const int ref :
ct.bool_or().literals()) {
1995 temp.push_back(get_literal(ref));
1997 solver->AddProblemClause(temp);
2005 for (
int ref = 0; ref < num_variables; ++ref) {
2007 if (domain.Min() == domain.Max()) {
2008 const Literal ref_literal =
2009 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
2010 solver->AddUnitClause(ref_literal);
2017 std::vector<bool> solution;
2019 &solution, drat_proof_handler.get());
2022 for (
int ref = 0; ref < num_variables; ++ref) {
2023 response.add_solution(solution[ref]);
2027 status = solver->SolveWithTimeLimit(
model->GetOrCreate<TimeLimit>());
2030 for (
int ref = 0; ref < num_variables; ++ref) {
2032 solver->Assignment().LiteralIsTrue(get_literal(ref)) ? 1 : 0);
2039 model->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
2040 solver->model()->GetOrCreate<TimeLimit>()->GetElapsedDeterministicTime());
2049 std::vector<int64>(
response.solution().begin(),
2059 LOG(
FATAL) <<
"Unexpected SatSolver::Status " << status;
2061 response.set_num_booleans(solver->NumVariables());
2062 response.set_num_branches(solver->num_branches());
2063 response.set_num_conflicts(solver->num_failures());
2064 response.set_num_binary_propagations(solver->num_propagations());
2065 response.set_num_integer_propagations(0);
2068 model->Get<TimeLimit>()->GetElapsedDeterministicTime());
2074 absl::GetFlag(FLAGS_max_drat_time_in_seconds));
2075 switch (drat_status) {
2077 LOG(
INFO) <<
"DRAT status: UNKNOWN";
2080 LOG(
INFO) <<
"DRAT status: VALID";
2083 LOG(
ERROR) <<
"DRAT status: INVALID";
2089 LOG(
INFO) <<
"DRAT wall time: " << drat_timer.
Get();
2090 }
else if (drat_proof_handler !=
nullptr) {
2093 LOG(
INFO) <<
"DRAT status: NA";
2094 LOG(
INFO) <<
"DRAT wall time: NA";
2095 LOG(
INFO) <<
"DRAT user time: NA";
2100 #if !defined(__PORTABLE_PLATFORM__)
2103 struct SharedClasses {
2113 bool SearchIsDone() {
2114 if (
response->ProblemIsSolved())
return true;
2121 class FullProblemSolver :
public SubSolver {
2123 FullProblemSolver(
const std::string&
name,
2124 const SatParameters& local_parameters,
bool split_in_chunks,
2125 SharedClasses* shared)
2128 split_in_chunks_(split_in_chunks),
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 RegisterVariableBoundsLevelZeroExport(
2156 *shared_->model_proto, shared_->bounds, local_model_.get());
2157 RegisterVariableBoundsLevelZeroImport(
2158 *shared_->model_proto, shared_->bounds, local_model_.get());
2162 bool TaskIsAvailable()
override {
2163 if (shared_->SearchIsDone())
return false;
2165 absl::MutexLock mutex_lock(&mutex_);
2166 return previous_task_is_completed_;
2169 std::function<void()> GenerateTask(
int64 task_id)
override {
2171 absl::MutexLock mutex_lock(&mutex_);
2172 previous_task_is_completed_ =
false;
2175 if (solving_first_chunk_) {
2176 LoadCpModel(*shared_->model_proto, shared_->response,
2177 local_model_.get());
2178 if (local_model_->GetOrCreate<SatParameters>()->repair_hint()) {
2179 MinimizeL1DistanceWithHint(*shared_->model_proto, shared_->response,
2180 shared_->wall_timer, shared_->time_limit,
2181 local_model_.get());
2183 QuickSolveWithHint(*shared_->model_proto, shared_->response,
2184 local_model_.get());
2188 solving_first_chunk_ =
false;
2190 if (split_in_chunks_) {
2192 absl::MutexLock mutex_lock(&mutex_);
2193 previous_task_is_completed_ =
true;
2198 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2199 if (split_in_chunks_) {
2202 auto* params = local_model_->GetOrCreate<SatParameters>();
2203 params->set_max_deterministic_time(1);
2204 time_limit->ResetLimitFromParameters(*params);
2205 shared_->time_limit->UpdateLocalLimit(
time_limit);
2208 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2209 SolveLoadedCpModel(*shared_->model_proto, shared_->response,
2210 local_model_.get());
2212 absl::MutexLock mutex_lock(&mutex_);
2213 deterministic_time_since_last_synchronize_ +=
2214 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2218 if (shared_->SearchIsDone()) {
2219 shared_->time_limit->Stop();
2224 if (split_in_chunks_) {
2225 absl::MutexLock mutex_lock(&mutex_);
2226 previous_task_is_completed_ =
true;
2234 local_model_.reset();
2241 void Synchronize()
override {
2242 absl::MutexLock mutex_lock(&mutex_);
2243 deterministic_time_ += deterministic_time_since_last_synchronize_;
2244 shared_->time_limit->AdvanceDeterministicTime(
2245 deterministic_time_since_last_synchronize_);
2246 deterministic_time_since_last_synchronize_ = 0.0;
2250 SharedClasses* shared_;
2251 const bool split_in_chunks_;
2252 std::unique_ptr<Model> local_model_;
2256 bool solving_first_chunk_ =
true;
2259 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2261 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2264 class FeasibilityPumpSolver :
public SubSolver {
2266 FeasibilityPumpSolver(
const SatParameters& local_parameters,
2267 SharedClasses* shared)
2268 : SubSolver(
"feasibility_pump"),
2270 local_model_(
absl::make_unique<Model>(name_)) {
2272 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
2273 shared_->time_limit->UpdateLocalLimit(
2274 local_model_->GetOrCreate<TimeLimit>());
2276 if (shared->response !=
nullptr) {
2277 local_model_->Register<SharedResponseManager>(shared->response);
2280 if (shared->relaxation_solutions !=
nullptr) {
2281 local_model_->Register<SharedRelaxationSolutionRepository>(
2282 shared->relaxation_solutions);
2285 if (shared->lp_solutions !=
nullptr) {
2286 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
2289 if (shared->incomplete_solutions !=
nullptr) {
2290 local_model_->Register<SharedIncompleteSolutionManager>(
2291 shared->incomplete_solutions);
2295 if (shared_->bounds !=
nullptr) {
2296 RegisterVariableBoundsLevelZeroImport(
2297 *shared_->model_proto, shared_->bounds, local_model_.get());
2301 bool TaskIsAvailable()
override {
2302 if (shared_->SearchIsDone())
return false;
2303 absl::MutexLock mutex_lock(&mutex_);
2304 return previous_task_is_completed_;
2307 std::function<void()> GenerateTask(
int64 task_id)
override {
2310 absl::MutexLock mutex_lock(&mutex_);
2311 if (!previous_task_is_completed_)
return;
2312 previous_task_is_completed_ =
false;
2315 absl::MutexLock mutex_lock(&mutex_);
2316 if (solving_first_chunk_) {
2317 LoadFeasibilityPump(*shared_->model_proto, shared_->response,
2318 local_model_.get());
2321 if (local_model_->Get<FeasibilityPump>() ==
nullptr)
return;
2322 solving_first_chunk_ =
false;
2324 previous_task_is_completed_ =
true;
2329 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2330 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2331 auto* feasibility_pump = local_model_->Mutable<FeasibilityPump>();
2332 if (!feasibility_pump->Solve()) {
2333 shared_->response->NotifyThatImprovingProblemIsInfeasible(name_);
2337 absl::MutexLock mutex_lock(&mutex_);
2338 deterministic_time_since_last_synchronize_ +=
2339 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2343 if (shared_->SearchIsDone()) {
2344 shared_->time_limit->Stop();
2348 absl::MutexLock mutex_lock(&mutex_);
2349 previous_task_is_completed_ =
true;
2353 void Synchronize()
override {
2354 absl::MutexLock mutex_lock(&mutex_);
2355 deterministic_time_ += deterministic_time_since_last_synchronize_;
2356 shared_->time_limit->AdvanceDeterministicTime(
2357 deterministic_time_since_last_synchronize_);
2358 deterministic_time_since_last_synchronize_ = 0.0;
2362 SharedClasses* shared_;
2363 std::unique_ptr<Model> local_model_;
2369 bool solving_first_chunk_ ABSL_GUARDED_BY(mutex_) =
true;
2371 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2373 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2377 class LnsSolver :
public SubSolver {
2379 LnsSolver(std::unique_ptr<NeighborhoodGenerator> generator,
2381 NeighborhoodGeneratorHelper* helper, SharedClasses* shared)
2382 : SubSolver(generator->
name()),
2383 generator_(std::move(generator)),
2388 bool TaskIsAvailable()
override {
2389 if (shared_->SearchIsDone())
return false;
2390 return generator_->ReadyToGenerate();
2393 std::function<void()> GenerateTask(
int64 task_id)
override {
2394 return [task_id,
this]() {
2395 if (shared_->SearchIsDone())
return;
2400 const int32 low =
static_cast<int32>(task_id);
2401 const int32 high = task_id >> 32;
2402 std::seed_seq seed{low, high, parameters_.random_seed()};
2405 NeighborhoodGenerator::SolveData data;
2406 data.difficulty = generator_->difficulty();
2407 data.deterministic_limit = generator_->deterministic_limit();
2410 CpSolverResponse base_response;
2412 const SharedSolutionRepository<int64>& repo =
2413 shared_->response->SolutionsRepository();
2414 if (repo.NumSolutions() > 0) {
2416 const SharedSolutionRepository<int64>::Solution solution =
2417 repo.GetRandomBiasedSolution(random);
2418 for (
const int64 value : solution.variable_values) {
2419 base_response.add_solution(
value);
2423 data.initial_best_objective = repo.GetSolution(0).rank;
2424 data.base_objective = solution.rank;
2433 data.initial_best_objective =
2434 shared_->response->GetInnerObjectiveUpperBound();
2435 data.base_objective = data.initial_best_objective;
2439 Neighborhood neighborhood;
2441 absl::MutexLock mutex_lock(helper_->MutableMutex());
2443 generator_->Generate(base_response, data.difficulty, random);
2445 neighborhood.cp_model.set_name(absl::StrCat(
"lns_", task_id));
2446 if (!neighborhood.is_generated)
return;
2447 data.neighborhood_id = neighborhood.id;
2449 const double fully_solved_proportion =
2450 static_cast<double>(generator_->num_fully_solved_calls()) /
2452 std::string source_info =
name();
2453 if (!neighborhood.source_info.empty()) {
2454 absl::StrAppend(&source_info,
"_", neighborhood.source_info);
2456 const std::string solution_info = absl::StrFormat(
2457 "%s(d=%0.2f s=%i t=%0.2f p=%0.2f)", source_info, data.difficulty,
2458 task_id, data.deterministic_limit, fully_solved_proportion);
2460 SatParameters local_params(parameters_);
2461 local_params.set_max_deterministic_time(data.deterministic_limit);
2462 local_params.set_stop_after_first_solution(
false);
2463 local_params.set_log_search_progress(
false);
2464 local_params.set_cp_model_probing_level(0);
2466 if (absl::GetFlag(FLAGS_cp_model_dump_lns)) {
2467 const std::string
name =
2468 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2469 neighborhood.cp_model.name(),
".pbtxt");
2470 LOG(
INFO) <<
"Dumping LNS model to '" <<
name <<
"'.";
2476 *(local_model.GetOrCreate<SatParameters>()) = local_params;
2477 TimeLimit* local_time_limit = local_model.GetOrCreate<TimeLimit>();
2478 local_time_limit->ResetLimitFromParameters(local_params);
2479 shared_->time_limit->UpdateLocalLimit(local_time_limit);
2481 const int64 num_neighborhood_model_vars =
2482 neighborhood.cp_model.variables_size();
2484 CpModelProto mapping_proto;
2485 std::vector<int> postsolve_mapping;
2486 auto context = absl::make_unique<PresolveContext>(
2487 VLOG_IS_ON(3), &local_model, &neighborhood.cp_model, &mapping_proto);
2496 SharedResponseManager local_response_manager(
2498 &neighborhood.cp_model, shared_->wall_timer, shared_->time_limit);
2499 LoadCpModel(neighborhood.cp_model, &local_response_manager, &local_model);
2500 QuickSolveWithHint(neighborhood.cp_model, &local_response_manager,
2502 SolveLoadedCpModel(neighborhood.cp_model, &local_response_manager,
2504 CpSolverResponse local_response = local_response_manager.GetResponse();
2505 if (local_response.solution_info().empty()) {
2506 local_response.set_solution_info(solution_info);
2508 local_response.set_solution_info(
2509 absl::StrCat(local_response.solution_info(),
" ", solution_info));
2514 PostsolveResponseWrapper(local_params, num_neighborhood_model_vars,
2515 mapping_proto, postsolve_mapping,
2516 shared_->wall_timer, &local_response);
2517 data.status = local_response.status();
2518 data.deterministic_time = local_time_limit->GetElapsedDeterministicTime();
2520 if (generator_->IsRelaxationGenerator()) {
2521 bool has_feasible_solution =
false;
2524 has_feasible_solution =
true;
2528 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2529 local_response.solution_info());
2532 if (shared_->model_proto->has_objective()) {
2535 const IntegerValue current_obj_lb =
2536 shared_->response->GetInnerObjectiveLowerBound();
2538 const IntegerValue local_obj_lb =
2539 local_response_manager.GetInnerObjectiveLowerBound();
2542 neighborhood.cp_model.objective(), local_obj_lb.value());
2545 const IntegerValue new_inner_obj_lb = IntegerValue(
2547 scaled_local_obj_bound) -
2549 data.new_objective_bound = new_inner_obj_lb;
2550 data.initial_best_objective_bound = current_obj_lb;
2551 if (new_inner_obj_lb > current_obj_lb) {
2552 shared_->response->UpdateInnerObjectiveBounds(
2559 if (has_feasible_solution) {
2561 *shared_->model_proto,
2562 std::vector<int64>(local_response.solution().begin(),
2563 local_response.solution().end()))) {
2564 shared_->response->NewSolution(local_response,
2569 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2570 local_response.solution_info());
2571 shared_->time_limit->Stop();
2574 shared_->relaxation_solutions->NewRelaxationSolution(local_response);
2577 if (!local_response.solution().empty()) {
2579 *shared_->model_proto,
2580 std::vector<int64>(local_response.solution().begin(),
2581 local_response.solution().end())))
2586 data.new_objective = data.base_objective;
2590 shared_->model_proto->objective(), local_response));
2596 shared_->response->NewSolution(local_response,
2599 if (!neighborhood.is_reduced &&
2602 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2603 local_response.solution_info());
2604 shared_->time_limit->Stop();
2608 generator_->AddSolveData(data);
2611 const int total_num_calls = task_id;
2612 VLOG(2) <<
name() <<
": [difficulty: " << data.difficulty
2613 <<
", id: " << task_id
2614 <<
", deterministic_time: " << data.deterministic_time <<
" / "
2615 << data.deterministic_limit
2616 <<
", status: " << ProtoEnumToString<CpSolverStatus>(data.status)
2617 <<
", num calls: " << generator_->num_calls()
2618 <<
", UCB1 Score: " << generator_->GetUCBScore(total_num_calls)
2619 <<
", p: " << fully_solved_proportion <<
"]";
2623 void Synchronize()
override {
2624 generator_->Synchronize();
2625 const double old = deterministic_time_;
2626 deterministic_time_ = generator_->deterministic_time();
2627 shared_->time_limit->AdvanceDeterministicTime(deterministic_time_ - old);
2631 std::unique_ptr<NeighborhoodGenerator> generator_;
2632 NeighborhoodGeneratorHelper* helper_;
2633 const SatParameters parameters_;
2634 SharedClasses* shared_;
2637 void SolveCpModelParallel(
const CpModelProto&
model_proto,
2638 SharedResponseManager* shared_response_manager,
2639 SharedTimeLimit* shared_time_limit,
2641 CHECK(shared_response_manager !=
nullptr);
2642 const SatParameters&
parameters = *global_model->GetOrCreate<SatParameters>();
2643 const int num_search_workers =
parameters.num_search_workers();
2646 <<
"Enumerating all solutions in parallel is not supported.";
2648 std::unique_ptr<SharedBoundsManager> shared_bounds_manager;
2650 shared_bounds_manager = absl::make_unique<SharedBoundsManager>(
model_proto);
2653 std::unique_ptr<SharedRelaxationSolutionRepository>
2654 shared_relaxation_solutions;
2656 shared_relaxation_solutions =
2657 absl::make_unique<SharedRelaxationSolutionRepository>(
2659 global_model->Register<SharedRelaxationSolutionRepository>(
2660 shared_relaxation_solutions.get());
2663 auto shared_lp_solutions = absl::make_unique<SharedLPSolutionRepository>(
2665 global_model->Register<SharedLPSolutionRepository>(shared_lp_solutions.get());
2669 std::unique_ptr<SharedIncompleteSolutionManager> shared_incomplete_solutions;
2670 const bool use_feasibility_pump =
parameters.use_feasibility_pump() &&
2674 if (use_feasibility_pump) {
2675 shared_incomplete_solutions =
2676 absl::make_unique<SharedIncompleteSolutionManager>();
2677 global_model->Register<SharedIncompleteSolutionManager>(
2678 shared_incomplete_solutions.get());
2681 SharedClasses shared;
2684 shared.time_limit = shared_time_limit;
2685 shared.bounds = shared_bounds_manager.get();
2686 shared.response = shared_response_manager;
2687 shared.relaxation_solutions = shared_relaxation_solutions.get();
2688 shared.lp_solutions = shared_lp_solutions.get();
2689 shared.incomplete_solutions = shared_incomplete_solutions.get();
2692 std::vector<std::unique_ptr<SubSolver>> subsolvers;
2695 subsolvers.push_back(absl::make_unique<SynchronizationPoint>(
2696 [shared_response_manager, &shared_bounds_manager,
2697 &shared_relaxation_solutions, &shared_lp_solutions]() {
2698 shared_response_manager->Synchronize();
2699 shared_response_manager->MutableSolutionsRepository()->Synchronize();
2700 if (shared_bounds_manager !=
nullptr) {
2701 shared_bounds_manager->Synchronize();
2703 if (shared_relaxation_solutions !=
nullptr) {
2704 shared_relaxation_solutions->Synchronize();
2706 if (shared_lp_solutions !=
nullptr) {
2707 shared_lp_solutions->Synchronize();
2716 local_params.set_stop_after_first_solution(
true);
2717 local_params.set_linearization_level(0);
2718 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2719 "first_solution", local_params,
2725 if (
parameters.optimize_with_max_hs())
continue;
2727 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2728 local_params.name(), local_params,
2734 if (use_feasibility_pump) {
2735 subsolvers.push_back(
2736 absl::make_unique<FeasibilityPumpSolver>(
parameters, &shared));
2743 auto unique_helper = absl::make_unique<NeighborhoodGeneratorHelper>(
2745 shared_bounds_manager.get());
2746 NeighborhoodGeneratorHelper* helper = unique_helper.get();
2747 subsolvers.push_back(std::move(unique_helper));
2750 std::vector<SatParameters> lns_params = {
parameters};
2751 lns_params.back().set_name(
"default");
2753 std::vector<SatParameters> lns_params =
2756 for (
const SatParameters& local_params : lns_params) {
2761 subsolvers.push_back(absl::make_unique<LnsSolver>(
2762 absl::make_unique<SimpleNeighborhoodGenerator>(
2763 helper, absl::StrCat(
"rnd_lns_", local_params.name())),
2764 local_params, helper, &shared));
2765 subsolvers.push_back(absl::make_unique<LnsSolver>(
2766 absl::make_unique<VariableGraphNeighborhoodGenerator>(
2767 helper, absl::StrCat(
"var_lns_", local_params.name())),
2768 local_params, helper, &shared));
2769 subsolvers.push_back(absl::make_unique<LnsSolver>(
2770 absl::make_unique<ConstraintGraphNeighborhoodGenerator>(
2771 helper, absl::StrCat(
"cst_lns_", local_params.name())),
2772 local_params, helper, &shared));
2774 if (!helper->TypeToConstraints(ConstraintProto::kNoOverlap).empty()) {
2775 subsolvers.push_back(absl::make_unique<LnsSolver>(
2776 absl::make_unique<SchedulingTimeWindowNeighborhoodGenerator>(
2777 helper, absl::StrCat(
"scheduling_time_window_lns_",
2778 local_params.name())),
2779 local_params, helper, &shared));
2780 subsolvers.push_back(absl::make_unique<LnsSolver>(
2781 absl::make_unique<SchedulingNeighborhoodGenerator>(
2783 absl::StrCat(
"scheduling_random_lns_", local_params.name())),
2784 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(
2831 absl::make_unique<SynchronizationPoint>([shared_response_manager]() {
2832 shared_response_manager->UpdatePrimalIntegral();
2837 std::vector<std::string> names;
2838 for (
const auto& subsolver : subsolvers) {
2839 if (!subsolver->name().empty()) names.push_back(subsolver->name());
2842 "*** starting Search at %.2fs with %i workers and subsolvers: [ %s ]",
2843 wall_timer->
Get(), num_search_workers, absl::StrJoin(names,
", "));
2860 void AddPostsolveClauses(
const std::vector<int>& postsolve_mapping,
2861 Model*
model, CpModelProto* mapping_proto) {
2862 auto* mapping =
model->GetOrCreate<CpModelMapping>();
2863 auto* postsolve =
model->GetOrCreate<PostsolveClauses>();
2864 for (
const auto& clause : postsolve->clauses) {
2865 auto*
ct = mapping_proto->add_constraints()->mutable_bool_or();
2866 for (
const Literal l : clause) {
2867 int var = mapping->GetProtoVariableFromBooleanVariable(l.Variable());
2869 var = postsolve_mapping[
var];
2873 postsolve->clauses.clear();
2884 #if defined(_MSC_VER)
2888 std::unique_ptr<CpSolverResponse> final_response_ptr(
new CpSolverResponse());
2889 CpSolverResponse& final_response = *final_response_ptr.get();
2891 CpSolverResponse final_response;
2894 #if !defined(__PORTABLE_PLATFORM__)
2896 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
2897 const std::string
file =
2898 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
"model.pbtxt");
2899 LOG(
INFO) <<
"Dumping cp model proto to '" <<
file <<
"'.";
2904 if (absl::GetFlag(FLAGS_cp_model_dump_response)) {
2905 const std::string
file = absl::StrCat(
2906 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"response.pbtxt");
2907 LOG(
INFO) <<
"Dumping response proto to '" <<
file <<
"'.";
2913 if (!absl::GetFlag(FLAGS_cp_model_params).empty()) {
2914 SatParameters params = *
model->GetOrCreate<SatParameters>();
2915 SatParameters flag_params;
2916 CHECK(google::protobuf::TextFormat::ParseFromString(
2917 absl::GetFlag(FLAGS_cp_model_params), &flag_params));
2918 params.MergeFrom(flag_params);
2919 *(
model->GetOrCreate<SatParameters>()) = params;
2925 *
model->GetOrCreate<SatParameters>());
2928 #if !defined(__PORTABLE_PLATFORM__)
2931 if (
model->GetOrCreate<SatParameters>()->catch_sigint_signal()) {
2932 handler.
Register([&shared_time_limit]() { shared_time_limit.Stop(); });
2936 const SatParameters& params = *
model->GetOrCreate<SatParameters>();
2937 const bool log_search = params.log_search_progress() ||
VLOG_IS_ON(1);
2938 LOG_IF(
INFO, log_search) <<
"Parameters: " << params.ShortDebugString();
2939 if (log_search && params.use_absl_random()) {
2944 auto display_response_cleanup =
2956 if (!error.empty()) {
2959 return final_response;
2968 if (!params.use_sat_inprocessing() && !
model_proto.has_objective() &&
2969 !
model_proto.has_solution_hint() && !params.enumerate_all_solutions() &&
2970 !params.use_lns_only() && params.num_search_workers() <= 1 &&
2972 bool is_pure_sat =
true;
2973 for (
const IntegerVariableProto&
var :
model_proto.variables()) {
2974 if (
var.domain_size() != 2 ||
var.domain(0) < 0 ||
var.domain(1) > 1) {
2975 is_pure_sat =
false;
2980 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
2981 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolOr &&
2982 ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolAnd) {
2983 is_pure_sat =
false;
2993 final_response.set_user_time(user_timer.
Get());
2994 final_response.set_deterministic_time(
2995 shared_time_limit.GetElapsedDeterministicTime());
2996 const SatParameters& params = *
model->GetOrCreate<SatParameters>();
2997 if (params.fill_tightened_domains_in_response()) {
2998 *final_response.mutable_tightened_variables() =
model_proto.variables();
3000 return final_response;
3009 CpModelProto mapping_proto;
3010 auto context = absl::make_unique<PresolveContext>(
3011 log_search,
model, &new_cp_model_proto, &mapping_proto);
3013 bool degraded_assumptions_support =
false;
3014 if (params.num_search_workers() > 1 ||
model_proto.has_objective()) {
3021 degraded_assumptions_support =
true;
3022 context->InitializeNewDomains();
3024 if (!
context->SetLiteralToTrue(ref)) {
3026 final_response.add_sufficient_assumptions_for_infeasibility(ref);
3027 return final_response;
3034 std::function<void(CpSolverResponse *
response)> postprocess_solution;
3037 std::vector<int> postsolve_mapping;
3040 LOG(
ERROR) <<
"Error while presolving, likely due to integer overflow.";
3042 return final_response;
3045 if (params.cp_model_presolve()) {
3046 postprocess_solution = [&
model_proto, ¶ms, &mapping_proto,
3047 &shared_time_limit, &postsolve_mapping, &
wall_timer,
3049 AddPostsolveClauses(postsolve_mapping,
model, &mapping_proto);
3050 PostsolveResponseWrapper(params,
model_proto.variables_size(),
3051 mapping_proto, postsolve_mapping, &
wall_timer,
3053 if (!
response->solution().empty()) {
3056 std::vector<int64>(
response->solution().begin(),
3058 &mapping_proto, &postsolve_mapping))
3059 <<
"final postsolved solution";
3061 if (params.fill_tightened_domains_in_response()) {
3063 if (mapping_proto.variables().size() >=
3065 for (
int i = 0; i <
model_proto.variables().size(); ++i) {
3066 *
response->add_tightened_variables() = mapping_proto.variables(i);
3071 response->set_user_time(user_timer.Get());
3073 shared_time_limit.GetElapsedDeterministicTime());
3078 &user_timer](CpSolverResponse*
response) {
3080 const int initial_size =
model_proto.variables_size();
3081 if (
response->solution_size() > 0) {
3082 response->mutable_solution()->Truncate(initial_size);
3083 }
else if (
response->solution_lower_bounds_size() > 0) {
3084 response->mutable_solution_lower_bounds()->Truncate(initial_size);
3085 response->mutable_solution_upper_bounds()->Truncate(initial_size);
3087 if (params.fill_tightened_domains_in_response()) {
3093 shared_time_limit.GetElapsedDeterministicTime());
3101 log_search, params.enumerate_all_solutions(), &new_cp_model_proto,
3104 absl::GetFlag(FLAGS_cp_model_dump_prefix));
3108 if (!observers.empty()) {
3110 [&
model_proto, &observers, &postprocess_solution](
3111 const CpSolverResponse& response_of_presolved_problem) {
3112 CpSolverResponse
response = response_of_presolved_problem;
3114 if (!
response.solution().empty()) {
3116 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
3123 for (
const auto& observer : observers) {
3133 if (new_cp_model_proto.has_objective()) {
3137 "initial domain", IntegerValue(domain.
Min()),
3138 IntegerValue(domain.
Max()));
3146 #if !defined(__PORTABLE_PLATFORM__)
3147 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
3148 const std::string presolved_file = absl::StrCat(
3149 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"presolved_model.pbtxt");
3150 LOG(
INFO) <<
"Dumping presolved cp model proto to '" << presolved_file
3155 const std::string mapping_file = absl::StrCat(
3156 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"mapping_model.pbtxt");
3157 LOG(
INFO) <<
"Dumping mapping cp model proto to '" << mapping_file <<
"'.";
3162 if (params.stop_after_presolve() || shared_time_limit.LimitReached()) {
3163 int64 num_terms = 0;
3164 for (
const ConstraintProto&
ct : new_cp_model_proto.constraints()) {
3168 <<
"Stopped after presolve."
3169 <<
"\nPresolvedNumVariables: " << new_cp_model_proto.variables().size()
3170 <<
"\nPresolvedNumConstraints: "
3171 << new_cp_model_proto.constraints().size()
3172 <<
"\nPresolvedNumTerms: " << num_terms;
3176 final_response = shared_response_manager.
GetResponse();
3177 postprocess_solution(&final_response);
3178 return final_response;
3182 if (params.stop_after_first_solution()) {
3184 [&shared_time_limit](
3185 const CpSolverResponse& response_of_presolved_problem) {
3186 shared_time_limit.Stop();
3190 #if defined(__PORTABLE_PLATFORM__)
3194 if (params.num_search_workers() > 1 || params.interleave_search()) {
3195 SolveCpModelParallel(new_cp_model_proto, &shared_response_manager,
3200 LOG(
INFO) << absl::StrFormat(
"*** starting to load the model at %.2fs",
3204 LoadCpModel(new_cp_model_proto, &shared_response_manager,
model);
3207 LOG(
INFO) << absl::StrFormat(
"*** starting sequential search at %.2fs",
3209 LOG(
INFO) <<
"Initial num_bool: "
3212 if (params.repair_hint()) {
3213 MinimizeL1DistanceWithHint(new_cp_model_proto, &shared_response_manager,
3216 QuickSolveWithHint(new_cp_model_proto, &shared_response_manager,
model);
3218 SolveLoadedCpModel(new_cp_model_proto, &shared_response_manager,
model);
3221 final_response = shared_response_manager.
GetResponse();
3222 postprocess_solution(&final_response);
3223 if (!final_response.solution().empty()) {
3225 model_proto, std::vector<int64>(final_response.solution().begin(),
3226 final_response.solution().end())));
3228 if (degraded_assumptions_support &&
3231 *final_response.mutable_sufficient_assumptions_for_infeasibility() =
3234 return final_response;
3243 const SatParameters& params) {
3249 #if !defined(__PORTABLE_PLATFORM__)
3251 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 UpdateInnerObjectiveBounds(const std::string &worker_info, IntegerValue lb, IntegerValue ub)
void NewSolution(const CpSolverResponse &response, Model *model)
void SetGapLimitsFromParameters(const SatParameters ¶meters)
int AddSolutionCallback(std::function< void(const CpSolverResponse &)> callback)
void SetUpdatePrimalIntegralOnEachChange(bool set)
void LoadDebugSolution(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
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)
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)