28 #if !defined(__PORTABLE_PLATFORM__)
29 #include "absl/synchronization/notification.h"
30 #include "google/protobuf/text_format.h"
35 #include "absl/container/flat_hash_set.h"
36 #include "absl/memory/memory.h"
37 #include "absl/status/status.h"
38 #include "absl/strings/str_cat.h"
39 #include "absl/strings/str_format.h"
40 #include "absl/strings/str_join.h"
41 #include "absl/synchronization/mutex.h"
90 ABSL_FLAG(std::string, cp_model_dump_prefix,
".\\",
91 "Prefix filename for all dumped files");
93 ABSL_FLAG(std::string, cp_model_dump_prefix,
"/tmp/",
94 "Prefix filename for all dumped files");
97 "DEBUG ONLY. When set to true, SolveCpModel() will dump its model "
98 "protos (original model, presolved model, mapping model) in text "
99 "format to 'FLAGS_cp_model_dump_prefix'{model|presolved_model|"
100 "mapping_model}.pbtxt.");
103 "DEBUG ONLY. When set to true, solve will dump all "
104 "lns models proto in text format to "
105 "'FLAGS_cp_model_dump_prefix'lns_xxx.pbtxt.");
108 "DEBUG ONLY. If true, the final response of each solve will be "
109 "dumped to 'FLAGS_cp_model_dump_prefix'response.pbtxt");
112 "This is interpreted as a text SatParameters proto. The "
113 "specified fields will override the normal ones for all solves.");
116 "If non-empty, a proof in DRAT format will be written to this file. "
117 "This will only be used for pure-SAT problems.");
120 "If true, a proof in DRAT format will be stored in memory and "
121 "checked if the problem is UNSAT. This will only be used for "
122 "pure-SAT problems.");
125 std::numeric_limits<double>::infinity(),
126 "Maximum time in seconds to check the DRAT proof. This will only "
127 "be used is the drat_check flag is enabled.");
129 ABSL_FLAG(
bool, cp_model_check_intermediate_solutions,
false,
130 "When true, all intermediate solutions found by the solver will be "
131 "checked. This can be expensive, therefore it is off by default.");
134 "If non-empty, dump a contention pprof proto to the specified "
135 "destination at the end of the solve.");
143 std::string Summarize(
const std::string&
input) {
146 return absl::StrCat(
input.substr(0, half),
" ... ",
157 std::map<std::string, int> num_constraints_by_name;
158 std::map<std::string, int> num_reif_constraints_by_name;
159 std::map<std::string, int> name_to_num_literals;
160 std::map<std::string, int> name_to_num_terms;
161 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
166 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) {
167 if (
ct.linear().vars_size() == 1)
name +=
"1";
168 if (
ct.linear().vars_size() == 2)
name +=
"2";
169 if (
ct.linear().vars_size() == 3)
name +=
"3";
170 if (
ct.linear().vars_size() > 3)
name +=
"N";
173 num_constraints_by_name[
name]++;
174 if (!
ct.enforcement_literal().empty()) {
175 num_reif_constraints_by_name[
name]++;
180 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) {
181 name_to_num_literals[
name] +=
ct.bool_or().literals().size();
182 }
else if (
ct.constraint_case() ==
183 ConstraintProto::ConstraintCase::kBoolAnd) {
184 name_to_num_literals[
name] +=
ct.bool_and().literals().size();
185 }
else if (
ct.constraint_case() ==
186 ConstraintProto::ConstraintCase::kAtMostOne) {
187 name_to_num_literals[
name] +=
ct.at_most_one().literals().size();
188 }
else if (
ct.constraint_case() ==
189 ConstraintProto::ConstraintCase::kExactlyOne) {
190 name_to_num_literals[
name] +=
ct.exactly_one().literals().size();
193 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear &&
194 ct.linear().vars_size() > 3) {
195 name_to_num_terms[
name] +=
ct.linear().vars_size();
199 int num_constants = 0;
200 std::set<int64_t> constant_values;
201 std::map<Domain, int> num_vars_per_domains;
203 if (
var.domain_size() == 2 &&
var.domain(0) ==
var.domain(1)) {
205 constant_values.insert(
var.domain(0));
213 absl::StrAppend(&result,
"optimization model '",
model_proto.name(),
216 absl::StrAppend(&result,
"satisfaction model '",
model_proto.name(),
220 for (
const DecisionStrategyProto& strategy :
model_proto.search_strategy()) {
222 &result,
"Search strategy: on ", strategy.variables_size(),
224 ProtoEnumToString<DecisionStrategyProto::VariableSelectionStrategy>(
225 strategy.variable_selection_strategy()),
227 ProtoEnumToString<DecisionStrategyProto::DomainReductionStrategy>(
228 strategy.domain_reduction_strategy()),
232 const std::string objective_string =
234 ? absl::StrCat(
" (",
model_proto.objective().vars_size(),
237 absl::StrAppend(&result,
"#Variables: ",
model_proto.variables_size(),
238 objective_string,
"\n");
239 if (num_vars_per_domains.size() < 100) {
240 for (
const auto& entry : num_vars_per_domains) {
241 const std::string temp = absl::StrCat(
" - ", entry.second,
" in ",
242 entry.first.ToString(),
"\n");
243 absl::StrAppend(&result, Summarize(temp));
246 int64_t max_complexity = 0;
249 for (
const auto& entry : num_vars_per_domains) {
253 max_complexity,
static_cast<int64_t
>(entry.first.NumIntervals()));
255 absl::StrAppend(&result,
" - ", num_vars_per_domains.size(),
256 " different domains in [",
min,
",",
max,
257 "] with a largest complexity of ", max_complexity,
".\n");
260 if (num_constants > 0) {
261 const std::string temp =
262 absl::StrCat(
" - ", num_constants,
" constants in {",
263 absl::StrJoin(constant_values,
","),
"} \n");
264 absl::StrAppend(&result, Summarize(temp));
267 std::vector<std::string> constraints;
268 constraints.reserve(num_constraints_by_name.size());
269 for (
const auto& entry : num_constraints_by_name) {
270 const std::string&
name = entry.first;
271 constraints.push_back(absl::StrCat(
"#",
name,
": ", entry.second));
273 absl::StrAppend(&constraints.back(),
274 " (#enforced: ", num_reif_constraints_by_name[
name],
")");
277 absl::StrAppend(&constraints.back(),
278 " (#literals: ", name_to_num_literals[
name],
")");
281 absl::StrAppend(&constraints.back(),
282 " (#terms: ", name_to_num_terms[
name],
")");
285 std::sort(constraints.begin(), constraints.end());
286 absl::StrAppend(&result, absl::StrJoin(constraints,
"\n"));
292 bool has_objective) {
294 absl::StrAppend(&result,
"CpSolverResponse summary:");
295 absl::StrAppend(&result,
"\nstatus: ",
296 ProtoEnumToString<CpSolverStatus>(
response.status()));
299 absl::StrAppendFormat(&result,
"\nobjective: %.16g",
301 absl::StrAppendFormat(&result,
"\nbest_bound: %.16g",
304 absl::StrAppend(&result,
"\nobjective: NA");
305 absl::StrAppend(&result,
"\nbest_bound: NA");
308 absl::StrAppend(&result,
"\nbooleans: ",
response.num_booleans());
309 absl::StrAppend(&result,
"\nconflicts: ",
response.num_conflicts());
310 absl::StrAppend(&result,
"\nbranches: ",
response.num_branches());
314 absl::StrAppend(&result,
315 "\npropagations: ",
response.num_binary_propagations());
317 &result,
"\ninteger_propagations: ",
response.num_integer_propagations());
319 absl::StrAppend(&result,
"\nrestarts: ",
response.num_restarts());
320 absl::StrAppend(&result,
"\nlp_iterations: ",
response.num_lp_iterations());
321 absl::StrAppend(&result,
"\nwalltime: ",
response.wall_time());
322 absl::StrAppend(&result,
"\nusertime: ",
response.user_time());
323 absl::StrAppend(&result,
324 "\ndeterministic_time: ",
response.deterministic_time());
325 absl::StrAppend(&result,
"\nprimal_integral: ",
response.primal_integral());
326 absl::StrAppend(&result,
"\n");
332 void FillSolutionInResponse(
const CpModelProto&
model_proto,
const Model&
model,
335 response->clear_solution_lower_bounds();
336 response->clear_solution_upper_bounds();
338 auto* mapping =
model.Get<CpModelMapping>();
340 auto* integer_trail =
model.Get<IntegerTrail>();
342 std::vector<int64_t> solution;
343 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
344 if (mapping->IsInteger(i)) {
345 const IntegerVariable
var = mapping->Integer(i);
346 if (integer_trail->IsCurrentlyIgnored(
var)) {
359 DCHECK(mapping->IsBoolean(i));
361 if (trail->Assignment().LiteralIsAssigned(
literal)) {
370 if (!solution.empty()) {
372 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
380 const auto& assignment = trail->Assignment();
381 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
382 if (mapping->IsBoolean(i)) {
383 if (assignment.VariableIsAssigned(mapping->Literal(i).Variable())) {
388 response->add_solution_lower_bounds(0);
389 response->add_solution_upper_bounds(1);
392 response->add_solution_lower_bounds(
394 response->add_solution_upper_bounds(
403 IntegerVariable GetOrCreateVariableWithTightBound(
404 const std::vector<std::pair<IntegerVariable, int64_t>>& terms,
407 if (terms.size() == 1 && terms.front().second == 1) {
408 return terms.front().first;
410 if (terms.size() == 1 && terms.front().second == -1) {
416 for (
const std::pair<IntegerVariable, int64_t> var_coeff : terms) {
419 const int64_t coeff = var_coeff.second;
420 const int64_t prod1 = min_domain * coeff;
421 const int64_t prod2 = max_domain * coeff;
428 IntegerVariable GetOrCreateVariableGreaterOrEqualToSumOf(
429 const std::vector<std::pair<IntegerVariable, int64_t>>& terms,
432 if (terms.size() == 1 && terms.front().second == 1) {
433 return terms.front().first;
435 if (terms.size() == 1 && terms.front().second == -1) {
440 const IntegerVariable new_var =
441 GetOrCreateVariableWithTightBound(terms,
model);
442 std::vector<IntegerVariable> vars;
443 std::vector<int64_t> coeffs;
444 for (
const auto& term : terms) {
445 vars.push_back(term.first);
446 coeffs.push_back(term.second);
448 vars.push_back(new_var);
449 coeffs.push_back(-1);
454 void TryToAddCutGenerators(
const CpModelProto&
model_proto,
455 const ConstraintProto&
ct, Model* m,
456 LinearRelaxation* relaxation) {
457 const int linearization_level =
458 m->GetOrCreate<SatParameters>()->linearization_level();
459 auto* mapping = m->GetOrCreate<CpModelMapping>();
460 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCircuit &&
461 linearization_level > 1) {
462 std::vector<int> tails(
ct.circuit().tails().begin(),
463 ct.circuit().tails().end());
464 std::vector<int> heads(
ct.circuit().heads().begin(),
465 ct.circuit().heads().end());
466 std::vector<Literal> literals = mapping->Literals(
ct.circuit().literals());
469 relaxation->cut_generators.push_back(
473 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kRoutes &&
474 linearization_level > 1) {
475 std::vector<int> tails(
ct.routes().tails().begin(),
476 ct.routes().tails().end());
477 std::vector<int> heads(
ct.routes().heads().begin(),
478 ct.routes().heads().end());
479 std::vector<Literal> literals = mapping->Literals(
ct.routes().literals());
482 for (
int i = 0; i <
ct.routes().tails_size(); ++i) {
483 num_nodes =
std::max(num_nodes, 1 +
ct.routes().tails(i));
484 num_nodes =
std::max(num_nodes, 1 +
ct.routes().heads(i));
486 if (
ct.routes().demands().empty() ||
ct.routes().capacity() == 0) {
487 relaxation->cut_generators.push_back(
491 const std::vector<int64_t> demands(
ct.routes().demands().begin(),
492 ct.routes().demands().end());
493 relaxation->cut_generators.push_back(
495 ct.routes().capacity(), m));
498 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kIntProd) {
500 if (
ct.int_prod().vars_size() != 2)
return;
504 IntegerVariable z = mapping->Integer(
ct.int_prod().target());
505 IntegerVariable x = mapping->Integer(
ct.int_prod().vars(0));
506 IntegerVariable y = mapping->Integer(
ct.int_prod().vars(1));
508 IntegerTrail*
const integer_trail = m->GetOrCreate<IntegerTrail>();
509 IntegerValue x_lb = integer_trail->LowerBound(x);
510 IntegerValue x_ub = integer_trail->UpperBound(x);
511 IntegerValue y_lb = integer_trail->LowerBound(y);
512 IntegerValue y_ub = integer_trail->UpperBound(y);
516 if (x_lb < 0 && x_ub > 0)
return;
526 if (x_lb < 0 && x_ub > 0)
return;
527 if (y_lb < 0 && y_ub > 0)
return;
540 relaxation->cut_generators.push_back(
544 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kAllDiff) {
545 if (linearization_level < 2)
return;
547 const int num_vars =
ct.all_diff().vars_size();
548 if (num_vars <= m->GetOrCreate<SatParameters>()->max_all_diff_cut_size()) {
549 std::vector<IntegerVariable> vars =
550 mapping->Integers(
ct.all_diff().vars());
551 relaxation->cut_generators.push_back(
556 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCumulative) {
557 if (linearization_level < 2)
return;
560 std::vector<IntegerVariable> demands =
561 mapping->Integers(
ct.cumulative().demands());
562 std::vector<IntervalVariable> intervals =
563 mapping->Intervals(
ct.cumulative().intervals());
565 mapping->Integer(
ct.cumulative().capacity());
566 relaxation->cut_generators.push_back(
569 relaxation->cut_generators.push_back(
573 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kNoOverlap) {
574 if (linearization_level < 2)
return;
576 std::vector<IntervalVariable> intervals =
577 mapping->Intervals(
ct.no_overlap().intervals());
578 relaxation->cut_generators.push_back(
580 relaxation->cut_generators.push_back(
582 relaxation->cut_generators.push_back(
586 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinMax) {
587 if (!m->GetOrCreate<SatParameters>()->add_lin_max_cuts())
return;
591 if (
ct.lin_max().target().vars_size() != 1)
return;
592 if (
ct.lin_max().target().coeffs(0) != 1)
return;
594 const IntegerVariable target =
595 mapping->Integer(
ct.lin_max().target().vars(0));
596 std::vector<LinearExpression> exprs;
597 exprs.reserve(
ct.lin_max().exprs_size());
598 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
607 const std::vector<IntegerVariable> z_vars =
610 if (linearization_level >= 2) {
611 relaxation->cut_generators.push_back(
619 LinearRelaxation ComputeLinearRelaxation(
const CpModelProto&
model_proto,
620 int linearization_level, Model* m) {
621 LinearRelaxation relaxation;
624 absl::flat_hash_set<int> used_integer_variable;
626 auto* mapping = m->GetOrCreate<CpModelMapping>();
627 auto* encoder = m->GetOrCreate<IntegerEncoder>();
628 auto* trail = m->GetOrCreate<Trail>();
631 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kCircuit) {
632 for (
const int ref :
ct.circuit().literals()) {
633 const Literal l = mapping->Literal(ref);
634 if (!encoder->LiteralOrNegationHasView(l)) {
647 for (
const int literal_ref : refs.literals) {
649 if (trail->Assignment().LiteralIsAssigned(
literal)) {
652 }
else if (!encoder->LiteralOrNegationHasView(
literal)) {
665 int num_full_encoding_relaxations = 0;
666 int num_partial_encoding_relaxations = 0;
667 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
668 if (mapping->IsBoolean(i))
continue;
670 const IntegerVariable
var = mapping->Integer(i);
681 if (encoder->VariableIsFullyEncoded(
var)) {
683 ++num_full_encoding_relaxations;
694 const int old = relaxation.linear_constraints.size();
696 if (relaxation.linear_constraints.size() > old) {
697 ++num_partial_encoding_relaxations;
701 if (!m->GetOrCreate<SatSolver>()->FinishPropagation())
return relaxation;
705 m->GetOrCreate<BinaryImplicationGraph>()->TransformIntoMaxCliques(
706 &relaxation.at_most_ones);
707 for (
const std::vector<Literal>& at_most_one : relaxation.at_most_ones) {
708 if (at_most_one.empty())
continue;
711 for (
const Literal
literal : at_most_one) {
714 const bool unused ABSL_ATTRIBUTE_UNUSED =
715 lc.AddLiteralTerm(
literal, IntegerValue(1));
717 relaxation.linear_constraints.push_back(lc.Build());
722 relaxation.at_most_ones.clear();
727 for (
int i = 0; i < relaxation.linear_constraints.size(); ++i) {
728 if (relaxation.linear_constraints[i].vars.size() <= 1)
continue;
729 std::swap(relaxation.linear_constraints[new_size++],
730 relaxation.linear_constraints[i]);
732 relaxation.linear_constraints.resize(new_size);
735 VLOG(3) <<
"num_full_encoding_relaxations: " << num_full_encoding_relaxations;
736 VLOG(3) <<
"num_partial_encoding_relaxations: "
737 << num_partial_encoding_relaxations;
738 VLOG(3) << relaxation.linear_constraints.size()
739 <<
" constraints in the LP relaxation.";
740 VLOG(3) << relaxation.cut_generators.size() <<
" cuts generators.";
745 IntegerVariable AddLPConstraints(
const CpModelProto&
model_proto,
746 int linearization_level, Model* m) {
747 const LinearRelaxation relaxation =
748 ComputeLinearRelaxation(
model_proto, linearization_level, m);
756 const int num_lp_constraints = relaxation.linear_constraints.size();
757 const int num_lp_cut_generators = relaxation.cut_generators.size();
758 const int num_integer_variables =
759 m->GetOrCreate<IntegerTrail>()->NumIntegerVariables().value();
762 num_integer_variables);
763 auto get_constraint_index = [](
int ct_index) {
return ct_index; };
764 auto get_cut_generator_index = [num_lp_constraints](
int cut_index) {
765 return num_lp_constraints + cut_index;
767 auto get_var_index = [num_lp_constraints,
768 num_lp_cut_generators](IntegerVariable
var) {
769 return num_lp_constraints + num_lp_cut_generators +
var.value();
771 for (
int i = 0; i < num_lp_constraints; i++) {
772 for (
const IntegerVariable
var : relaxation.linear_constraints[i].vars) {
773 components.
AddEdge(get_constraint_index(i), get_var_index(
var));
776 for (
int i = 0; i < num_lp_cut_generators; ++i) {
777 for (
const IntegerVariable
var : relaxation.cut_generators[i].vars) {
778 components.
AddEdge(get_cut_generator_index(i), get_var_index(
var));
786 for (
const std::vector<Literal>& at_most_one : relaxation.at_most_ones) {
788 for (
const Literal
literal : at_most_one) {
791 const bool unused ABSL_ATTRIBUTE_UNUSED =
792 builder.AddLiteralTerm(
literal, IntegerValue(1));
794 LinearConstraint lc = builder.Build();
795 for (
int i = 1; i < lc.vars.size(); ++i) {
796 components.
AddEdge(get_var_index(lc.vars[0]), get_var_index(lc.vars[i]));
801 std::vector<int> component_sizes(num_components, 0);
802 const std::vector<int> index_to_component = components.
GetComponentIds();
803 for (
int i = 0; i < num_lp_constraints; i++) {
804 ++component_sizes[index_to_component[get_constraint_index(i)]];
806 for (
int i = 0; i < num_lp_cut_generators; i++) {
807 ++component_sizes[index_to_component[get_cut_generator_index(i)]];
815 auto* mapping = m->GetOrCreate<CpModelMapping>();
816 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
817 const IntegerVariable
var =
819 ++component_sizes[index_to_component[get_var_index(
var)]];
823 std::vector<LinearProgrammingConstraint*> lp_constraints(num_components,
825 std::vector<std::vector<LinearConstraint>> component_to_constraints(
827 for (
int i = 0; i < num_lp_constraints; i++) {
828 const int c = index_to_component[get_constraint_index(i)];
829 if (component_sizes[c] <= 1)
continue;
830 component_to_constraints[c].push_back(relaxation.linear_constraints[i]);
831 if (lp_constraints[c] ==
nullptr) {
832 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
835 lp_constraints[c]->AddLinearConstraint(relaxation.linear_constraints[i]);
839 for (
int i = 0; i < num_lp_cut_generators; i++) {
840 const int c = index_to_component[get_cut_generator_index(i)];
841 if (lp_constraints[c] ==
nullptr) {
842 lp_constraints[c] = m->Create<LinearProgrammingConstraint>();
844 lp_constraints[c]->AddCutGenerator(std::move(relaxation.cut_generators[i]));
848 const SatParameters& params = *(m->GetOrCreate<SatParameters>());
849 if (params.add_clique_cuts() && params.linearization_level() > 1) {
850 for (LinearProgrammingConstraint* lp : lp_constraints) {
851 if (lp ==
nullptr)
continue;
856 if (params.add_knapsack_cuts() && params.linearization_level() > 1) {
857 for (
int c = 0; c < num_components; ++c) {
858 if (component_to_constraints[c].empty())
continue;
860 component_to_constraints[c], lp_constraints[c]->integer_variables(),
866 std::vector<std::vector<std::pair<IntegerVariable, int64_t>>>
867 component_to_cp_terms(num_components);
868 std::vector<std::pair<IntegerVariable, int64_t>> top_level_cp_terms;
869 int num_components_containing_objective = 0;
873 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
874 const IntegerVariable
var =
876 const int64_t coeff =
model_proto.objective().coeffs(i);
877 const int c = index_to_component[get_var_index(
var)];
878 if (lp_constraints[c] !=
nullptr) {
879 lp_constraints[c]->SetObjectiveCoefficient(
var, IntegerValue(coeff));
880 component_to_cp_terms[c].push_back(std::make_pair(
var, coeff));
883 top_level_cp_terms.push_back(std::make_pair(
var, coeff));
887 for (
int c = 0; c < num_components; ++c) {
888 if (component_to_cp_terms[c].empty())
continue;
889 const IntegerVariable sub_obj_var =
890 GetOrCreateVariableGreaterOrEqualToSumOf(component_to_cp_terms[c], m);
891 top_level_cp_terms.push_back(std::make_pair(sub_obj_var, 1));
892 lp_constraints[c]->SetMainObjectiveVariable(sub_obj_var);
893 num_components_containing_objective++;
897 const IntegerVariable main_objective_var =
899 ? GetOrCreateVariableGreaterOrEqualToSumOf(top_level_cp_terms, m)
904 for (LinearProgrammingConstraint* lp_constraint : lp_constraints) {
905 if (lp_constraint ==
nullptr)
continue;
906 lp_constraint->RegisterWith(m);
907 VLOG(3) <<
"LP constraint: " << lp_constraint->DimensionString() <<
".";
910 VLOG(3) << top_level_cp_terms.size()
911 <<
" terms in the main objective linear equation ("
912 << num_components_containing_objective <<
" from LP constraints).";
913 return main_objective_var;
925 const std::function<
void(
const CpSolverResponse&
response)>& observer) {
931 #if !defined(__PORTABLE_PLATFORM__)
934 const std::string& params) {
936 if (!params.empty()) {
937 CHECK(google::protobuf::TextFormat::ParseFromString(params, &
parameters))
964 void RegisterVariableBoundsLevelZeroExport(
965 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
967 CHECK(shared_bounds_manager !=
nullptr);
968 int saved_trail_index = 0;
969 auto broadcast_level_zero_bounds =
971 const std::vector<IntegerVariable>& modified_vars)
mutable {
972 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
974 std::vector<int> model_variables;
975 std::vector<int64_t> new_lower_bounds;
976 std::vector<int64_t> new_upper_bounds;
977 absl::flat_hash_set<int> visited_variables;
980 auto* integer_trail =
model->Get<IntegerTrail>();
981 for (
const IntegerVariable&
var : modified_vars) {
983 const int model_var =
984 mapping->GetProtoVariableFromIntegerVariable(positive_var);
985 if (model_var == -1 || visited_variables.contains(model_var)) {
992 visited_variables.insert(model_var);
993 const int64_t new_lb =
994 integer_trail->LevelZeroLowerBound(positive_var).value();
995 const int64_t new_ub =
996 integer_trail->LevelZeroUpperBound(positive_var).value();
999 model_variables.push_back(model_var);
1000 new_lower_bounds.push_back(new_lb);
1001 new_upper_bounds.push_back(new_ub);
1005 auto* trail =
model->Get<Trail>();
1006 for (; saved_trail_index < trail->Index(); ++saved_trail_index) {
1007 const Literal fixed_literal = (*trail)[saved_trail_index];
1008 const int model_var = mapping->GetProtoVariableFromBooleanVariable(
1009 fixed_literal.Variable());
1010 if (model_var == -1 || visited_variables.contains(model_var)) {
1017 visited_variables.insert(model_var);
1018 model_variables.push_back(model_var);
1019 if (fixed_literal.IsPositive()) {
1020 new_lower_bounds.push_back(1);
1021 new_upper_bounds.push_back(1);
1023 new_lower_bounds.push_back(0);
1024 new_upper_bounds.push_back(0);
1028 if (!model_variables.empty()) {
1029 shared_bounds_manager->ReportPotentialNewBounds(
1034 if (!
model->Get<SatParameters>()->interleave_search()) {
1035 shared_bounds_manager->Synchronize();
1047 const IntegerVariable num_vars =
1048 model->GetOrCreate<IntegerTrail>()->NumIntegerVariables();
1049 std::vector<IntegerVariable> all_variables;
1050 all_variables.reserve(num_vars.value());
1051 for (IntegerVariable
var(0);
var < num_vars; ++
var) {
1052 all_variables.push_back(
var);
1054 broadcast_level_zero_bounds(all_variables);
1056 model->GetOrCreate<GenericLiteralWatcher>()
1057 ->RegisterLevelZeroModifiedVariablesCallback(broadcast_level_zero_bounds);
1063 void RegisterVariableBoundsLevelZeroImport(
1064 const CpModelProto&
model_proto, SharedBoundsManager* shared_bounds_manager,
1066 CHECK(shared_bounds_manager !=
nullptr);
1067 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1068 CpModelMapping*
const mapping =
model->GetOrCreate<CpModelMapping>();
1069 const int id = shared_bounds_manager->RegisterNewId();
1071 const auto& import_level_zero_bounds = [&
model_proto, shared_bounds_manager,
1072 model, integer_trail, id, mapping]() {
1073 std::vector<int> model_variables;
1074 std::vector<int64_t> new_lower_bounds;
1075 std::vector<int64_t> new_upper_bounds;
1076 shared_bounds_manager->GetChangedBounds(
1077 id, &model_variables, &new_lower_bounds, &new_upper_bounds);
1078 bool new_bounds_have_been_imported =
false;
1079 for (
int i = 0; i < model_variables.size(); ++i) {
1080 const int model_var = model_variables[i];
1083 if (!mapping->IsInteger(model_var))
continue;
1084 const IntegerVariable
var = mapping->Integer(model_var);
1085 const IntegerValue new_lb(new_lower_bounds[i]);
1086 const IntegerValue new_ub(new_upper_bounds[i]);
1087 const IntegerValue old_lb = integer_trail->LowerBound(
var);
1088 const IntegerValue old_ub = integer_trail->UpperBound(
var);
1089 const bool changed_lb = new_lb > old_lb;
1090 const bool changed_ub = new_ub < old_ub;
1091 if (!changed_lb && !changed_ub)
continue;
1093 new_bounds_have_been_imported =
true;
1095 const IntegerVariableProto& var_proto =
1097 const std::string& var_name =
1098 var_proto.name().empty()
1099 ? absl::StrCat(
"anonymous_var(", model_var,
")")
1101 LOG(
INFO) <<
" '" <<
model->Name() <<
"' imports new bounds for "
1102 << var_name <<
": from [" << old_lb <<
", " << old_ub
1103 <<
"] to [" << new_lb <<
", " << new_ub <<
"]";
1117 if (new_bounds_have_been_imported &&
1118 !
model->GetOrCreate<SatSolver>()->FinishPropagation()) {
1123 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
1124 import_level_zero_bounds);
1129 void RegisterObjectiveBestBoundExport(
1130 IntegerVariable objective_var,
1131 SharedResponseManager* shared_response_manager, Model*
model) {
1132 auto* integer_trail =
model->Get<IntegerTrail>();
1133 const auto broadcast_objective_lower_bound =
1134 [objective_var, integer_trail, shared_response_manager,
1135 model](
const std::vector<IntegerVariable>& unused) {
1136 shared_response_manager->UpdateInnerObjectiveBounds(
1137 model->Name(), integer_trail->LevelZeroLowerBound(objective_var),
1138 integer_trail->LevelZeroUpperBound(objective_var));
1140 if (!
model->Get<SatParameters>()->interleave_search()) {
1141 shared_response_manager->Synchronize();
1144 model->GetOrCreate<GenericLiteralWatcher>()
1145 ->RegisterLevelZeroModifiedVariablesCallback(
1146 broadcast_objective_lower_bound);
1152 void RegisterObjectiveBoundsImport(
1153 SharedResponseManager* shared_response_manager, Model*
model) {
1154 auto* solver =
model->GetOrCreate<SatSolver>();
1155 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1156 auto* objective =
model->GetOrCreate<ObjectiveDefinition>();
1158 const auto import_objective_bounds = [
name, solver, integer_trail, objective,
1159 shared_response_manager]() {
1160 if (solver->AssumptionLevel() != 0)
return true;
1161 bool propagate =
false;
1163 const IntegerValue external_lb =
1164 shared_response_manager->SynchronizedInnerObjectiveLowerBound();
1165 const IntegerValue current_lb =
1166 integer_trail->LowerBound(objective->objective_var);
1167 if (external_lb > current_lb) {
1169 objective->objective_var, external_lb),
1176 const IntegerValue external_ub =
1177 shared_response_manager->SynchronizedInnerObjectiveUpperBound();
1178 const IntegerValue current_ub =
1179 integer_trail->UpperBound(objective->objective_var);
1180 if (external_ub < current_ub) {
1182 objective->objective_var, external_ub),
1189 if (!propagate)
return true;
1191 VLOG(2) <<
"'" <<
name <<
"' imports objective bounds: external ["
1192 << objective->ScaleIntegerObjective(external_lb) <<
", "
1193 << objective->ScaleIntegerObjective(external_ub) <<
"], current ["
1194 << objective->ScaleIntegerObjective(current_lb) <<
", "
1195 << objective->ScaleIntegerObjective(current_ub) <<
"]";
1197 return solver->FinishPropagation();
1200 model->GetOrCreate<LevelZeroCallbackHelper>()->callbacks.push_back(
1201 import_objective_bounds);
1205 auto* shared_response_manager =
model->Mutable<SharedResponseManager>();
1206 CHECK(shared_response_manager !=
nullptr);
1207 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1210 const auto unsat = [shared_response_manager, sat_solver,
model] {
1211 sat_solver->NotifyThatModelIsUnsat();
1212 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1213 absl::StrCat(
model->Name(),
" [loading]"));
1217 model->GetOrCreate<IntegerEncoder>()->DisableImplicationBetweenLiteral();
1219 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1220 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1221 const bool view_all_booleans_as_integers =
1223 (
parameters.search_branching() == SatParameters::FIXED_SEARCH &&
1225 mapping->CreateVariables(
model_proto, view_all_booleans_as_integers,
model);
1240 if (sat_solver->IsModelUnsat())
return unsat();
1246 std::set<std::string> unsupported_types;
1247 int num_ignored_constraints = 0;
1248 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1249 if (mapping->ConstraintIsAlreadyLoaded(&
ct)) {
1250 ++num_ignored_constraints;
1265 if (sat_solver->FinishPropagation()) {
1266 Trail* trail =
model->GetOrCreate<Trail>();
1267 const int old_num_fixed = trail->Index();
1268 if (trail->Index() > old_num_fixed) {
1269 VLOG(3) <<
"Constraint fixed " << trail->Index() - old_num_fixed
1274 if (sat_solver->IsModelUnsat()) {
1275 VLOG(2) <<
"UNSAT during extraction (after adding '"
1281 if (num_ignored_constraints > 0) {
1282 VLOG(3) << num_ignored_constraints <<
" constraints were skipped.";
1284 if (!unsupported_types.empty()) {
1285 VLOG(1) <<
"There is unsupported constraints types in this model: ";
1286 for (
const std::string& type : unsupported_types) {
1287 VLOG(1) <<
" - " << type;
1292 model->GetOrCreate<IntegerEncoder>()
1293 ->AddAllImplicationsBetweenAssociatedLiterals();
1294 if (!sat_solver->FinishPropagation())
return unsat();
1300 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1301 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1302 if (
parameters.linearization_level() == 0)
return;
1305 const LinearRelaxation relaxation = ComputeLinearRelaxation(
1307 const int num_lp_constraints = relaxation.linear_constraints.size();
1308 if (num_lp_constraints == 0)
return;
1309 auto* feasibility_pump =
model->GetOrCreate<FeasibilityPump>();
1310 for (
int i = 0; i < num_lp_constraints; i++) {
1311 feasibility_pump->AddLinearConstraint(relaxation.linear_constraints[i]);
1315 for (
int i = 0; i <
model_proto.objective().coeffs_size(); ++i) {
1316 const IntegerVariable
var =
1317 mapping->Integer(
model_proto.objective().vars(i));
1318 const int64_t coeff =
model_proto.objective().coeffs(i);
1319 feasibility_pump->SetObjectiveCoefficient(
var, IntegerValue(coeff));
1329 auto* shared_response_manager =
model->Mutable<SharedResponseManager>();
1330 CHECK(shared_response_manager !=
nullptr);
1335 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1336 const auto unsat = [shared_response_manager, sat_solver,
model] {
1337 sat_solver->NotifyThatModelIsUnsat();
1338 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1339 absl::StrCat(
model->Name(),
" [loading]"));
1342 auto* mapping =
model->GetOrCreate<CpModelMapping>();
1343 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
1349 if (
model->Mutable<PrecedencesPropagator>() !=
nullptr &&
1350 parameters.auto_detect_greater_than_at_least_one_of()) {
1351 model->Mutable<PrecedencesPropagator>()
1352 ->AddGreaterThanAtLeastOneOfConstraints(
model);
1353 if (!sat_solver->FinishPropagation())
return unsat();
1359 if (
parameters.cp_model_probing_level() > 1) {
1360 Prober* prober =
model->GetOrCreate<Prober>();
1361 prober->ProbeBooleanVariables(1.0);
1362 if (
model->GetOrCreate<SatSolver>()->IsModelUnsat()) {
1365 if (!
model->GetOrCreate<BinaryImplicationGraph>()
1366 ->ComputeTransitiveReduction()) {
1379 const CpObjectiveProto& obj =
model_proto.objective();
1380 std::vector<std::pair<IntegerVariable, int64_t>> terms;
1381 terms.reserve(obj.vars_size());
1382 for (
int i = 0; i < obj.vars_size(); ++i) {
1384 std::make_pair(mapping->Integer(obj.vars(i)), obj.coeffs(i)));
1387 objective_var = GetOrCreateVariableWithTightBound(terms,
model);
1389 objective_var = GetOrCreateVariableGreaterOrEqualToSumOf(terms,
model);
1396 const CpObjectiveProto& objective_proto =
model_proto.objective();
1397 auto* objective_definition =
model->GetOrCreate<ObjectiveDefinition>();
1399 objective_definition->scaling_factor = objective_proto.scaling_factor();
1400 if (objective_definition->scaling_factor == 0.0) {
1401 objective_definition->scaling_factor = 1.0;
1403 objective_definition->offset = objective_proto.offset();
1404 objective_definition->objective_var = objective_var;
1406 const int size = objective_proto.vars_size();
1407 objective_definition->vars.resize(size);
1408 objective_definition->coeffs.resize(size);
1409 for (
int i = 0; i < objective_proto.vars_size(); ++i) {
1412 objective_definition->vars[i] = mapping->Integer(objective_proto.vars(i));
1413 objective_definition->coeffs[i] = IntegerValue(objective_proto.coeffs(i));
1416 const int ref = objective_proto.vars(i);
1417 if (mapping->IsInteger(ref)) {
1418 const IntegerVariable
var = mapping->Integer(objective_proto.vars(i));
1419 objective_definition->objective_impacting_variables.insert(
1425 model->TakeOwnership(
1426 new LevelZeroEquality(objective_var, objective_definition->vars,
1427 objective_definition->coeffs,
model));
1433 const Domain automatic_domain =
1434 model->GetOrCreate<IntegerTrail>()->InitialVariableDomain(
1437 <<
" scaling_factor:" <<
model_proto.objective().scaling_factor();
1438 VLOG(3) <<
"Automatic internal objective domain: " << automatic_domain;
1439 VLOG(3) <<
"User specified internal objective domain: " << user_domain;
1441 const bool ok =
model->GetOrCreate<IntegerTrail>()->UpdateInitialDomain(
1442 objective_var, user_domain);
1444 VLOG(2) <<
"UNSAT due to the objective domain.";
1455 if (!automatic_domain.IsIncludedIn(user_domain)) {
1456 std::vector<IntegerVariable> vars;
1457 std::vector<int64_t> coeffs;
1458 const CpObjectiveProto& obj =
model_proto.objective();
1459 for (
int i = 0; i < obj.vars_size(); ++i) {
1460 vars.push_back(mapping->Integer(obj.vars(i)));
1461 coeffs.push_back(obj.coeffs(i));
1463 vars.push_back(objective_var);
1464 coeffs.push_back(-1);
1472 "Initial num_bool: ", sat_solver->NumVariables());
1473 if (!sat_solver->FinishPropagation())
return unsat();
1477 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1478 shared_response_manager->UpdateInnerObjectiveBounds(
1479 absl::StrCat(
model->Name(),
" initial_propagation"),
1480 integer_trail->LowerBound(objective_var),
1481 integer_trail->UpperBound(objective_var));
1484 RegisterObjectiveBestBoundExport(objective_var, shared_response_manager,
1490 if (
model->GetOrCreate<SatParameters>()->share_objective_bounds()) {
1491 RegisterObjectiveBoundsImport(shared_response_manager,
model);
1497 auto* integer_trail =
model->GetOrCreate<IntegerTrail>();
1498 auto* lp_dispatcher =
model->GetOrCreate<LinearProgrammingDispatcher>();
1499 auto* lp_vars =
model->GetOrCreate<LPVariables>();
1500 IntegerVariable size = integer_trail->NumIntegerVariables();
1501 for (IntegerVariable positive_var(0); positive_var < size;
1502 positive_var += 2) {
1504 lp_var.positive_var = positive_var;
1506 mapping->GetProtoVariableFromIntegerVariable(positive_var);
1509 if (lp_var.model_var >= 0) {
1510 lp_vars->vars.push_back(lp_var);
1511 lp_vars->model_vars_size =
1512 std::max(lp_vars->model_vars_size, lp_var.model_var + 1);
1517 auto* search_heuristics =
model->GetOrCreate<SearchHeuristics>();
1521 search_heuristics->fixed_search =
1523 search_heuristics->fixed_search,
model);
1527 std::vector<BooleanOrIntegerVariable> vars;
1528 std::vector<IntegerValue> values;
1529 for (
int i = 0; i <
model_proto.solution_hint().vars_size(); ++i) {
1530 const int ref =
model_proto.solution_hint().vars(i);
1532 BooleanOrIntegerVariable
var;
1533 if (mapping->IsBoolean(ref)) {
1534 var.bool_var = mapping->Literal(ref).Variable();
1536 var.int_var = mapping->Integer(ref);
1538 vars.push_back(
var);
1539 values.push_back(IntegerValue(
model_proto.solution_hint().values(i)));
1547 const std::string solution_info =
model->Name();
1549 shared_response_manager]() {
1552 response.set_solution_info(solution_info);
1556 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1557 CoreBasedOptimizer* core =
1558 new CoreBasedOptimizer(objective_var, objective.vars, objective.coeffs,
1559 solution_observer,
model);
1560 model->Register<CoreBasedOptimizer>(core);
1561 model->TakeOwnership(core);
1572 auto* shared_response_manager =
model->Mutable<SharedResponseManager>();
1573 if (shared_response_manager->ProblemIsSolved())
return;
1575 const std::string& solution_info =
model->Name();
1577 &shared_response_manager]() {
1580 response.set_solution_info(solution_info);
1587 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1589 const SatParameters&
parameters = *
model->GetOrCreate<SatParameters>();
1591 std::vector<BooleanVariable> bool_vars;
1592 std::vector<IntegerVariable> int_vars;
1593 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1594 absl::flat_hash_set<BooleanVariable> visited;
1595 for (
int v = 0; v <
model_proto.variables_size(); ++v) {
1596 if (mapping.IsBoolean(v)) {
1597 const BooleanVariable bool_var = mapping.Literal(v).Variable();
1598 if (!visited.contains(bool_var)) {
1599 visited.insert(bool_var);
1600 bool_vars.push_back(bool_var);
1603 IntegerVariable
var = mapping.Integer(v);
1604 if (integer_trail->IsFixed(
var))
continue;
1605 int_vars.push_back(
var);
1614 solution_observer();
1615 if (!
parameters.enumerate_all_solutions())
break;
1619 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1623 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1628 auto* sat_solver =
model->GetOrCreate<SatSolver>();
1629 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1631 std::vector<int> core_in_proto_format;
1632 for (
const Literal l : core) {
1633 core_in_proto_format.push_back(
1634 mapping.GetProtoVariableFromBooleanVariable(l.Variable()));
1635 if (!l.IsPositive()) {
1636 core_in_proto_format.back() =
NegatedRef(core_in_proto_format.back());
1639 shared_response_manager->AddUnsatCore(core_in_proto_format);
1643 const auto& objective = *
model->GetOrCreate<ObjectiveDefinition>();
1644 const IntegerVariable objective_var = objective.objective_var;
1653 objective, solution_observer,
model);
1655 status =
model->Mutable<CoreBasedOptimizer>()->Optimize();
1660 if (
parameters.binary_search_num_conflicts() >= 0) {
1662 solution_observer,
model);
1665 objective_var, solution_observer,
model);
1673 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1680 shared_response_manager->SetStatsFromModel(
model);
1688 auto* shared_response_manager =
model->Mutable<SharedResponseManager>();
1689 if (shared_response_manager->ProblemIsSolved())
return;
1693 const SatParameters saved_params = *
parameters;
1695 parameters->set_search_branching(SatParameters::HINT_SEARCH);
1702 const auto& mapping = *
model->GetOrCreate<CpModelMapping>();
1706 const std::string& solution_info =
model->Name();
1710 response.set_solution_info(absl::StrCat(solution_info,
" [hint]"));
1719 const IntegerVariable objective_var =
1720 model->GetOrCreate<ObjectiveDefinition>()->objective_var;
1721 model->GetOrCreate<SatSolver>()->Backtrack(0);
1722 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
1723 if (!integer_trail->Enqueue(
1726 shared_response_manager->GetInnerObjectiveUpperBound()),
1728 shared_response_manager->NotifyThatImprovingProblemIsInfeasible(
1729 absl::StrCat(solution_info,
" [hint]"));
1730 shared_response_manager->SetStatsFromModel(
model);
1740 void MinimizeL1DistanceWithHint(
const CpModelProto&
model_proto,
1742 SharedTimeLimit* shared_time_limit,
1748 auto* shared_response_manager =
model->Mutable<SharedResponseManager>();
1749 if (shared_response_manager->ProblemIsSolved())
return;
1751 auto*
parameters = local_model.GetOrCreate<SatParameters>();
1755 if (
parameters->enumerate_all_solutions())
return;
1758 const SatParameters saved_params = *
model->GetOrCreate<SatParameters>();
1765 updated_model_proto.clear_objective();
1768 for (
int i = 0; i <
model_proto.solution_hint().vars_size(); ++i) {
1773 const int new_var_index = updated_model_proto.variables_size();
1774 IntegerVariableProto* var_proto = updated_model_proto.add_variables();
1776 const int64_t max_domain =
1780 var_proto->add_domain(min_domain);
1781 var_proto->add_domain(max_domain);
1784 ConstraintProto*
const linear_constraint_proto =
1785 updated_model_proto.add_constraints();
1786 LinearConstraintProto* linear = linear_constraint_proto->mutable_linear();
1787 linear->add_vars(new_var_index);
1788 linear->add_coeffs(1);
1789 linear->add_vars(
var);
1790 linear->add_coeffs(-1);
1791 linear->add_domain(-
value);
1792 linear->add_domain(-
value);
1795 const int abs_var_index = updated_model_proto.variables_size();
1796 IntegerVariableProto* abs_var_proto = updated_model_proto.add_variables();
1797 const int64_t abs_min_domain = 0;
1798 const int64_t abs_max_domain =
1799 std::max(std::abs(min_domain), std::abs(max_domain));
1800 abs_var_proto->add_domain(abs_min_domain);
1801 abs_var_proto->add_domain(abs_max_domain);
1802 ConstraintProto*
const abs_constraint_proto =
1803 updated_model_proto.add_constraints();
1804 abs_constraint_proto->mutable_int_max()->set_target(abs_var_index);
1805 abs_constraint_proto->mutable_int_max()->add_vars(new_var_index);
1806 abs_constraint_proto->mutable_int_max()->add_vars(
1809 updated_model_proto.mutable_objective()->add_vars(abs_var_index);
1810 updated_model_proto.mutable_objective()->add_coeffs(1);
1813 SharedResponseManager local_response_manager(
1815 shared_time_limit,
model->GetOrCreate<SolverLogger>());
1817 local_model.Register<SharedResponseManager>(&local_response_manager);
1820 LoadCpModel(updated_model_proto, &local_model);
1823 const auto& mapping = *local_model.GetOrCreate<CpModelMapping>();
1825 mapping.Literals(updated_model_proto.assumptions()), &local_model);
1827 const std::string& solution_info =
model->Name();
1832 CpSolverResponse updated_response;
1833 FillSolutionInResponse(updated_model_proto, local_model,
1835 LOG(
INFO) <<
"Found solution with repaired hint penalty = "
1839 response.set_solution_info(absl::StrCat(solution_info,
" [repaired]"));
1848 void PostsolveResponseWithFullSolver(
1849 const int64_t num_variables_in_original_model, CpModelProto mapping_proto,
1858 if (mapping_proto.variables_size() == 0) {
1863 for (
int i = 0; i <
response->solution_size(); ++i) {
1864 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1865 var_proto->clear_domain();
1866 var_proto->add_domain(
response->solution(i));
1867 var_proto->add_domain(
response->solution(i));
1869 for (
int i = 0; i <
response->solution_lower_bounds_size(); ++i) {
1870 auto* var_proto = mapping_proto.mutable_variables(postsolve_mapping[i]);
1873 .IntersectionWith({
response->solution_lower_bounds(i),
1874 response->solution_upper_bounds(i)}),
1881 Model postsolve_model;
1883 SatParameters& params = *postsolve_model.GetOrCreate<SatParameters>();
1884 params.set_linearization_level(0);
1885 params.set_cp_model_probing_level(0);
1889 SharedTimeLimit shared_time_limit(
time_limit.get());
1890 SharedResponseManager local_response_manager(
1892 &shared_time_limit, postsolve_model.GetOrCreate<SolverLogger>());
1893 postsolve_model.Register(&local_response_manager);
1894 LoadCpModel(mapping_proto, &postsolve_model);
1895 SolveLoadedCpModel(mapping_proto, &postsolve_model);
1896 const CpSolverResponse postsolve_response =
1897 local_response_manager.GetResponse();
1903 response->clear_solution_lower_bounds();
1904 response->clear_solution_upper_bounds();
1905 if (!postsolve_response.solution().empty()) {
1906 for (
int i = 0; i < num_variables_in_original_model; ++i) {
1907 response->add_solution(postsolve_response.solution(i));
1910 for (
int i = 0; i < num_variables_in_original_model; ++i) {
1911 response->add_solution_lower_bounds(
1912 postsolve_response.solution_lower_bounds(i));
1913 response->add_solution_upper_bounds(
1914 postsolve_response.solution_upper_bounds(i));
1919 void PostsolveResponseWrapper(
const SatParameters& params,
1920 const int64_t num_variables_in_original_model,
1921 const CpModelProto& mapping_proto,
1922 const std::vector<int>& postsolve_mapping,
1925 if (params.cp_model_postsolve_with_full_solver()) {
1926 PostsolveResponseWithFullSolver(num_variables_in_original_model,
1927 mapping_proto, postsolve_mapping,
1936 CpSolverResponse SolvePureSatModel(
const CpModelProto&
model_proto,
1938 SolverLogger* logger) {
1939 std::unique_ptr<SatSolver> solver(
new SatSolver());
1942 model->GetOrCreate<TimeLimit>()->ResetLimitFromParameters(
parameters);
1945 std::unique_ptr<DratProofHandler> drat_proof_handler;
1946 #if !defined(__PORTABLE_PLATFORM__)
1947 if (!absl::GetFlag(FLAGS_drat_output).empty() ||
1948 absl::GetFlag(FLAGS_drat_check)) {
1949 if (!absl::GetFlag(FLAGS_drat_output).empty()) {
1953 drat_proof_handler = absl::make_unique<DratProofHandler>(
1954 false, output, absl::GetFlag(FLAGS_drat_check));
1956 drat_proof_handler = absl::make_unique<DratProofHandler>();
1958 solver->SetDratProofHandler(drat_proof_handler.get());
1962 auto get_literal = [](
int ref) {
1963 if (ref >= 0)
return Literal(BooleanVariable(ref),
true);
1964 return Literal(BooleanVariable(
NegatedRef(ref)),
false);
1967 std::vector<Literal> temp;
1968 const int num_variables =
model_proto.variables_size();
1969 solver->SetNumVariables(num_variables);
1970 if (drat_proof_handler !=
nullptr) {
1971 drat_proof_handler->SetNumVariables(num_variables);
1975 for (
int ref = 0; ref < num_variables; ++ref) {
1977 if (domain.IsFixed()) {
1978 const Literal ref_literal =
1979 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
1980 drat_proof_handler->AddProblemClause({ref_literal});
1983 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
1984 switch (
ct.constraint_case()) {
1985 case ConstraintProto::ConstraintCase::kBoolAnd: {
1986 if (
ct.enforcement_literal_size() == 0) {
1987 for (
const int ref :
ct.bool_and().literals()) {
1988 drat_proof_handler->AddProblemClause({get_literal(ref)});
1992 const Literal not_a =
1993 get_literal(
ct.enforcement_literal(0)).Negated();
1994 for (
const int ref :
ct.bool_and().literals()) {
1995 drat_proof_handler->AddProblemClause({not_a, get_literal(ref)});
2000 case ConstraintProto::ConstraintCase::kBoolOr:
2002 for (
const int ref :
ct.bool_or().literals()) {
2003 temp.push_back(get_literal(ref));
2005 for (
const int ref :
ct.enforcement_literal()) {
2006 temp.push_back(get_literal(ref).Negated());
2008 drat_proof_handler->AddProblemClause(temp);
2016 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
2017 switch (
ct.constraint_case()) {
2018 case ConstraintProto::ConstraintCase::kBoolAnd: {
2019 if (
ct.enforcement_literal_size() == 0) {
2020 for (
const int ref :
ct.bool_and().literals()) {
2021 const Literal
b = get_literal(ref);
2022 solver->AddUnitClause(
b);
2026 const Literal not_a =
2027 get_literal(
ct.enforcement_literal(0)).Negated();
2028 for (
const int ref :
ct.bool_and().literals()) {
2029 const Literal
b = get_literal(ref);
2030 solver->AddProblemClause({not_a,
b});
2035 case ConstraintProto::ConstraintCase::kBoolOr:
2037 for (
const int ref :
ct.bool_or().literals()) {
2038 temp.push_back(get_literal(ref));
2040 for (
const int ref :
ct.enforcement_literal()) {
2041 temp.push_back(get_literal(ref).Negated());
2043 solver->AddProblemClause(temp);
2051 for (
int ref = 0; ref < num_variables; ++ref) {
2053 if (domain.Min() == domain.Max()) {
2054 const Literal ref_literal =
2055 domain.Min() == 0 ? get_literal(ref).Negated() : get_literal(ref);
2056 solver->AddUnitClause(ref_literal);
2063 std::vector<bool> solution;
2065 &solution, drat_proof_handler.get(), logger);
2068 for (
int ref = 0; ref < num_variables; ++ref) {
2069 response.add_solution(solution[ref]);
2073 status = solver->SolveWithTimeLimit(
model->GetOrCreate<TimeLimit>());
2076 for (
int ref = 0; ref < num_variables; ++ref) {
2078 solver->Assignment().LiteralIsTrue(get_literal(ref)) ? 1 : 0);
2085 model->GetOrCreate<TimeLimit>()->AdvanceDeterministicTime(
2086 solver->model()->GetOrCreate<TimeLimit>()->GetElapsedDeterministicTime());
2105 LOG(
FATAL) <<
"Unexpected SatSolver::Status " << status;
2107 response.set_num_booleans(solver->NumVariables());
2108 response.set_num_branches(solver->num_branches());
2109 response.set_num_conflicts(solver->num_failures());
2110 response.set_num_binary_propagations(solver->num_propagations());
2111 response.set_num_integer_propagations(0);
2114 model->Get<TimeLimit>()->GetElapsedDeterministicTime());
2120 absl::GetFlag(FLAGS_max_drat_time_in_seconds));
2121 switch (drat_status) {
2123 LOG(
INFO) <<
"DRAT status: UNKNOWN";
2126 LOG(
INFO) <<
"DRAT status: VALID";
2129 LOG(
ERROR) <<
"DRAT status: INVALID";
2135 LOG(
INFO) <<
"DRAT wall time: " << drat_timer.
Get();
2136 }
else if (drat_proof_handler !=
nullptr) {
2139 LOG(
INFO) <<
"DRAT status: NA";
2140 LOG(
INFO) <<
"DRAT wall time: NA";
2141 LOG(
INFO) <<
"DRAT user time: NA";
2146 #if !defined(__PORTABLE_PLATFORM__)
2149 struct SharedClasses {
2159 bool SearchIsDone() {
2160 if (
response->ProblemIsSolved())
return true;
2167 class FullProblemSolver :
public SubSolver {
2169 FullProblemSolver(
const std::string&
name,
2170 const SatParameters& local_parameters,
bool split_in_chunks,
2171 SharedClasses* shared)
2174 split_in_chunks_(split_in_chunks),
2175 local_model_(
absl::make_unique<Model>(
name)) {
2177 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
2178 shared_->time_limit->UpdateLocalLimit(
2179 local_model_->GetOrCreate<TimeLimit>());
2181 if (shared->response !=
nullptr) {
2182 local_model_->Register<SharedResponseManager>(shared->response);
2185 if (shared->relaxation_solutions !=
nullptr) {
2186 local_model_->Register<SharedRelaxationSolutionRepository>(
2187 shared->relaxation_solutions);
2190 if (shared->lp_solutions !=
nullptr) {
2191 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
2194 if (shared->incomplete_solutions !=
nullptr) {
2195 local_model_->Register<SharedIncompleteSolutionManager>(
2196 shared->incomplete_solutions);
2200 bool TaskIsAvailable()
override {
2201 if (shared_->SearchIsDone())
return false;
2203 absl::MutexLock mutex_lock(&mutex_);
2204 return previous_task_is_completed_;
2207 std::function<void()> GenerateTask(int64_t task_id)
override {
2209 absl::MutexLock mutex_lock(&mutex_);
2210 previous_task_is_completed_ =
false;
2213 if (solving_first_chunk_) {
2214 LoadCpModel(*shared_->model_proto, local_model_.get());
2220 if (shared_->bounds !=
nullptr) {
2221 RegisterVariableBoundsLevelZeroExport(
2222 *shared_->model_proto, shared_->bounds, local_model_.get());
2223 RegisterVariableBoundsLevelZeroImport(
2224 *shared_->model_proto, shared_->bounds, local_model_.get());
2227 if (local_model_->GetOrCreate<SatParameters>()->repair_hint()) {
2228 MinimizeL1DistanceWithHint(*shared_->model_proto, shared_->wall_timer,
2229 shared_->time_limit, local_model_.get());
2231 QuickSolveWithHint(*shared_->model_proto, local_model_.get());
2235 solving_first_chunk_ =
false;
2237 if (split_in_chunks_) {
2239 absl::MutexLock mutex_lock(&mutex_);
2240 previous_task_is_completed_ =
true;
2245 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2246 if (split_in_chunks_) {
2249 auto* params = local_model_->GetOrCreate<SatParameters>();
2250 params->set_max_deterministic_time(1);
2251 time_limit->ResetLimitFromParameters(*params);
2252 shared_->time_limit->UpdateLocalLimit(
time_limit);
2255 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2256 SolveLoadedCpModel(*shared_->model_proto, local_model_.get());
2258 absl::MutexLock mutex_lock(&mutex_);
2259 deterministic_time_since_last_synchronize_ +=
2260 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2264 if (shared_->SearchIsDone()) {
2265 shared_->time_limit->Stop();
2270 if (split_in_chunks_) {
2271 absl::MutexLock mutex_lock(&mutex_);
2272 previous_task_is_completed_ =
true;
2280 local_model_.reset();
2287 void Synchronize()
override {
2288 absl::MutexLock mutex_lock(&mutex_);
2289 deterministic_time_ += deterministic_time_since_last_synchronize_;
2290 shared_->time_limit->AdvanceDeterministicTime(
2291 deterministic_time_since_last_synchronize_);
2292 deterministic_time_since_last_synchronize_ = 0.0;
2296 SharedClasses* shared_;
2297 const bool split_in_chunks_;
2298 std::unique_ptr<Model> local_model_;
2302 bool solving_first_chunk_ =
true;
2305 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2307 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2310 class FeasibilityPumpSolver :
public SubSolver {
2312 FeasibilityPumpSolver(
const SatParameters& local_parameters,
2313 SharedClasses* shared)
2314 : SubSolver(
"feasibility_pump"),
2316 local_model_(
absl::make_unique<Model>(name_)) {
2318 *(local_model_->GetOrCreate<SatParameters>()) = local_parameters;
2319 shared_->time_limit->UpdateLocalLimit(
2320 local_model_->GetOrCreate<TimeLimit>());
2322 if (shared->response !=
nullptr) {
2323 local_model_->Register<SharedResponseManager>(shared->response);
2326 if (shared->relaxation_solutions !=
nullptr) {
2327 local_model_->Register<SharedRelaxationSolutionRepository>(
2328 shared->relaxation_solutions);
2331 if (shared->lp_solutions !=
nullptr) {
2332 local_model_->Register<SharedLPSolutionRepository>(shared->lp_solutions);
2335 if (shared->incomplete_solutions !=
nullptr) {
2336 local_model_->Register<SharedIncompleteSolutionManager>(
2337 shared->incomplete_solutions);
2341 if (shared_->bounds !=
nullptr) {
2342 RegisterVariableBoundsLevelZeroImport(
2343 *shared_->model_proto, shared_->bounds, local_model_.get());
2347 bool TaskIsAvailable()
override {
2348 if (shared_->SearchIsDone())
return false;
2349 absl::MutexLock mutex_lock(&mutex_);
2350 return previous_task_is_completed_;
2353 std::function<void()> GenerateTask(int64_t task_id)
override {
2356 absl::MutexLock mutex_lock(&mutex_);
2357 if (!previous_task_is_completed_)
return;
2358 previous_task_is_completed_ =
false;
2361 absl::MutexLock mutex_lock(&mutex_);
2362 if (solving_first_chunk_) {
2363 LoadFeasibilityPump(*shared_->model_proto, local_model_.get());
2366 if (local_model_->Get<FeasibilityPump>() ==
nullptr)
return;
2367 solving_first_chunk_ =
false;
2369 previous_task_is_completed_ =
true;
2374 auto*
time_limit = local_model_->GetOrCreate<TimeLimit>();
2375 const double saved_dtime =
time_limit->GetElapsedDeterministicTime();
2376 auto* feasibility_pump = local_model_->Mutable<FeasibilityPump>();
2377 if (!feasibility_pump->Solve()) {
2378 shared_->response->NotifyThatImprovingProblemIsInfeasible(name_);
2382 absl::MutexLock mutex_lock(&mutex_);
2383 deterministic_time_since_last_synchronize_ +=
2384 time_limit->GetElapsedDeterministicTime() - saved_dtime;
2388 if (shared_->SearchIsDone()) {
2389 shared_->time_limit->Stop();
2393 absl::MutexLock mutex_lock(&mutex_);
2394 previous_task_is_completed_ =
true;
2398 void Synchronize()
override {
2399 absl::MutexLock mutex_lock(&mutex_);
2400 deterministic_time_ += deterministic_time_since_last_synchronize_;
2401 shared_->time_limit->AdvanceDeterministicTime(
2402 deterministic_time_since_last_synchronize_);
2403 deterministic_time_since_last_synchronize_ = 0.0;
2407 SharedClasses* shared_;
2408 std::unique_ptr<Model> local_model_;
2414 bool solving_first_chunk_ ABSL_GUARDED_BY(mutex_) =
true;
2416 double deterministic_time_since_last_synchronize_ ABSL_GUARDED_BY(mutex_) =
2418 bool previous_task_is_completed_ ABSL_GUARDED_BY(mutex_) =
true;
2422 class LnsSolver :
public SubSolver {
2424 LnsSolver(std::unique_ptr<NeighborhoodGenerator> generator,
2426 NeighborhoodGeneratorHelper* helper, SharedClasses* shared)
2427 : SubSolver(generator->
name()),
2428 generator_(std::move(generator)),
2433 bool TaskIsAvailable()
override {
2434 if (shared_->SearchIsDone())
return false;
2435 return generator_->ReadyToGenerate();
2438 std::function<void()> GenerateTask(int64_t task_id)
override {
2439 return [task_id,
this]() {
2440 if (shared_->SearchIsDone())
return;
2445 const int32_t low =
static_cast<int32_t
>(task_id);
2446 const int32_t high = task_id >> 32;
2447 std::seed_seq seed{low, high, parameters_.random_seed()};
2450 NeighborhoodGenerator::SolveData data;
2451 data.difficulty = generator_->difficulty();
2452 data.deterministic_limit = generator_->deterministic_limit();
2455 CpSolverResponse base_response;
2457 const SharedSolutionRepository<int64_t>& repo =
2458 shared_->response->SolutionsRepository();
2459 if (repo.NumSolutions() > 0) {
2461 const SharedSolutionRepository<int64_t>::Solution solution =
2462 repo.GetRandomBiasedSolution(random);
2463 for (
const int64_t
value : solution.variable_values) {
2464 base_response.add_solution(
value);
2468 data.initial_best_objective = repo.GetSolution(0).rank;
2469 data.base_objective = solution.rank;
2478 data.initial_best_objective =
2479 shared_->response->GetInnerObjectiveUpperBound();
2480 data.base_objective = data.initial_best_objective;
2484 Neighborhood neighborhood =
2485 generator_->Generate(base_response, data.difficulty, random);
2487 if (!neighborhood.is_generated)
return;
2489 data.neighborhood_id = neighborhood.id;
2491 const double fully_solved_proportion =
2492 static_cast<double>(generator_->num_fully_solved_calls()) /
2493 std::max(int64_t{1}, generator_->num_calls());
2494 std::string source_info =
name();
2495 if (!neighborhood.source_info.empty()) {
2496 absl::StrAppend(&source_info,
"_", neighborhood.source_info);
2498 const std::string solution_info = absl::StrFormat(
2499 "%s(d=%0.2f s=%i t=%0.2f p=%0.2f)", source_info, data.difficulty,
2500 task_id, data.deterministic_limit, fully_solved_proportion);
2502 SatParameters local_params(parameters_);
2503 local_params.set_max_deterministic_time(data.deterministic_limit);
2504 local_params.set_stop_after_first_solution(
false);
2505 local_params.set_log_search_progress(
false);
2506 local_params.set_cp_model_probing_level(0);
2507 local_params.set_symmetry_level(0);
2509 Model local_model(solution_info);
2510 *(local_model.GetOrCreate<SatParameters>()) = local_params;
2511 TimeLimit* local_time_limit = local_model.GetOrCreate<TimeLimit>();
2512 local_time_limit->ResetLimitFromParameters(local_params);
2513 shared_->time_limit->UpdateLocalLimit(local_time_limit);
2516 CpModelProto lns_fragment;
2517 CpModelProto mapping_proto;
2518 auto context = absl::make_unique<PresolveContext>(
2519 &local_model, &lns_fragment, &mapping_proto);
2521 *lns_fragment.mutable_variables() = neighborhood.delta.variables();
2523 ModelCopy copier(
context.get());
2526 if (!copier.ImportAndSimplifyConstraints(
2527 helper_->ModelProto(), neighborhood.constraints_to_ignore)) {
2532 if (!neighborhood.delta.constraints().empty() &&
2533 !copier.ImportAndSimplifyConstraints(neighborhood.delta, {})) {
2540 helper_->ModelProto(),
context.get());
2543 if (neighborhood.delta.has_solution_hint()) {
2544 *lns_fragment.mutable_solution_hint() =
2545 neighborhood.delta.solution_hint();
2547 if (absl::GetFlag(FLAGS_cp_model_dump_lns)) {
2549 const std::string lns_name =
2550 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2551 lns_fragment.name(),
".pbtxt");
2552 LOG(
INFO) <<
"Dumping LNS model to '" << lns_name <<
"'.";
2556 std::vector<int> postsolve_mapping;
2561 neighborhood.delta.Clear();
2566 SharedResponseManager local_response_manager(
2567 false, &lns_fragment, shared_->wall_timer,
2568 shared_->time_limit, local_model.GetOrCreate<SolverLogger>());
2569 local_model.Register(&local_response_manager);
2570 LoadCpModel(lns_fragment, &local_model);
2571 QuickSolveWithHint(lns_fragment, &local_model);
2572 SolveLoadedCpModel(lns_fragment, &local_model);
2573 CpSolverResponse local_response = local_response_manager.GetResponse();
2577 PostsolveResponseWrapper(
2578 local_params, helper_->ModelProto().variables_size(), mapping_proto,
2579 postsolve_mapping, shared_->wall_timer, &local_response);
2580 data.status = local_response.status();
2581 data.deterministic_time = local_time_limit->GetElapsedDeterministicTime();
2583 if (generator_->IsRelaxationGenerator()) {
2584 bool has_feasible_solution =
false;
2587 has_feasible_solution =
true;
2591 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2592 local_response.solution_info());
2595 if (shared_->model_proto->has_objective()) {
2598 const IntegerValue current_obj_lb =
2599 shared_->response->GetInnerObjectiveLowerBound();
2601 const IntegerValue local_obj_lb =
2602 local_response_manager.GetInnerObjectiveLowerBound();
2605 lns_fragment.objective(), local_obj_lb.value());
2608 const IntegerValue new_inner_obj_lb = IntegerValue(
2610 scaled_local_obj_bound) -
2612 data.new_objective_bound = new_inner_obj_lb;
2613 data.initial_best_objective_bound = current_obj_lb;
2614 if (new_inner_obj_lb > current_obj_lb) {
2615 shared_->response->UpdateInnerObjectiveBounds(
2622 if (has_feasible_solution) {
2624 *shared_->model_proto,
2625 std::vector<int64_t>(local_response.solution().begin(),
2626 local_response.solution().end()))) {
2627 shared_->response->NewSolution(local_response,
2632 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2633 local_response.solution_info());
2634 shared_->time_limit->Stop();
2637 shared_->relaxation_solutions->NewRelaxationSolution(local_response);
2640 if (!local_response.solution().empty()) {
2647 *shared_->model_proto,
2648 std::vector<int64_t>(local_response.solution().begin(),
2649 local_response.solution().end()));
2651 const std::string
name =
2652 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
2653 lns_fragment.name(),
".pbtxt");
2654 LOG(
INFO) <<
"Dumping problematic LNS model to '" <<
name <<
"'.";
2656 LOG(
FATAL) <<
"Infeasible LNS solution! " << solution_info;
2661 data.new_objective = data.base_objective;
2665 shared_->model_proto->objective(), local_response));
2671 shared_->response->NewSolution(local_response,
2674 if (!neighborhood.is_reduced &&
2677 shared_->response->NotifyThatImprovingProblemIsInfeasible(
2678 local_response.solution_info());
2679 shared_->time_limit->Stop();
2683 generator_->AddSolveData(data);
2686 const int total_num_calls = task_id;
2687 VLOG(2) <<
name() <<
": [difficulty: " << data.difficulty
2688 <<
", id: " << task_id
2689 <<
", deterministic_time: " << data.deterministic_time <<
" / "
2690 << data.deterministic_limit
2691 <<
", status: " << ProtoEnumToString<CpSolverStatus>(data.status)
2692 <<
", num calls: " << generator_->num_calls()
2693 <<
", UCB1 Score: " << generator_->GetUCBScore(total_num_calls)
2694 <<
", p: " << fully_solved_proportion <<
"]";
2698 void Synchronize()
override {
2699 generator_->Synchronize();
2700 const double old = deterministic_time_;
2701 deterministic_time_ = generator_->deterministic_time();
2702 shared_->time_limit->AdvanceDeterministicTime(deterministic_time_ - old);
2706 std::unique_ptr<NeighborhoodGenerator> generator_;
2707 NeighborhoodGeneratorHelper* helper_;
2708 const SatParameters parameters_;
2709 SharedClasses* shared_;
2712 void SolveCpModelParallel(
const CpModelProto&
model_proto,
2713 SharedResponseManager* shared_response_manager,
2714 SharedTimeLimit* shared_time_limit,
2716 SolverLogger* logger) {
2717 CHECK(shared_response_manager !=
nullptr);
2718 const SatParameters&
parameters = *global_model->GetOrCreate<SatParameters>();
2719 const int num_search_workers =
parameters.num_search_workers();
2722 <<
"Enumerating all solutions in parallel is not supported.";
2724 std::unique_ptr<SharedBoundsManager> shared_bounds_manager;
2726 shared_bounds_manager = absl::make_unique<SharedBoundsManager>(
model_proto);
2729 std::unique_ptr<SharedRelaxationSolutionRepository>
2730 shared_relaxation_solutions;
2732 shared_relaxation_solutions =
2733 absl::make_unique<SharedRelaxationSolutionRepository>(
2735 global_model->Register<SharedRelaxationSolutionRepository>(
2736 shared_relaxation_solutions.get());
2739 auto shared_lp_solutions = absl::make_unique<SharedLPSolutionRepository>(
2741 global_model->Register<SharedLPSolutionRepository>(shared_lp_solutions.get());
2745 std::unique_ptr<SharedIncompleteSolutionManager> shared_incomplete_solutions;
2746 const bool use_feasibility_pump =
parameters.use_feasibility_pump() &&
2750 if (use_feasibility_pump) {
2751 shared_incomplete_solutions =
2752 absl::make_unique<SharedIncompleteSolutionManager>();
2753 global_model->Register<SharedIncompleteSolutionManager>(
2754 shared_incomplete_solutions.get());
2757 SharedClasses shared;
2760 shared.time_limit = shared_time_limit;
2761 shared.bounds = shared_bounds_manager.get();
2762 shared.response = shared_response_manager;
2763 shared.relaxation_solutions = shared_relaxation_solutions.get();
2764 shared.lp_solutions = shared_lp_solutions.get();
2765 shared.incomplete_solutions = shared_incomplete_solutions.get();
2768 std::vector<std::unique_ptr<SubSolver>> subsolvers;
2771 subsolvers.push_back(absl::make_unique<SynchronizationPoint>(
2772 [shared_response_manager, &shared_bounds_manager,
2773 &shared_relaxation_solutions, &shared_lp_solutions]() {
2774 shared_response_manager->Synchronize();
2775 shared_response_manager->MutableSolutionsRepository()->Synchronize();
2776 if (shared_bounds_manager !=
nullptr) {
2777 shared_bounds_manager->Synchronize();
2779 if (shared_relaxation_solutions !=
nullptr) {
2780 shared_relaxation_solutions->Synchronize();
2782 if (shared_lp_solutions !=
nullptr) {
2783 shared_lp_solutions->Synchronize();
2792 local_params.set_stop_after_first_solution(
true);
2793 local_params.set_linearization_level(0);
2794 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2795 "first_solution", local_params,
2801 if (
parameters.optimize_with_max_hs())
continue;
2803 subsolvers.push_back(absl::make_unique<FullProblemSolver>(
2804 local_params.name(), local_params,
2810 if (use_feasibility_pump) {
2811 subsolvers.push_back(
2812 absl::make_unique<FeasibilityPumpSolver>(
parameters, &shared));
2819 auto unique_helper = absl::make_unique<NeighborhoodGeneratorHelper>(
2821 shared_bounds_manager.get());
2822 NeighborhoodGeneratorHelper* helper = unique_helper.get();
2823 subsolvers.push_back(std::move(unique_helper));
2826 std::vector<SatParameters> lns_params = {
parameters};
2827 lns_params.back().set_name(
"default");
2829 std::vector<SatParameters> lns_params =
2832 for (
const SatParameters& local_params : lns_params) {
2837 subsolvers.push_back(absl::make_unique<LnsSolver>(
2838 absl::make_unique<SimpleNeighborhoodGenerator>(
2839 helper, absl::StrCat(
"rnd_var_lns_", local_params.name())),
2840 local_params, helper, &shared));
2841 subsolvers.push_back(absl::make_unique<LnsSolver>(
2842 absl::make_unique<SimpleConstraintNeighborhoodGenerator>(
2843 helper, absl::StrCat(
"rnd_cst_lns_", local_params.name())),
2844 local_params, helper, &shared));
2845 subsolvers.push_back(absl::make_unique<LnsSolver>(
2846 absl::make_unique<VariableGraphNeighborhoodGenerator>(
2847 helper, absl::StrCat(
"graph_var_lns_", local_params.name())),
2848 local_params, helper, &shared));
2849 subsolvers.push_back(absl::make_unique<LnsSolver>(
2850 absl::make_unique<ConstraintGraphNeighborhoodGenerator>(
2851 helper, absl::StrCat(
"graph_cst_lns_", local_params.name())),
2852 local_params, helper, &shared));
2854 if (!helper->TypeToConstraints(ConstraintProto::kNoOverlap).empty()) {
2855 subsolvers.push_back(absl::make_unique<LnsSolver>(
2856 absl::make_unique<SchedulingTimeWindowNeighborhoodGenerator>(
2857 helper, absl::StrCat(
"scheduling_time_window_lns_",
2858 local_params.name())),
2859 local_params, helper, &shared));
2860 subsolvers.push_back(absl::make_unique<LnsSolver>(
2861 absl::make_unique<SchedulingNeighborhoodGenerator>(
2863 absl::StrCat(
"scheduling_random_lns_", local_params.name())),
2864 local_params, helper, &shared));
2877 subsolvers.push_back(absl::make_unique<LnsSolver>(
2878 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2879 helper, shared.response, shared.relaxation_solutions,
2880 shared.lp_solutions,
nullptr,
2881 absl::StrCat(
"rins_lns_", local_params.name())),
2882 local_params, helper, &shared));
2885 subsolvers.push_back(absl::make_unique<LnsSolver>(
2886 absl::make_unique<RelaxationInducedNeighborhoodGenerator>(
2887 helper,
nullptr, shared.relaxation_solutions,
2888 shared.lp_solutions, shared.incomplete_solutions,
2889 absl::StrCat(
"rens_lns_", local_params.name())),
2890 local_params, helper, &shared));
2894 subsolvers.push_back(absl::make_unique<LnsSolver>(
2896 ConsecutiveConstraintsRelaxationNeighborhoodGenerator>(
2897 helper, absl::StrCat(
"rnd_rel_lns_", local_params.name())),
2898 local_params, helper, &shared));
2900 subsolvers.push_back(absl::make_unique<LnsSolver>(
2901 absl::make_unique<WeightedRandomRelaxationNeighborhoodGenerator>(
2902 helper, absl::StrCat(
"wgt_rel_lns_", local_params.name())),
2903 local_params, helper, &shared));
2910 subsolvers.push_back(
2911 absl::make_unique<SynchronizationPoint>([shared_response_manager]() {
2912 shared_response_manager->UpdatePrimalIntegral();
2917 std::vector<std::string> names;
2918 for (
const auto& subsolver : subsolvers) {
2919 if (!subsolver->name().empty()) names.push_back(subsolver->name());
2922 SOLVER_LOG(logger, absl::StrFormat(
"Starting Search at %.2fs with %i "
2923 "workers and subsolvers: [ %s ]",
2925 absl::StrJoin(names,
", ")));
2942 void AddPostsolveClauses(
const std::vector<int>& postsolve_mapping,
2943 Model*
model, CpModelProto* mapping_proto) {
2944 auto* mapping =
model->GetOrCreate<CpModelMapping>();
2945 auto* postsolve =
model->GetOrCreate<PostsolveClauses>();
2946 for (
const auto& clause : postsolve->clauses) {
2947 auto*
ct = mapping_proto->add_constraints()->mutable_bool_or();
2948 for (
const Literal l : clause) {
2949 int var = mapping->GetProtoVariableFromBooleanVariable(l.Variable());
2951 var = postsolve_mapping[
var];
2955 postsolve->clauses.clear();
2966 #if defined(_MSC_VER)
2970 std::unique_ptr<CpSolverResponse> final_response_ptr(
new CpSolverResponse());
2971 CpSolverResponse& final_response = *final_response_ptr.get();
2973 CpSolverResponse final_response;
2976 #if !defined(__PORTABLE_PLATFORM__)
2978 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
2979 const std::string
file =
2980 absl::StrCat(absl::GetFlag(FLAGS_cp_model_dump_prefix),
"model.pbtxt");
2981 LOG(
INFO) <<
"Dumping cp model proto to '" <<
file <<
"'.";
2986 if (absl::GetFlag(FLAGS_cp_model_dump_response)) {
2987 const std::string
file = absl::StrCat(
2988 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"response.pbtxt");
2989 LOG(
INFO) <<
"Dumping response proto to '" <<
file <<
"'.";
2995 if (!absl::GetFlag(FLAGS_cp_model_params).empty()) {
2996 SatParameters params = *
model->GetOrCreate<SatParameters>();
2997 SatParameters flag_params;
2998 CHECK(google::protobuf::TextFormat::ParseFromString(
2999 absl::GetFlag(FLAGS_cp_model_params), &flag_params));
3000 params.MergeFrom(flag_params);
3001 *(
model->GetOrCreate<SatParameters>()) = params;
3007 *
model->GetOrCreate<SatParameters>());
3010 #if !defined(__PORTABLE_PLATFORM__)
3013 if (
model->GetOrCreate<SatParameters>()->catch_sigint_signal()) {
3014 handler.
Register([&shared_time_limit]() { shared_time_limit.Stop(); });
3019 const SatParameters& params = *
model->GetOrCreate<SatParameters>();
3020 const bool log_search = params.log_search_progress() ||
VLOG_IS_ON(1);
3022 std::string log_string;
3026 if (params.log_to_response()) {
3027 const auto append_to_string = [&log_string](
const std::string&
message) {
3028 absl::StrAppend(&log_string,
message,
"\n");
3034 SOLVER_LOG(logger,
"Starting CP-SAT solver.");
3035 SOLVER_LOG(logger,
"Parameters: ", params.ShortDebugString());
3036 if (log_search && params.use_absl_random()) {
3041 auto display_response_cleanup =
3046 if (!log_string.empty()) {
3047 final_response.set_solve_log(log_string);
3055 if (!error.empty()) {
3058 return final_response;
3069 if (!params.use_sat_inprocessing() && !
model_proto.has_objective() &&
3070 !
model_proto.has_solution_hint() && !params.enumerate_all_solutions() &&
3071 !params.use_lns_only() && params.num_search_workers() <= 1 &&
3073 bool is_pure_sat =
true;
3074 for (
const IntegerVariableProto&
var :
model_proto.variables()) {
3075 if (
var.domain_size() != 2 ||
var.domain(0) < 0 ||
var.domain(1) > 1) {
3076 is_pure_sat =
false;
3081 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
3082 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolOr &&
3083 ct.constraint_case() != ConstraintProto::ConstraintCase::kBoolAnd) {
3084 is_pure_sat =
false;
3095 final_response.set_user_time(user_timer.
Get());
3096 final_response.set_deterministic_time(
3097 shared_time_limit.GetElapsedDeterministicTime());
3098 const SatParameters& params = *
model->GetOrCreate<SatParameters>();
3099 if (params.fill_tightened_domains_in_response()) {
3100 *final_response.mutable_tightened_variables() =
model_proto.variables();
3102 return final_response;
3109 absl::StrFormat(
"Starting presolve at %.2fs",
wall_timer.
Get()));
3110 CpModelProto new_cp_model_proto;
3111 CpModelProto mapping_proto;
3112 auto context = absl::make_unique<PresolveContext>(
model, &new_cp_model_proto,
3118 VLOG(1) <<
"Model found infeasible during copy";
3125 bool degraded_assumptions_support =
false;
3126 if (params.num_search_workers() > 1 ||
model_proto.has_objective()) {
3133 degraded_assumptions_support =
true;
3134 context->InitializeNewDomains();
3136 if (!
context->SetLiteralToTrue(ref)) {
3138 final_response.add_sufficient_assumptions_for_infeasibility(ref);
3139 return final_response;
3146 std::function<void(CpSolverResponse *
response)> postprocess_solution;
3149 std::vector<int> postsolve_mapping;
3152 LOG(
ERROR) <<
"Error while presolving, likely due to integer overflow.";
3154 return final_response;
3162 if (params.cp_model_presolve()) {
3163 postprocess_solution = [&
model_proto, ¶ms, &mapping_proto,
3164 &shared_time_limit, &postsolve_mapping, &
wall_timer,
3166 AddPostsolveClauses(postsolve_mapping,
model, &mapping_proto);
3167 PostsolveResponseWrapper(params,
model_proto.variables_size(),
3168 mapping_proto, postsolve_mapping, &
wall_timer,
3170 if (!
response->solution().empty()) {
3173 std::vector<int64_t>(
response->solution().begin(),
3175 &mapping_proto, &postsolve_mapping))
3176 <<
"final postsolved solution";
3178 if (params.fill_tightened_domains_in_response()) {
3180 if (mapping_proto.variables().size() >=
3182 for (
int i = 0; i <
model_proto.variables().size(); ++i) {
3183 *
response->add_tightened_variables() = mapping_proto.variables(i);
3188 response->set_user_time(user_timer.Get());
3190 shared_time_limit.GetElapsedDeterministicTime());
3195 &user_timer](CpSolverResponse*
response) {
3197 const int initial_size =
model_proto.variables_size();
3198 if (
response->solution_size() > 0) {
3199 response->mutable_solution()->Truncate(initial_size);
3200 }
else if (
response->solution_lower_bounds_size() > 0) {
3201 response->mutable_solution_lower_bounds()->Truncate(initial_size);
3202 response->mutable_solution_upper_bounds()->Truncate(initial_size);
3204 if (params.fill_tightened_domains_in_response()) {
3210 shared_time_limit.GetElapsedDeterministicTime());
3217 if (params.symmetry_level() > 1) {
3222 params.enumerate_all_solutions(), &new_cp_model_proto, &
wall_timer,
3223 &shared_time_limit, logger);
3225 absl::GetFlag(FLAGS_cp_model_dump_prefix));
3230 if (!observers.empty()) {
3232 [&
model_proto, &observers, &postprocess_solution](
3233 const CpSolverResponse& response_of_presolved_problem) {
3234 CpSolverResponse
response = response_of_presolved_problem;
3236 if (!
response.solution().empty()) {
3238 absl::GetFlag(FLAGS_cp_model_check_intermediate_solutions)) {
3241 std::vector<int64_t>(
response.solution().begin(),
3246 for (
const auto& observer : observers) {
3256 if (new_cp_model_proto.has_objective()) {
3260 "initial_domain", IntegerValue(domain.
Min()),
3261 IntegerValue(domain.
Max()));
3269 #if !defined(__PORTABLE_PLATFORM__)
3270 if (absl::GetFlag(FLAGS_cp_model_dump_models)) {
3271 const std::string presolved_file = absl::StrCat(
3272 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"presolved_model.pbtxt");
3273 LOG(
INFO) <<
"Dumping presolved cp model proto to '" << presolved_file
3278 const std::string mapping_file = absl::StrCat(
3279 absl::GetFlag(FLAGS_cp_model_dump_prefix),
"mapping_model.pbtxt");
3280 LOG(
INFO) <<
"Dumping mapping cp model proto to '" << mapping_file <<
"'.";
3285 if (params.stop_after_presolve() || shared_time_limit.LimitReached()) {
3286 int64_t num_terms = 0;
3287 for (
const ConstraintProto&
ct : new_cp_model_proto.constraints()) {
3291 logger,
"Stopped after presolve.",
3292 "\nPresolvedNumVariables: ", new_cp_model_proto.variables().size(),
3293 "\nPresolvedNumConstraints: ", new_cp_model_proto.constraints().size(),
3294 "\nPresolvedNumTerms: ", num_terms);
3298 final_response = shared_response_manager.
GetResponse();
3299 postprocess_solution(&final_response);
3300 return final_response;
3304 if (params.stop_after_first_solution()) {
3306 [&shared_time_limit](
3307 const CpSolverResponse& response_of_presolved_problem) {
3308 shared_time_limit.Stop();
3312 #if defined(__PORTABLE_PLATFORM__)
3316 if (params.num_search_workers() > 1 || params.interleave_search()) {
3317 SolveCpModelParallel(new_cp_model_proto, &shared_response_manager,
3322 SOLVER_LOG(logger, absl::StrFormat(
"Starting to load the model at %.2fs",
3325 LoadCpModel(new_cp_model_proto,
model);
3329 SOLVER_LOG(logger, absl::StrFormat(
"Starting sequential search at %.2fs",
3331 if (params.repair_hint()) {
3332 MinimizeL1DistanceWithHint(new_cp_model_proto, &
wall_timer,
3333 &shared_time_limit,
model);
3335 QuickSolveWithHint(new_cp_model_proto,
model);
3337 SolveLoadedCpModel(new_cp_model_proto,
model);
3340 final_response = shared_response_manager.
GetResponse();
3341 postprocess_solution(&final_response);
3342 if (!final_response.solution().empty()) {
3344 model_proto, std::vector<int64_t>(final_response.solution().begin(),
3345 final_response.solution().end())));
3347 if (degraded_assumptions_support &&
3350 *final_response.mutable_sufficient_assumptions_for_infeasibility() =
3353 if (log_search && params.num_search_workers() > 1) {
3358 return final_response;
3367 const SatParameters& params) {
3373 #if !defined(__PORTABLE_PLATFORM__)
3375 const std::string& params) {
#define CHECK_NE(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
bool AddEdge(int node1, int node2)
std::vector< int > GetComponentIds()
void SetNumberOfNodes(int num_nodes)
int GetNumberOfComponents() const
We call domain any subset of Int64 = [kint64min, kint64max].
int64_t Min() const
Returns the min value of the domain.
bool IsEmpty() const
Returns true if this is the empty set.
int64_t Max() const
Returns the max value of the domain.
void Register(const std::function< void()> &f)
void SetLogToStdOut(bool enable)
void AddInfoLoggingCallback(std::function< void(const std::string &message)> callback)
void EnableLogging(bool enable)
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
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)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
CutGenerator CreateCVRPCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, const std::vector< int64_t > &demands, int64_t capacity, Model *model)
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_t(const Model &)> UpperBound(IntegerVariable v)
void DetectAndAddSymmetryToProto(const SatParameters ¶ms, CpModelProto *proto, SolverLogger *logger)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
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::string CpSolverResponseStats(const CpSolverResponse &response, bool has_objective)
Returns a string with some statistics on the solver response.
bool LoadConstraint(const ConstraintProto &ct, Model *m)
std::vector< int > UsedVariables(const ConstraintProto &ct)
double UnscaleObjectiveValue(const CpObjectiveProto &proto, double value)
bool RefIsPositive(int ref)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
void MaybeFullyEncodeMoreVariables(const CpModelProto &model_proto, Model *m)
void PostsolveResponse(const int64_t num_variables_in_original_model, const CpModelProto &mapping_proto, const std::vector< int > &postsolve_mapping, CpSolverResponse *response)
CutGenerator CreateCumulativeCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, Model *model)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
bool HasEnforcementLiteral(const ConstraintProto &ct)
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)
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_t value)
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
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)
void CopyEverythingExceptVariablesAndConstraintsFieldsIntoContext(const CpModelProto &in_model, PresolveContext *context)
int ReindexArcs(IntContainer *tails, IntContainer *heads)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
CutGenerator CreateNoOverlapBalasCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
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_t upper_bound)
bool ImportConstraintsWithBasicPresolveIntoContext(const CpModelProto &in_model, PresolveContext *context)
std::string CpModelStats(const CpModelProto &model_proto)
Returns a string with some statistics on the given CpModelProto.
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
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)
CutGenerator CreateNoOverlapEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
void MinimizeCoreWithPropagation(TimeLimit *limit, SatSolver *solver, std::vector< Literal > *core)
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)
SatSolver::Status SolveWithPresolve(std::unique_ptr< SatSolver > *solver, TimeLimit *time_limit, std::vector< bool > *solution, DratProofHandler *drat_proof_handler, SolverLogger *logger)
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)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
bool SolutionIsFeasible(const CpModelProto &model, const std::vector< int64_t > &variable_values, const CpModelProto *mapping_proto, const std::vector< int > *postsolve_mapping)
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< IntegerVariable(Model *)> ConstantIntegerVariable(int64_t value)
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.
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
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)
Collection of objects used to extend the Constraint Solver library.
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 SOLVER_LOG(logger,...)
#define VLOG_IS_ON(verboselevel)