26 #include "absl/container/flat_hash_map.h"
27 #include "absl/container/flat_hash_set.h"
62 template <
typename Values>
63 std::vector<int64_t> ValuesFromProto(
const Values& values) {
64 return std::vector<int64_t>(values.begin(), values.end());
67 void ComputeLinearBounds(
const LinearConstraintProto&
proto,
68 CpModelMapping* mapping, IntegerTrail* integer_trail,
69 int64_t* sum_min, int64_t* sum_max) {
73 for (
int i = 0; i <
proto.vars_size(); ++i) {
74 const int64_t coeff =
proto.coeffs(i);
75 const IntegerVariable
var = mapping->Integer(
proto.vars(i));
76 const int64_t lb = integer_trail->LowerBound(
var).value();
77 const int64_t ub = integer_trail->UpperBound(
var).value();
79 (*sum_min) += coeff * lb;
80 (*sum_max) += coeff * ub;
82 (*sum_min) += coeff * ub;
83 (*sum_max) += coeff * lb;
89 bool ConstraintIsEq(
const LinearConstraintProto&
proto) {
94 bool ConstraintIsNEq(
const LinearConstraintProto&
proto,
95 CpModelMapping* mapping, IntegerTrail* integer_trail,
96 int64_t* single_value) {
99 ComputeLinearBounds(
proto, mapping, integer_trail, &sum_min, &sum_max);
101 const Domain complement =
102 Domain(sum_min, sum_max)
104 if (complement.IsEmpty())
return false;
105 const int64_t
value = complement.Min();
107 if (complement.Size() == 1) {
108 if (single_value !=
nullptr) {
109 *single_value =
value;
119 bool view_all_booleans_as_integers,
121 const int num_proto_variables =
model_proto.variables_size();
127 CHECK_EQ(sat_solver->NumVariables(), 0);
129 BooleanVariable new_var(0);
130 std::vector<BooleanVariable> false_variables;
131 std::vector<BooleanVariable> true_variables;
134 reverse_boolean_map_.
resize(num_proto_variables, -1);
135 for (
int i = 0; i < num_proto_variables; ++i) {
136 const auto& domain =
model_proto.variables(i).domain();
137 if (domain.size() != 2)
continue;
138 if (domain[0] >= 0 && domain[1] <= 1) {
139 booleans_[i] = new_var;
140 reverse_boolean_map_[new_var] = i;
141 if (domain[1] == 0) {
143 }
else if (domain[0] == 1) {
144 true_variables.push_back(new_var);
150 sat_solver->SetNumVariables(new_var.value());
151 for (
const BooleanVariable
var : true_variables) {
154 for (
const BooleanVariable
var : false_variables) {
161 std::vector<int> var_to_instantiate_as_integer;
162 if (view_all_booleans_as_integers) {
163 var_to_instantiate_as_integer.resize(num_proto_variables);
164 for (
int i = 0; i < num_proto_variables; ++i) {
165 var_to_instantiate_as_integer[i] = i;
169 absl::flat_hash_set<int> used_variables;
172 for (
int c = 0; c <
model_proto.constraints_size(); ++c) {
183 for (
const int obj_var :
model_proto.objective().vars()) {
190 for (
int i = 0; i < num_proto_variables; ++i) {
192 used_variables.insert(i);
197 var_to_instantiate_as_integer.assign(used_variables.begin(),
198 used_variables.end());
205 var_to_instantiate_as_integer.size());
206 reverse_integer_map_.
resize(2 * var_to_instantiate_as_integer.size(), -1);
207 for (
const int i : var_to_instantiate_as_integer) {
212 reverse_integer_map_[integers_[i]] = i;
219 for (
int i = 0; i < num_proto_variables; ++i) {
224 encoder->AssociateToIntegerEqualValue(
sat::Literal(booleans_[i],
true),
225 integers_[i], IntegerValue(1));
230 for (
int c = 0; c <
model_proto.constraints_size(); ++c) {
232 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kInterval) {
241 if (
ct.interval().has_start_view()) {
242 intervals_[c] = intervals_repository->CreateInterval(
246 enforcement_literal.
Index(),
251 Integer(
ct.interval().size()), enforcement_literal));
254 if (
ct.interval().has_start_view()) {
255 intervals_[c] = intervals_repository->CreateInterval(
266 already_loaded_ct_.insert(&
ct);
272 const SymmetryProto symmetry =
model_proto.symmetry();
273 if (symmetry.permutations().empty())
return;
277 sat_solver->AddPropagator(symmetry_handler);
278 const int num_literals = 2 * sat_solver->NumVariables();
280 for (
const SparsePermutationProto& perm : symmetry.permutations()) {
281 bool all_bool =
true;
282 for (
const int var : perm.support()) {
288 if (!all_bool)
continue;
291 auto literal_permutation =
292 absl::make_unique<SparsePermutation>(num_literals);
293 int support_index = 0;
294 const int num_cycle = perm.cycle_sizes().size();
295 for (
int i = 0; i < num_cycle; ++i) {
296 const int size = perm.cycle_sizes(i);
297 const int saved_support_index = support_index;
298 for (
int j = 0; j < size; ++j) {
299 const int var = perm.support(support_index++);
302 literal_permutation->CloseCurrentCycle();
306 support_index = saved_support_index;
307 for (
int j = 0; j < size; ++j) {
308 const int var = perm.support(support_index++);
309 literal_permutation->AddToCurrentCycle(
312 literal_permutation->CloseCurrentCycle();
314 symmetry_handler->AddSymmetry(std::move(literal_permutation));
318 symmetry_handler->num_permutations(),
319 " symmetry to the SAT solver.");
335 if (sat_solver->IsModelUnsat())
return;
340 struct EqualityDetectionHelper {
341 const ConstraintProto*
ct;
346 bool operator<(
const EqualityDetectionHelper& o)
const {
347 if (
literal.Variable() == o.literal.Variable()) {
348 if (
value == o.value)
return is_equality && !o.is_equality;
349 return value < o.value;
351 return literal.Variable() < o.literal.Variable();
354 std::vector<std::vector<EqualityDetectionHelper>> var_to_equalities(
366 struct InequalityDetectionHelper {
367 const ConstraintProto*
ct;
371 bool operator<(
const InequalityDetectionHelper& o)
const {
372 if (
literal.Variable() == o.literal.Variable()) {
373 return i_lit.
var < o.i_lit.var;
375 return literal.Variable() < o.literal.Variable();
378 std::vector<InequalityDetectionHelper> inequalities;
381 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
382 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kLinear) {
385 if (
ct.enforcement_literal().size() != 1)
continue;
386 if (
ct.linear().vars_size() != 1)
continue;
390 const int ref =
ct.linear().vars(0);
394 const Domain domain_if_enforced =
401 if (domain_if_enforced.
Max() >= domain.
Max() &&
402 domain_if_enforced.
Min() > domain.
Min()) {
403 inequalities.push_back(
404 {&
ct, enforcement_literal,
407 implied_bounds->Add(enforcement_literal, inequalities.back().i_lit);
408 }
else if (domain_if_enforced.
Min() <= domain.
Min() &&
409 domain_if_enforced.
Max() < domain.
Max()) {
410 inequalities.push_back(
411 {&
ct, enforcement_literal,
414 implied_bounds->Add(enforcement_literal, inequalities.back().i_lit);
426 var_to_equalities[
var].push_back(
427 {&
ct, enforcement_literal, inter.
Min(),
true});
429 variables_to_encoded_values_[
var].insert(inter.
Min());
437 var_to_equalities[
var].push_back(
438 {&
ct, enforcement_literal, inter.
Min(),
false});
440 variables_to_encoded_values_[
var].insert(inter.
Min());
447 int num_inequalities = 0;
448 std::sort(inequalities.begin(), inequalities.end());
449 for (
int i = 0; i + 1 < inequalities.size(); i++) {
450 if (inequalities[i].
literal != inequalities[i + 1].
literal.Negated()) {
457 if (integer_trail->IntegerLiteralIsTrue(inequalities[i].i_lit) ||
458 integer_trail->IntegerLiteralIsFalse(inequalities[i].i_lit)) {
461 if (integer_trail->IntegerLiteralIsTrue(inequalities[i + 1].i_lit) ||
462 integer_trail->IntegerLiteralIsFalse(inequalities[i + 1].i_lit)) {
466 const auto pair_a = encoder->Canonicalize(inequalities[i].i_lit);
467 const auto pair_b = encoder->Canonicalize(inequalities[i + 1].i_lit);
468 if (pair_a.first == pair_b.second) {
470 encoder->AssociateToIntegerLiteral(inequalities[i].
literal,
471 inequalities[i].i_lit);
472 already_loaded_ct_.insert(inequalities[i].
ct);
473 already_loaded_ct_.insert(inequalities[i + 1].
ct);
478 int num_half_inequalities = 0;
479 for (
const auto inequality : inequalities) {
483 encoder->GetOrCreateAssociatedLiteral(inequality.i_lit)));
484 if (sat_solver->IsModelUnsat())
return;
486 ++num_half_inequalities;
487 already_loaded_ct_.insert(inequality.ct);
488 is_half_encoding_ct_.insert(inequality.ct);
491 if (!inequalities.empty()) {
492 VLOG(1) << num_inequalities <<
" literals associated to VAR >= value, and "
493 << num_half_inequalities <<
" half-associations.";
499 int num_constraints = 0;
500 int num_equalities = 0;
501 int num_half_equalities = 0;
502 int num_fully_encoded = 0;
503 int num_partially_encoded = 0;
504 for (
int i = 0; i < var_to_equalities.size(); ++i) {
505 std::vector<EqualityDetectionHelper>& encoding = var_to_equalities[i];
506 std::sort(encoding.begin(), encoding.end());
507 if (encoding.empty())
continue;
508 num_constraints += encoding.size();
510 absl::flat_hash_set<int64_t> values;
511 for (
int j = 0; j + 1 < encoding.size(); j++) {
512 if ((encoding[j].
value != encoding[j + 1].
value) ||
514 (encoding[j].is_equality !=
true) ||
515 (encoding[j + 1].is_equality !=
false)) {
520 encoder->AssociateToIntegerEqualValue(encoding[j].
literal, integers_[i],
521 IntegerValue(encoding[j].
value));
522 already_loaded_ct_.insert(encoding[j].
ct);
523 already_loaded_ct_.insert(encoding[j + 1].
ct);
524 values.insert(encoding[j].
value);
530 if (sat_solver->IsModelUnsat())
return;
538 for (
const auto equality : encoding) {
540 const class Literal eq = encoder->GetOrCreateLiteralAssociatedToEquality(
541 integers_[i], IntegerValue(equality.value));
542 if (equality.is_equality) {
548 ++num_half_equalities;
549 already_loaded_ct_.insert(equality.ct);
550 is_half_encoding_ct_.insert(equality.ct);
555 if (encoder->VariableIsFullyEncoded(integers_[i])) {
558 ++num_partially_encoded;
563 if (num_constraints > 0) {
564 VLOG(1) << num_equalities <<
" literals associated to VAR == value, and "
565 << num_half_equalities <<
" half-associations.";
567 if (num_fully_encoded > 0) {
568 VLOG(1) <<
"num_fully_encoded_variables: " << num_fully_encoded;
570 if (num_partially_encoded > 0) {
571 VLOG(1) <<
"num_partially_encoded_variables: " << num_partially_encoded;
581 int64_t num_associations = 0;
582 int64_t num_set_to_false = 0;
583 for (
const ConstraintProto&
ct :
model_proto.constraints()) {
584 if (!
ct.enforcement_literal().empty())
continue;
585 if (
ct.constraint_case() != ConstraintProto::kLinear)
continue;
586 if (
ct.linear().vars_size() != 2)
continue;
587 if (!ConstraintIsEq(
ct.linear()))
continue;
589 const IntegerValue rhs(
ct.linear().domain(0));
592 IntegerVariable var1 =
Integer(
ct.linear().vars(0));
593 IntegerVariable var2 =
Integer(
ct.linear().vars(1));
594 IntegerValue coeff1(
ct.linear().coeffs(0));
595 IntegerValue coeff2(
ct.linear().coeffs(1));
607 if (coeff1 == 0 || coeff2 == 0)
continue;
612 for (
int i = 0; i < 2; ++i) {
613 for (
const auto value_literal :
614 encoder->PartialGreaterThanEncoding(var1)) {
615 const IntegerValue value1 = value_literal.first;
616 const IntegerValue bound2 =
FloorRatio(rhs - value1 * coeff1, coeff2);
618 encoder->AssociateToIntegerLiteral(
630 for (
int i = 0; i < 2; ++i) {
631 for (
const auto value_literal : encoder->PartialDomainEncoding(var1)) {
632 const IntegerValue value1 = value_literal.value;
633 const IntegerValue intermediate = rhs - value1 * coeff1;
634 if (intermediate % coeff2 != 0) {
637 sat_solver->AddUnitClause(value_literal.literal.Negated());
642 intermediate / coeff2);
649 if (num_associations > 0) {
650 VLOG(1) <<
"Num associations from equivalences = " << num_associations;
652 if (num_set_to_false > 0) {
653 VLOG(1) <<
"Num literals set to false from equivalences = "
661 if (!
parameters.use_optional_variables())
return;
662 if (
parameters.enumerate_all_solutions())
return;
665 const int num_proto_variables =
model_proto.variables_size();
666 std::vector<bool> already_seen(num_proto_variables,
false);
668 for (
const int ref :
model_proto.objective().vars()) {
681 std::vector<std::vector<int>> enforcement_intersection(num_proto_variables);
682 std::set<int> literals_set;
683 for (
int c = 0; c <
model_proto.constraints_size(); ++c) {
685 if (
ct.enforcement_literal().empty()) {
687 already_seen[
var] =
true;
688 enforcement_intersection[
var].clear();
691 literals_set.clear();
692 literals_set.insert(
ct.enforcement_literal().begin(),
693 ct.enforcement_literal().end());
695 if (!already_seen[
var]) {
696 enforcement_intersection[
var].assign(
ct.enforcement_literal().begin(),
697 ct.enforcement_literal().end());
700 std::vector<int>& vector_ref = enforcement_intersection[
var];
702 for (
const int literal : vector_ref) {
704 vector_ref[new_size++] =
literal;
707 vector_ref.resize(new_size);
709 already_seen[
var] =
true;
715 int num_optionals = 0;
717 for (
int var = 0;
var < num_proto_variables; ++
var) {
718 const IntegerVariableProto& var_proto =
model_proto.variables(
var);
719 const int64_t
min = var_proto.domain(0);
720 const int64_t
max = var_proto.domain(var_proto.domain().size() - 1);
722 if (
min == 0 &&
max == 1)
continue;
723 if (enforcement_intersection[
var].empty())
continue;
726 integer_trail->MarkIntegerVariableAsOptional(
729 VLOG(2) <<
"Auto-detected " << num_optionals <<
" optional variables.";
741 parameters_(*(
model->GetOrCreate<SatParameters>())),
750 DEFINE_INT_TYPE(ConstraintIndex, int32_t);
753 void Register(ConstraintIndex ct_index,
int variable) {
755 constraint_is_registered_[ct_index] =
true;
756 if (variable_watchers_.size() <= variable) {
757 variable_watchers_.resize(variable + 1);
758 variable_was_added_in_to_propagate_.resize(variable + 1);
760 variable_watchers_[variable].push_back(ct_index);
763 void AddVariableToPropagationQueue(
int variable) {
765 if (variable_was_added_in_to_propagate_.size() <= variable) {
766 variable_watchers_.resize(variable + 1);
767 variable_was_added_in_to_propagate_.resize(variable + 1);
769 if (!variable_was_added_in_to_propagate_[variable]) {
770 variable_was_added_in_to_propagate_[variable] =
true;
771 variables_to_propagate_.push_back(variable);
776 const bool IsFullyEncoded(
int v) {
777 const IntegerVariable variable = mapping_->
Integer(v);
779 return integer_trail_->
IsFixed(variable) ||
783 const bool VariableIsFixed(
int v) {
784 const IntegerVariable variable = mapping_->
Integer(v);
786 return integer_trail_->
IsFixed(variable);
789 void FullyEncode(
int v) {
791 const IntegerVariable variable = mapping_->
Integer(v);
793 if (!integer_trail_->
IsFixed(variable)) {
796 AddVariableToPropagationQueue(v);
799 bool ProcessConstraint(ConstraintIndex ct_index);
800 bool ProcessElement(ConstraintIndex ct_index);
801 bool ProcessTable(ConstraintIndex ct_index);
802 bool ProcessAutomaton(ConstraintIndex ct_index);
803 bool ProcessLinear(ConstraintIndex ct_index);
805 const CpModelProto& model_proto_;
806 const SatParameters& parameters_;
809 CpModelMapping* mapping_;
810 IntegerEncoder* integer_encoder_;
811 IntegerTrail* integer_trail_;
813 std::vector<bool> variable_was_added_in_to_propagate_;
814 std::vector<int> variables_to_propagate_;
815 std::vector<std::vector<ConstraintIndex>> variable_watchers_;
820 absl::flat_hash_map<int, absl::flat_hash_set<int>>
821 variables_to_equal_or_diff_variables_;
827 const int num_constraints = model_proto_.constraints_size();
828 const int num_vars = model_proto_.variables_size();
829 constraint_is_finished_.
assign(num_constraints,
false);
830 constraint_is_registered_.
assign(num_constraints,
false);
833 for (ConstraintIndex ct_index(0); ct_index < num_constraints; ++ct_index) {
834 constraint_is_finished_[ct_index] = ProcessConstraint(ct_index);
844 int num_variables_fully_encoded_by_heuristics = 0;
845 for (
int var = 0;
var < num_vars; ++
var) {
847 const IntegerVariableProto& int_var_proto = model_proto_.variables(
var);
849 int64_t domain_size = domain.
Size();
850 int64_t num_diff_or_equal_var_constraints = 0;
851 int64_t num_potential_encoded_values_without_bounds = 0;
853 if (domain_size <= 2)
continue;
855 const absl::flat_hash_set<int64_t>& value_set =
857 for (
const int value : value_set) {
860 num_potential_encoded_values_without_bounds++;
864 const auto& it = variables_to_equal_or_diff_variables_.find(
var);
865 if (it != variables_to_equal_or_diff_variables_.end()) {
866 num_diff_or_equal_var_constraints = it->second.size();
869 if (num_potential_encoded_values_without_bounds >= domain_size / 2 ||
870 (num_diff_or_equal_var_constraints >= domain_size / 2 &&
872 VLOG(3) << model_proto_.variables(
var).ShortDebugString()
873 <<
" is encoded with "
874 << num_potential_encoded_values_without_bounds
875 <<
" unary constraints, and " << num_diff_or_equal_var_constraints
876 <<
" binary constraints on a domain of size " << domain_size;
878 num_variables_fully_encoded_by_heuristics++;
881 if (num_variables_fully_encoded_by_heuristics > 0) {
882 VLOG(2) << num_variables_fully_encoded_by_heuristics
883 <<
" variables fully encoded after model introspection.";
887 for (
int v = 0; v < variable_watchers_.size(); v++) {
888 if (!variable_watchers_[v].empty() && IsFullyEncoded(v)) {
889 AddVariableToPropagationQueue(v);
894 while (!variables_to_propagate_.empty()) {
895 const int variable = variables_to_propagate_.back();
896 variables_to_propagate_.pop_back();
897 for (
const ConstraintIndex ct_index : variable_watchers_[variable]) {
898 if (constraint_is_finished_[ct_index])
continue;
899 constraint_is_finished_[ct_index] = ProcessConstraint(ct_index);
905 bool FullEncodingFixedPointComputer::ProcessConstraint(
906 ConstraintIndex ct_index) {
907 const ConstraintProto&
ct = model_proto_.constraints(ct_index.value());
908 switch (
ct.constraint_case()) {
909 case ConstraintProto::ConstraintProto::kElement:
910 return ProcessElement(ct_index);
911 case ConstraintProto::ConstraintProto::kTable:
912 return ProcessTable(ct_index);
913 case ConstraintProto::ConstraintProto::kAutomaton:
914 return ProcessAutomaton(ct_index);
915 case ConstraintProto::ConstraintProto::kLinear:
916 return ProcessLinear(ct_index);
922 bool FullEncodingFixedPointComputer::ProcessElement(ConstraintIndex ct_index) {
923 const ConstraintProto&
ct = model_proto_.constraints(ct_index.value());
926 FullyEncode(
ct.element().index());
928 const int target =
ct.element().target();
931 if (VariableIsFixed(target))
return true;
934 if (IsFullyEncoded(target)) {
935 for (
const int v :
ct.element().vars()) FullyEncode(v);
939 bool all_variables_are_fully_encoded =
true;
940 for (
const int v :
ct.element().vars()) {
941 if (v == target)
continue;
942 if (!IsFullyEncoded(v)) {
943 all_variables_are_fully_encoded =
false;
947 if (all_variables_are_fully_encoded) {
948 if (!IsFullyEncoded(target)) FullyEncode(target);
953 if (constraint_is_registered_[ct_index]) {
954 for (
const int v :
ct.element().vars()) Register(ct_index, v);
955 Register(ct_index, target);
960 bool FullEncodingFixedPointComputer::ProcessTable(ConstraintIndex ct_index) {
961 const ConstraintProto&
ct = model_proto_.constraints(ct_index.value());
963 if (
ct.table().negated())
return true;
965 for (
const int variable :
ct.table().vars()) {
966 FullyEncode(variable);
972 bool FullEncodingFixedPointComputer::ProcessAutomaton(
973 ConstraintIndex ct_index) {
974 const ConstraintProto&
ct = model_proto_.constraints(ct_index.value());
975 for (
const int variable :
ct.automaton().vars()) {
976 FullyEncode(variable);
981 bool FullEncodingFixedPointComputer::ProcessLinear(ConstraintIndex ct_index) {
984 const ConstraintProto&
ct = model_proto_.constraints(ct_index.value());
985 if (parameters_.boolean_encoding_level() == 0 ||
986 ct.linear().vars_size() != 2) {
990 if (!ConstraintIsEq(
ct.linear()) &&
991 !ConstraintIsNEq(
ct.linear(), mapping_, integer_trail_,
nullptr)) {
995 const int var0 =
ct.linear().vars(0);
996 const int var1 =
ct.linear().vars(1);
997 if (!IsFullyEncoded(var0)) {
998 variables_to_equal_or_diff_variables_[var0].insert(var1);
1000 if (!IsFullyEncoded(var1)) {
1001 variables_to_equal_or_diff_variables_[var1].insert(var0);
1017 std::vector<Literal> literals = mapping->
Literals(
ct.bool_or().literals());
1018 for (
const int ref :
ct.enforcement_literal()) {
1019 literals.push_back(mapping->Literal(ref).Negated());
1026 std::vector<Literal> literals;
1027 for (
const int ref :
ct.enforcement_literal()) {
1028 literals.push_back(mapping->Literal(ref).Negated());
1031 for (
const Literal literal : mapping->Literals(
ct.bool_and().literals())) {
1034 literals.pop_back();
1060 void LoadEquivalenceAC(
const std::vector<Literal> enforcement_literal,
1061 IntegerValue coeff1, IntegerVariable var1,
1062 IntegerValue coeff2, IntegerVariable var2,
1063 const IntegerValue rhs, Model* m) {
1064 auto* encoder = m->GetOrCreate<IntegerEncoder>();
1065 CHECK(encoder->VariableIsFullyEncoded(var1));
1066 CHECK(encoder->VariableIsFullyEncoded(var2));
1067 absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
1068 for (
const auto value_literal : encoder->FullDomainEncoding(var1)) {
1069 term1_value_to_literal[coeff1 * value_literal.value] =
1070 value_literal.literal;
1072 for (
const auto value_literal : encoder->FullDomainEncoding(var2)) {
1073 const IntegerValue target = rhs - value_literal.value * coeff2;
1076 {value_literal.literal.Negated()}));
1078 const Literal target_literal = term1_value_to_literal[target];
1080 {value_literal.literal.Negated(), target_literal}));
1082 {value_literal.literal, target_literal.Negated()}));
1086 term1_value_to_literal.erase(target);
1092 std::vector<Literal> implied_false;
1093 for (
const auto entry : term1_value_to_literal) {
1094 implied_false.push_back(entry.second);
1096 std::sort(implied_false.begin(), implied_false.end());
1097 for (
const Literal l : implied_false) {
1104 void LoadEquivalenceNeqAC(
const std::vector<Literal> enforcement_literal,
1105 IntegerValue coeff1, IntegerVariable var1,
1106 IntegerValue coeff2, IntegerVariable var2,
1107 const IntegerValue rhs, Model* m) {
1108 auto* encoder = m->GetOrCreate<IntegerEncoder>();
1109 CHECK(encoder->VariableIsFullyEncoded(var1));
1110 CHECK(encoder->VariableIsFullyEncoded(var2));
1111 absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
1112 for (
const auto value_literal : encoder->FullDomainEncoding(var1)) {
1113 term1_value_to_literal[coeff1 * value_literal.value] =
1114 value_literal.literal;
1116 for (
const auto value_literal : encoder->FullDomainEncoding(var2)) {
1117 const IntegerValue target_value = rhs - value_literal.value * coeff2;
1118 const auto& it = term1_value_to_literal.find(target_value);
1119 if (it != term1_value_to_literal.end()) {
1120 const Literal target_literal = it->second;
1122 enforcement_literal,
1123 {value_literal.literal.Negated(), target_literal.Negated()}));
1132 if (
ct.linear().vars().empty()) {
1136 std::vector<Literal> clause;
1137 for (
const int ref :
ct.enforcement_literal()) {
1138 clause.push_back(mapping->Literal(ref).Negated());
1142 VLOG(1) <<
"Trivially UNSAT constraint: " <<
ct.DebugString();
1149 const std::vector<IntegerVariable> vars =
1150 mapping->Integers(
ct.linear().vars());
1151 const std::vector<int64_t> coeffs = ValuesFromProto(
ct.linear().coeffs());
1157 IntegerValue min_sum(0);
1158 IntegerValue max_sum(0);
1159 IntegerValue max_domain_size(0);
1160 bool all_booleans =
true;
1161 for (
int i = 0; i < vars.size(); ++i) {
1162 if (all_booleans && !mapping->IsBoolean(
ct.linear().vars(i))) {
1163 all_booleans =
false;
1165 const IntegerValue lb = integer_trail->LowerBound(vars[i]);
1166 const IntegerValue ub = integer_trail->UpperBound(vars[i]);
1167 max_domain_size =
std::max(max_domain_size, ub - lb + 1);
1168 const IntegerValue term_a = coeffs[i] * lb;
1169 const IntegerValue term_b = coeffs[i] * ub;
1170 min_sum +=
std::min(term_a, term_b);
1171 max_sum +=
std::max(term_a, term_b);
1174 if (
ct.linear().vars_size() == 2 && !integer_trail->IsFixed(vars[0]) &&
1175 !integer_trail->IsFixed(vars[1]) && max_domain_size < 16) {
1176 const SatParameters& params = *m->
GetOrCreate<SatParameters>();
1178 if (params.boolean_encoding_level() > 0 && ConstraintIsEq(
ct.linear()) &&
1179 ct.linear().domain(0) != min_sum &&
ct.linear().domain(0) != max_sum &&
1180 encoder->VariableIsFullyEncoded(vars[0]) &&
1181 encoder->VariableIsFullyEncoded(vars[1])) {
1182 VLOG(3) <<
"Load AC version of " <<
ct.DebugString() <<
", var0 domain = "
1183 << integer_trail->InitialVariableDomain(vars[0])
1184 <<
", var1 domain = "
1185 << integer_trail->InitialVariableDomain(vars[1]);
1186 return LoadEquivalenceAC(mapping->Literals(
ct.enforcement_literal()),
1187 IntegerValue(coeffs[0]), vars[0],
1188 IntegerValue(coeffs[1]), vars[1],
1189 IntegerValue(
ct.linear().domain(0)), m);
1192 int64_t single_value = 0;
1193 if (params.boolean_encoding_level() > 0 &&
1194 ConstraintIsNEq(
ct.linear(), mapping, integer_trail, &single_value) &&
1195 single_value != min_sum && single_value != max_sum &&
1196 encoder->VariableIsFullyEncoded(vars[0]) &&
1197 encoder->VariableIsFullyEncoded(vars[1])) {
1198 VLOG(3) <<
"Load NAC version of " <<
ct.DebugString()
1199 <<
", var0 domain = "
1200 << integer_trail->InitialVariableDomain(vars[0])
1201 <<
", var1 domain = "
1202 << integer_trail->InitialVariableDomain(vars[1])
1203 <<
", value = " << single_value;
1204 return LoadEquivalenceNeqAC(mapping->Literals(
ct.enforcement_literal()),
1205 IntegerValue(coeffs[0]), vars[0],
1206 IntegerValue(coeffs[1]), vars[1],
1207 IntegerValue(single_value), m);
1211 if (
ct.linear().domain_size() == 2) {
1212 int64_t lb =
ct.linear().domain(0);
1213 int64_t ub =
ct.linear().domain(1);
1221 std::vector<LiteralWithCoeff> cst;
1222 for (
int i = 0; i < vars.size(); ++i) {
1223 const int ref =
ct.linear().vars(i);
1224 cst.push_back({mapping->Literal(ref), coeffs[i]});
1236 const std::vector<Literal> enforcement_literals =
1237 mapping->Literals(
ct.enforcement_literal());
1250 const bool special_case =
1251 ct.enforcement_literal().empty() &&
ct.linear().domain_size() == 4;
1253 std::vector<Literal> clause;
1254 for (
int i = 0; i <
ct.linear().domain_size(); i += 2) {
1255 int64_t lb =
ct.linear().domain(i);
1256 int64_t ub =
ct.linear().domain(i + 1);
1260 const Literal subdomain_literal(
1261 special_case && i > 0 ? clause.back().Negated()
1263 clause.push_back(subdomain_literal);
1274 for (
const int ref :
ct.enforcement_literal()) {
1275 clause.push_back(mapping->Literal(ref).Negated());
1283 const std::vector<IntegerVariable> vars =
1289 int num_fully_encoded = 0;
1290 int64_t max_domain_size = 0;
1291 for (
const IntegerVariable variable : vars) {
1292 if (encoder->VariableIsFullyEncoded(variable)) num_fully_encoded++;
1294 IntegerValue lb = integer_trail->
LowerBound(variable);
1295 IntegerValue ub = integer_trail->
UpperBound(variable);
1296 const int64_t domain_size = ub.value() - lb.value() + 1;
1297 max_domain_size =
std::max(max_domain_size, domain_size);
1300 if (num_fully_encoded == vars.size() && max_domain_size < 1024) {
1310 const IntegerVariable prod = mapping->
Integer(
ct.int_prod().target());
1311 const std::vector<IntegerVariable> vars =
1312 mapping->Integers(
ct.int_prod().vars());
1313 CHECK_EQ(vars.size(), 2) <<
"General int_prod not supported yet.";
1319 const IntegerVariable div = mapping->
Integer(
ct.int_div().target());
1320 const std::vector<IntegerVariable> vars =
1321 mapping->Integers(
ct.int_div().vars());
1323 const IntegerValue denom(m->
Get(
Value(vars[1])));
1336 const IntegerVariable
min = mapping->Integer(
ct.int_min().target());
1337 const std::vector<IntegerVariable> vars =
1338 mapping->Integers(
ct.int_min().vars());
1346 for (
int j = 0; j < expr_proto.coeffs_size(); ++j) {
1347 expr.
coeffs.push_back(IntegerValue(expr_proto.coeffs(j)));
1349 expr.
offset = IntegerValue(expr_proto.offset());
1357 std::vector<LinearExpression> negated_exprs;
1358 negated_exprs.reserve(
ct.lin_max().exprs_size());
1359 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
1360 negated_exprs.push_back(
1369 const IntegerVariable
max = mapping->Integer(
ct.int_max().target());
1370 const std::vector<IntegerVariable> vars =
1371 mapping->Integers(
ct.int_max().vars());
1381 if (
ct.no_overlap_2d().x_intervals().empty())
return;
1383 const std::vector<IntervalVariable> x_intervals =
1384 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
1385 const std::vector<IntervalVariable> y_intervals =
1386 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
1388 x_intervals, y_intervals,
1389 !
ct.no_overlap_2d().boxes_with_null_area_can_overlap()));
1394 const std::vector<IntervalVariable> intervals =
1397 std::vector<AffineExpression> demands;
1398 for (
const IntegerVariable
var :
1399 mapping->Integers(
ct.cumulative().demands())) {
1408 std::vector<AffineExpression> times;
1409 std::vector<IntegerValue> deltas;
1410 std::vector<Literal> presences;
1411 const int size =
ct.reservoir().times().size();
1412 for (
int i = 0; i < size; ++i) {
1413 times.push_back(mapping->Integer(
ct.reservoir().times(i)));
1414 deltas.push_back(IntegerValue(
ct.reservoir().demands(i)));
1415 if (!
ct.reservoir().actives().empty()) {
1416 presences.push_back(mapping->Literal(
ct.reservoir().actives(i)));
1418 presences.push_back(encoder->GetTrueLiteral());
1422 ct.reservoir().max_level(), m);
1434 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1435 const IntegerVariable target = mapping->Integer(
ct.element().target());
1436 const std::vector<IntegerVariable> vars =
1437 mapping->Integers(
ct.element().vars());
1441 Domain union_of_non_constant_domains;
1442 std::map<IntegerValue, int> constant_to_num;
1444 const int i = literal_value.value.value();
1447 constant_to_num[
value]++;
1449 union_of_non_constant_domains = union_of_non_constant_domains.
UnionWith(
1450 integer_trail->InitialVariableDomain(vars[i]));
1455 for (
const auto entry : constant_to_num) {
1456 if (union_of_non_constant_domains.
Contains(entry.first.value())) {
1457 constant_to_num[entry.first]++;
1463 bool is_one_to_one_mapping =
true;
1465 const int i = literal_value.value.value();
1467 is_one_to_one_mapping =
false;
1472 if (constant_to_num[
value] == 1) {
1473 const Literal r = literal_value.literal;
1474 encoder->AssociateToIntegerEqualValue(r, target,
value);
1476 is_one_to_one_mapping =
false;
1480 return is_one_to_one_mapping;
1488 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1489 const IntegerVariable target = mapping->Integer(
ct.element().target());
1490 const std::vector<IntegerVariable> vars =
1491 mapping->Integers(
ct.element().vars());
1496 std::vector<Literal> selectors;
1497 std::vector<IntegerVariable> possible_vars;
1498 for (
const auto literal_value : encoding) {
1499 const int i = literal_value.value.value();
1502 possible_vars.push_back(vars[i]);
1503 selectors.push_back(literal_value.literal);
1504 const Literal r = literal_value.literal;
1506 if (vars[i] == target)
continue;
1540 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1541 const IntegerVariable target = mapping->Integer(
ct.element().target());
1542 const std::vector<IntegerVariable> vars =
1543 mapping->Integers(
ct.element().vars());
1547 absl::flat_hash_map<IntegerValue, Literal> target_map;
1549 for (
const auto literal_value : target_encoding) {
1550 target_map[literal_value.value] = literal_value.literal;
1555 absl::flat_hash_map<IntegerValue, std::vector<Literal>> value_to_literals;
1558 for (
const auto literal_value : index_encoding) {
1559 const int i = literal_value.value.value();
1560 const Literal i_lit = literal_value.literal;
1564 value_to_literals[integer_trail->
LowerBound(vars[i])].push_back(i_lit);
1569 std::vector<Literal> var_selected_literals;
1570 for (
const auto var_literal_value : var_encoding) {
1571 const IntegerValue
value = var_literal_value.value;
1572 const Literal var_is_value = var_literal_value.literal;
1581 const Literal var_is_value_and_selected =
1584 value_to_literals[
value].push_back(var_is_value_and_selected);
1585 var_selected_literals.push_back(var_is_value_and_selected);
1592 for (
const auto& entry : target_map) {
1593 const IntegerValue
value = entry.first;
1594 const Literal target_is_value = entry.second;
1612 void LoadElementConstraintHalfAC(
const ConstraintProto&
ct, Model* m) {
1613 auto* mapping = m->GetOrCreate<CpModelMapping>();
1614 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1615 const IntegerVariable target = mapping->Integer(
ct.element().target());
1616 const std::vector<IntegerVariable> vars =
1617 mapping->Integers(
ct.element().vars());
1623 const int i = value_literal.value.value();
1625 LoadEquivalenceAC({value_literal.literal}, IntegerValue(1), vars[i],
1626 IntegerValue(-1), target, IntegerValue(0), m);
1630 void LoadBooleanElement(
const ConstraintProto&
ct, Model* m) {
1631 auto* mapping = m->GetOrCreate<CpModelMapping>();
1632 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1633 const std::vector<Literal> literals = mapping->Literals(
ct.element().vars());
1634 const Literal target = mapping->Literal(
ct.element().target());
1641 std::vector<Literal> all_true;
1642 std::vector<Literal> all_false;
1644 const Literal a_lit = literals[value_literal.value.value()];
1645 const Literal i_lit = value_literal.literal;
1648 all_true.push_back(a_lit.Negated());
1649 all_false.push_back(a_lit);
1651 all_true.push_back(target);
1652 all_false.push_back(target.Negated());
1662 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1664 bool boolean_array =
true;
1665 for (
const int ref :
ct.element().vars()) {
1666 if (!mapping->IsBoolean(ref)) {
1667 boolean_array =
false;
1671 if (boolean_array && !mapping->IsBoolean(
ct.element().target())) {
1673 VLOG(1) <<
"Fix boolean_element not propagated on target";
1674 boolean_array =
false;
1679 if (boolean_array) {
1680 LoadBooleanElement(
ct, m);
1684 const IntegerVariable target = mapping->Integer(
ct.element().target());
1685 const std::vector<IntegerVariable> vars =
1686 mapping->Integers(
ct.element().vars());
1715 int num_AC_variables = 0;
1716 const int num_vars =
ct.element().vars().size();
1717 for (
const int v :
ct.element().vars()) {
1718 IntegerVariable variable = mapping->Integer(v);
1719 const bool is_full =
1721 if (is_full) num_AC_variables++;
1724 const SatParameters& params = *m->
GetOrCreate<SatParameters>();
1725 if (params.boolean_encoding_level() > 0 &&
1726 (target_is_AC || num_AC_variables >= num_vars - 1)) {
1727 if (params.boolean_encoding_level() > 1) {
1730 LoadElementConstraintHalfAC(
ct, m);
1739 const std::vector<IntegerVariable> vars =
1741 const std::vector<int64_t> values = ValuesFromProto(
ct.table().values());
1742 const int num_vars = vars.size();
1743 const int num_tuples = values.size() / num_vars;
1744 std::vector<std::vector<int64_t>> tuples(num_tuples);
1746 for (
int i = 0; i < num_tuples; ++i) {
1747 for (
int j = 0; j < num_vars; ++j) {
1748 tuples[i].push_back(values[count++]);
1751 if (
ct.table().negated()) {
1760 const std::vector<IntegerVariable> vars =
1763 const int num_transitions =
ct.automaton().transition_tail_size();
1764 std::vector<std::vector<int64_t>> transitions;
1765 transitions.reserve(num_transitions);
1766 for (
int i = 0; i < num_transitions; ++i) {
1767 transitions.push_back({
ct.automaton().transition_tail(i),
1768 ct.automaton().transition_label(i),
1769 ct.automaton().transition_head(i)});
1772 const int64_t starting_state =
ct.automaton().starting_state();
1773 const std::vector<int64_t> final_states =
1774 ValuesFromProto(
ct.automaton().final_states());
1781 const std::vector<IntegerVariable>& vars,
Model* m) {
1782 const int n = vars.size();
1787 std::vector<std::vector<Literal>> matrix(
1788 n, std::vector<Literal>(n, kFalseLiteral));
1789 for (
int i = 0; i < n; i++) {
1790 for (
int j = 0; j < n; j++) {
1795 matrix[i][
value] = kTrueLiteral;
1798 for (
const auto& entry : encoding) {
1799 const int value = entry.value.value();
1802 matrix[i][
value] = entry.literal;
1811 const auto& circuit =
ct.circuit();
1812 if (circuit.tails().empty())
return;
1814 std::vector<int> tails(circuit.tails().begin(), circuit.tails().end());
1815 std::vector<int> heads(circuit.heads().begin(), circuit.heads().end());
1816 std::vector<Literal> literals =
1818 const int num_nodes =
ReindexArcs(&tails, &heads);
1823 const auto& routes =
ct.routes();
1824 if (routes.tails().empty())
return;
1826 std::vector<int> tails(routes.tails().begin(), routes.tails().end());
1827 std::vector<int> heads(routes.heads().begin(), routes.heads().end());
1828 std::vector<Literal> literals =
1830 const int num_nodes =
ReindexArcs(&tails, &heads);
1836 switch (
ct.constraint_case()) {
1837 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
1839 case ConstraintProto::ConstraintCase::kBoolOr:
1842 case ConstraintProto::ConstraintCase::kBoolAnd:
1845 case ConstraintProto::ConstraintCase::kAtMostOne:
1848 case ConstraintProto::ConstraintCase::kExactlyOne:
1851 case ConstraintProto::ConstraintCase::kBoolXor:
1854 case ConstraintProto::ConstraintProto::kLinear:
1857 case ConstraintProto::ConstraintProto::kAllDiff:
1860 case ConstraintProto::ConstraintProto::kIntProd:
1863 case ConstraintProto::ConstraintProto::kIntDiv:
1866 case ConstraintProto::ConstraintProto::kIntMin:
1869 case ConstraintProto::ConstraintProto::kLinMax:
1872 case ConstraintProto::ConstraintProto::kIntMax:
1875 case ConstraintProto::ConstraintProto::kInterval:
1878 case ConstraintProto::ConstraintProto::kNoOverlap:
1881 case ConstraintProto::ConstraintProto::kNoOverlap2D:
1884 case ConstraintProto::ConstraintProto::kCumulative:
1887 case ConstraintProto::ConstraintProto::kReservoir:
1890 case ConstraintProto::ConstraintProto::kElement:
1893 case ConstraintProto::ConstraintProto::kTable:
1896 case ConstraintProto::ConstraintProto::kAutomaton:
1899 case ConstraintProto::ConstraintProto::kCircuit:
1902 case ConstraintProto::ConstraintProto::kRoutes:
#define DCHECK_LE(val1, val2)
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define VLOG(verboselevel)
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
void push_back(const value_type &x)
We call domain any subset of Int64 = [kint64min, kint64max].
Domain InverseMultiplicationBy(const int64_t coeff) const
Returns {x ∈ Int64, ∃ e ∈ D, x * coeff = e}.
Domain Complement() const
Returns the set Int64 ∖ D.
bool Contains(int64_t value) const
Returns true iff value is in Domain.
int NumIntervals() const
Basic read-only std::vector<> wrapping to view a Domain as a sorted list of non-adjacent intervals.
int64_t Size() const
Returns the number of elements in the domain.
Domain UnionWith(const Domain &domain) const
Returns the union of D and domain.
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
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.
std::vector< sat::Literal > Literals(const ProtoIndices &indices) const
AffineExpression LoadAffineView(const LinearExpressionProto &exp) const
std::vector< IntegerVariable > Integers(const List &list) const
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
bool IsBoolean(int ref) const
void LoadBooleanSymmetries(const CpModelProto &model_proto, Model *m)
bool IsInteger(int ref) const
const absl::flat_hash_set< int64_t > & PotentialEncodedValues(int var)
bool ConstraintIsAlreadyLoaded(const ConstraintProto *ct) const
IntegerVariable Integer(int ref) const
sat::Literal Literal(int ref) const
void DetectOptionalVariables(const CpModelProto &model_proto, Model *m)
void ExtractEncoding(const CpModelProto &model_proto, Model *m)
void PropagateEncodingFromEquivalenceRelations(const CpModelProto &model_proto, Model *m)
void CreateVariables(const CpModelProto &model_proto, bool view_all_booleans_as_integers, Model *m)
FullEncodingFixedPointComputer(const CpModelProto &model_proto, Model *model)
void AssociateToIntegerEqualValue(Literal literal, IntegerVariable var, IntegerValue value)
bool VariableIsFullyEncoded(IntegerVariable var) const
void ReserveSpaceForNumVariables(int num_vars)
bool IsFixed(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
LiteralIndex Index() const
Class that owns everything related to a particular optimization model.
T Get(std::function< T(const Model &)> f) const
Similar to Add() but this is const.
T Add(std::function< T(Model *)> f)
This makes it possible to have a nicer API on the client side, and it allows both of these forms:
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
bool AddProblemClause(absl::Span< const Literal > literals)
CpModelProto const * model_proto
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
bool ContainsKey(const Collection &collection, const Key &key)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
void AddReservoirConstraint(std::vector< AffineExpression > times, std::vector< IntegerValue > deltas, std::vector< Literal > presences, int64_t min_level, int64_t max_level, Model *model)
void LoadTableConstraint(const ConstraintProto &ct, Model *m)
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
std::function< void(Model *)> AllDifferentAC(const std::vector< IntegerVariable > &variables)
std::function< void(Model *)> IsEqualToMaxOf(IntegerVariable max_var, const std::vector< IntegerVariable > &vars)
void LoadExactlyOneConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
std::function< IntervalVariable(Model *)> NewInterval(int64_t min_start, int64_t max_end, int64_t size)
std::function< void(Model *)> ExactlyOneConstraint(const std::vector< Literal > &literals)
void LoadIntProdConstraint(const ConstraintProto &ct, Model *m)
bool LoadConstraint(const ConstraintProto &ct, Model *m)
std::vector< int > UsedVariables(const ConstraintProto &ct)
void LoadBoolOrConstraint(const ConstraintProto &ct, Model *m)
bool RefIsPositive(int ref)
std::function< void(Model *)> DivisionConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable c)
std::function< void(Model *)> ConditionalWeightedSumLowerOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
void MaybeFullyEncodeMoreVariables(const CpModelProto &model_proto, Model *m)
const LiteralIndex kNoLiteralIndex(-1)
std::function< void(Model *)> PartialIsOneOfVar(IntegerVariable target_var, const std::vector< IntegerVariable > &vars, const std::vector< Literal > &selectors)
std::function< void(Model *)> LiteralXorIs(const std::vector< Literal > &literals, bool value)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
std::function< int64_t(const Model &)> Value(IntegerVariable v)
std::function< void(Model *)> SubcircuitConstraint(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, bool multiple_subcircuit_through_zero)
void AddNegatedTableConstraint(absl::Span< const IntegerVariable > vars, std::vector< std::vector< int64_t >> tuples, Model *model)
bool HasEnforcementLiteral(const ConstraintProto &ct)
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< IntegerVariable > &vars)
std::function< std::vector< IntegerEncoder::ValueLiteralPair >Model *)> FullyEncodeVariable(IntegerVariable var)
bool DetectEquivalencesInElementConstraint(const ConstraintProto &ct, Model *m)
void LoadCumulativeConstraint(const ConstraintProto &ct, Model *m)
void LoadRoutesConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ConditionalWeightedSumGreaterOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
void LoadReservoirConstraint(const ConstraintProto &ct, Model *m)
void LoadBoolAndConstraint(const ConstraintProto &ct, Model *m)
void LoadLinMaxConstraint(const ConstraintProto &ct, Model *m)
void LoadBoolXorConstraint(const ConstraintProto &ct, Model *m)
LinearExpression GetExprFromProto(const LinearExpressionProto &expr_proto, const CpModelMapping &mapping)
const IntegerVariable kNoIntegerVariable(-1)
const IntervalVariable kNoIntervalVariable(-1)
LinearExpression CanonicalizeExpr(const LinearExpression &expr)
std::function< void(Model *)> Cumulative(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
std::function< void(Model *)> EnforcedClause(absl::Span< const Literal > enforcement_literals, absl::Span< const Literal > clause)
std::vector< std::vector< Literal > > GetSquareMatrixFromIntegerVariables(const std::vector< IntegerVariable > &vars, Model *m)
void LoadIntDivConstraint(const ConstraintProto &ct, Model *m)
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> Implication(const std::vector< Literal > &enforcement_literals, IntegerLiteral i)
std::function< void(Model *)> FixedDivisionConstraint(IntegerVariable a, IntegerValue b, IntegerVariable c)
std::function< void(Model *)> BooleanLinearConstraint(int64_t lower_bound, int64_t upper_bound, std::vector< LiteralWithCoeff > *cst)
int ReindexArcs(IntContainer *tails, IntContainer *heads)
std::function< void(Model *)> Disjunctive(const std::vector< IntervalVariable > &vars)
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
void LoadAtMostOneConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> AllDifferentBinary(const std::vector< IntegerVariable > &vars)
void LoadCircuitConstraint(const ConstraintProto &ct, Model *m)
void LoadIntMaxConstraint(const ConstraintProto &ct, Model *m)
void LoadNoOverlapConstraint(const ConstraintProto &ct, Model *m)
void LoadAllDiffConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ReifiedBoolAnd(const std::vector< Literal > &literals, Literal r)
std::function< void(Model *)> TransitionConstraint(const std::vector< IntegerVariable > &vars, const std::vector< std::vector< int64_t >> &automaton, int64_t initial_state, const std::vector< int64_t > &final_states)
void LoadElementConstraint(const ConstraintProto &ct, Model *m)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
void LoadAutomatonConstraint(const ConstraintProto &ct, Model *m)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> ImpliesInInterval(Literal in_interval, IntegerVariable v, int64_t lb, int64_t ub)
std::function< void(Model *)> Equality(IntegerVariable v, int64_t value)
void LoadNoOverlap2dConstraint(const ConstraintProto &ct, Model *m)
void LoadIntMinConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> AtMostOneConstraint(const std::vector< Literal > &literals)
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
std::function< void(Model *)> NonOverlappingRectangles(const std::vector< IntervalVariable > &x, const std::vector< IntervalVariable > &y, bool is_strict, bool add_cumulative_relaxation=true)
void AddTableConstraint(absl::Span< const IntegerVariable > vars, std::vector< std::vector< int64_t >> tuples, Model *model)
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64_t min_start, int64_t max_end, int64_t size, Literal is_present)
const BooleanVariable kNoBooleanVariable(-1)
std::function< void(Model *)> ConditionalLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_le)
std::function< void(Model *)> ProductConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable p)
void LoadElementConstraintAC(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
void LoadElementConstraintBounds(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ReifiedBoolOr(const std::vector< Literal > &literals, Literal r)
Collection of objects used to extend the Constraint Solver library.
std::vector< int > variables
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
std::vector< IntegerValue > coeffs
std::vector< IntegerVariable > vars
#define SOLVER_LOG(logger,...)
#define VLOG_IS_ON(verboselevel)