26#include "absl/container/flat_hash_map.h"
27#include "absl/container/flat_hash_set.h"
62template <
typename Values>
63std::vector<int64_t> ValuesFromProto(
const Values& values) {
64 return std::vector<int64_t>(values.begin(), values.end());
67void 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;
89bool ConstraintIsEq(
const LinearConstraintProto&
proto) {
94bool 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,
Model* m) {
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 mapping->reverse_boolean_map_.resize(num_proto_variables, -1);
135 for (
int i = 0; i < num_proto_variables; ++i) {
137 if (domain.size() != 2)
continue;
138 if (domain[0] >= 0 && domain[1] <= 1) {
139 mapping->booleans_[i] = new_var;
140 mapping->reverse_boolean_map_[new_var] = i;
141 if (domain[1] == 0) {
142 false_variables.push_back(new_var);
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;
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 mapping->reverse_integer_map_.resize(2 * var_to_instantiate_as_integer.size(),
208 for (
const int i : var_to_instantiate_as_integer) {
210 mapping->integers_[i] =
212 DCHECK_LT(mapping->integers_[i], mapping->reverse_integer_map_.size());
213 mapping->reverse_integer_map_[mapping->integers_[i]] = i;
220 for (
int i = 0; i < num_proto_variables; ++i) {
225 encoder->AssociateToIntegerEqualValue(
226 sat::Literal(mapping->booleans_[i],
true), mapping->integers_[i],
235 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kInterval) {
240 mapping->
Literal(
ct.enforcement_literal(0));
244 if (
ct.interval().has_start_view()) {
245 mapping->intervals_[c] = intervals_repository->CreateInterval(
246 mapping->LoadAffineView(
ct.interval().start_view()),
247 mapping->LoadAffineView(
ct.interval().end_view()),
248 mapping->LoadAffineView(
ct.interval().size_view()),
249 enforcement_literal.
Index(),
253 mapping->Integer(
ct.interval().start()),
254 mapping->Integer(
ct.interval().end()),
255 mapping->Integer(
ct.interval().size()), enforcement_literal));
258 if (
ct.interval().has_start_view()) {
259 mapping->intervals_[c] = intervals_repository->CreateInterval(
260 mapping->LoadAffineView(
ct.interval().start_view()),
261 mapping->LoadAffineView(
ct.interval().end_view()),
265 mapping->intervals_[c] =
267 mapping->Integer(
ct.interval().end()),
268 mapping->Integer(
ct.interval().size())));
271 mapping->already_loaded_ct_.insert(&
ct);
278 if (symmetry.permutations().empty())
return;
282 sat_solver->AddPropagator(symmetry_handler);
283 const int num_literals = 2 * sat_solver->NumVariables();
286 bool all_bool =
true;
287 for (
const int var : perm.support()) {
288 if (!mapping->IsBoolean(
var)) {
293 if (!all_bool)
continue;
296 auto literal_permutation =
297 absl::make_unique<SparsePermutation>(num_literals);
298 int support_index = 0;
299 const int num_cycle = perm.cycle_sizes().size();
300 for (
int i = 0; i < num_cycle; ++i) {
301 const int size = perm.cycle_sizes(i);
302 const int saved_support_index = support_index;
303 for (
int j = 0; j < size; ++j) {
304 const int var = perm.support(support_index++);
305 literal_permutation->AddToCurrentCycle(
306 mapping->Literal(
var).Index().value());
308 literal_permutation->CloseCurrentCycle();
312 support_index = saved_support_index;
313 for (
int j = 0; j < size; ++j) {
314 const int var = perm.support(support_index++);
315 literal_permutation->AddToCurrentCycle(
316 mapping->Literal(
var).NegatedIndex().value());
318 literal_permutation->CloseCurrentCycle();
320 symmetry_handler->AddSymmetry(std::move(literal_permutation));
324 symmetry_handler->num_permutations(),
325 " symmetry to the SAT solver.");
341 if (sat_solver->IsModelUnsat())
return;
346 struct EqualityDetectionHelper {
352 bool operator<(
const EqualityDetectionHelper& o)
const {
353 if (
literal.Variable() == o.literal.Variable()) {
354 if (
value == o.value)
return is_equality && !o.is_equality;
355 return value < o.value;
357 return literal.Variable() < o.literal.Variable();
360 std::vector<std::vector<EqualityDetectionHelper>> var_to_equalities(
372 struct InequalityDetectionHelper {
377 bool operator<(
const InequalityDetectionHelper& o)
const {
378 if (
literal.Variable() == o.literal.Variable()) {
379 return i_lit.
var < o.i_lit.var;
381 return literal.Variable() < o.literal.Variable();
384 std::vector<InequalityDetectionHelper> inequalities;
388 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kLinear) {
391 if (
ct.enforcement_literal().size() != 1)
continue;
392 if (
ct.linear().vars_size() != 1)
continue;
396 mapping->
Literal(
ct.enforcement_literal(0));
397 if (sat_solver->Assignment().LiteralIsFalse(enforcement_literal))
continue;
399 const int ref =
ct.linear().vars(0);
403 const Domain domain_if_enforced =
408 if (domain_if_enforced.
IsEmpty()) {
409 if (!sat_solver->AddUnitClause(enforcement_literal.
Negated()))
return;
415 if (domain_if_enforced.
Max() >= domain.
Max() &&
416 domain_if_enforced.
Min() > domain.
Min()) {
417 inequalities.push_back({&
ct, enforcement_literal,
419 mapping->Integer(
var),
420 IntegerValue(domain_if_enforced.
Min()))});
421 }
else if (domain_if_enforced.
Min() <= domain.
Min() &&
422 domain_if_enforced.
Max() < domain.
Max()) {
423 inequalities.push_back({&
ct, enforcement_literal,
425 mapping->Integer(
var),
426 IntegerValue(domain_if_enforced.
Max()))});
432 if (domain_if_enforced.
Min() > domain.
Min()) {
436 mapping->Integer(
var), IntegerValue(domain_if_enforced.
Min())));
438 if (domain_if_enforced.
Max() < domain.
Max()) {
442 IntegerValue(domain_if_enforced.
Max())));
453 var_to_equalities[
var].push_back(
454 {&
ct, enforcement_literal, inter.
Min(),
true});
456 mapping->variables_to_encoded_values_[
var].insert(inter.
Min());
464 var_to_equalities[
var].push_back(
465 {&
ct, enforcement_literal, inter.
Min(),
false});
467 mapping->variables_to_encoded_values_[
var].insert(inter.
Min());
474 int num_inequalities = 0;
475 std::sort(inequalities.begin(), inequalities.end());
476 for (
int i = 0; i + 1 < inequalities.size(); i++) {
484 if (integer_trail->IntegerLiteralIsTrue(inequalities[i].i_lit) ||
485 integer_trail->IntegerLiteralIsFalse(inequalities[i].i_lit)) {
488 if (integer_trail->IntegerLiteralIsTrue(inequalities[i + 1].i_lit) ||
489 integer_trail->IntegerLiteralIsFalse(inequalities[i + 1].i_lit)) {
493 const auto pair_a = encoder->Canonicalize(inequalities[i].i_lit);
494 const auto pair_b = encoder->Canonicalize(inequalities[i + 1].i_lit);
495 if (pair_a.first == pair_b.second) {
497 encoder->AssociateToIntegerLiteral(inequalities[i].
literal,
498 inequalities[i].i_lit);
499 mapping->already_loaded_ct_.insert(inequalities[i].
ct);
500 mapping->already_loaded_ct_.insert(inequalities[i + 1].
ct);
505 int num_half_inequalities = 0;
506 for (
const auto inequality : inequalities) {
507 if (mapping->ConstraintIsAlreadyLoaded(inequality.ct))
continue;
510 encoder->GetOrCreateAssociatedLiteral(inequality.i_lit)));
511 if (sat_solver->IsModelUnsat())
return;
513 ++num_half_inequalities;
514 mapping->already_loaded_ct_.insert(inequality.ct);
515 mapping->is_half_encoding_ct_.insert(inequality.ct);
518 if (!inequalities.empty()) {
519 VLOG(1) << num_inequalities <<
" literals associated to VAR >= value, and "
520 << num_half_inequalities <<
" half-associations.";
526 int num_constraints = 0;
527 int num_equalities = 0;
528 int num_half_equalities = 0;
529 int num_fully_encoded = 0;
530 int num_partially_encoded = 0;
531 for (
int i = 0; i < var_to_equalities.size(); ++i) {
532 std::vector<EqualityDetectionHelper>& encoding = var_to_equalities[i];
533 std::sort(encoding.begin(), encoding.end());
534 if (encoding.empty())
continue;
535 num_constraints += encoding.size();
537 absl::flat_hash_set<int64_t> values;
538 for (
int j = 0; j + 1 < encoding.size(); j++) {
539 if ((encoding[j].
value != encoding[j + 1].
value) ||
541 (encoding[j].is_equality !=
true) ||
542 (encoding[j + 1].is_equality !=
false)) {
547 encoder->AssociateToIntegerEqualValue(encoding[j].
literal,
548 mapping->integers_[i],
549 IntegerValue(encoding[j].
value));
550 mapping->already_loaded_ct_.insert(encoding[j].
ct);
551 mapping->already_loaded_ct_.insert(encoding[j + 1].
ct);
552 values.insert(encoding[j].
value);
558 if (sat_solver->IsModelUnsat())
return;
566 for (
const auto equality : encoding) {
567 if (mapping->ConstraintIsAlreadyLoaded(equality.ct))
continue;
568 const class Literal eq = encoder->GetOrCreateLiteralAssociatedToEquality(
569 mapping->integers_[i], IntegerValue(equality.value));
570 if (equality.is_equality) {
576 ++num_half_equalities;
577 mapping->already_loaded_ct_.insert(equality.ct);
578 mapping->is_half_encoding_ct_.insert(equality.ct);
583 if (encoder->VariableIsFullyEncoded(mapping->integers_[i])) {
586 ++num_partially_encoded;
591 if (num_constraints > 0) {
592 VLOG(1) << num_equalities <<
" literals associated to VAR == value, and "
593 << num_half_equalities <<
" half-associations.";
595 if (num_fully_encoded > 0) {
596 VLOG(1) <<
"num_fully_encoded_variables: " << num_fully_encoded;
598 if (num_partially_encoded > 0) {
599 VLOG(1) <<
"num_partially_encoded_variables: " << num_partially_encoded;
610 int64_t num_associations = 0;
611 int64_t num_set_to_false = 0;
613 if (!
ct.enforcement_literal().empty())
continue;
615 if (
ct.linear().vars_size() != 2)
continue;
616 if (!ConstraintIsEq(
ct.linear()))
continue;
618 const IntegerValue rhs(
ct.linear().domain(0));
621 IntegerVariable var1 = mapping->Integer(
ct.linear().vars(0));
622 IntegerVariable var2 = mapping->Integer(
ct.linear().vars(1));
623 IntegerValue coeff1(
ct.linear().coeffs(0));
624 IntegerValue coeff2(
ct.linear().coeffs(1));
636 if (coeff1 == 0 || coeff2 == 0)
continue;
641 for (
int i = 0; i < 2; ++i) {
642 for (
const auto value_literal :
643 encoder->PartialGreaterThanEncoding(var1)) {
644 const IntegerValue value1 = value_literal.first;
645 const IntegerValue bound2 =
FloorRatio(rhs - value1 * coeff1, coeff2);
647 encoder->AssociateToIntegerLiteral(
659 for (
int i = 0; i < 2; ++i) {
660 for (
const auto value_literal : encoder->PartialDomainEncoding(var1)) {
661 const IntegerValue value1 = value_literal.value;
662 const IntegerValue intermediate = rhs - value1 * coeff1;
663 if (intermediate % coeff2 != 0) {
666 sat_solver->AddUnitClause(value_literal.literal.Negated());
670 encoder->AssociateToIntegerEqualValue(value_literal.literal, var2,
671 intermediate / coeff2);
678 if (num_associations > 0) {
679 VLOG(1) <<
"Num associations from equivalences = " << num_associations;
681 if (num_set_to_false > 0) {
682 VLOG(1) <<
"Num literals set to false from equivalences = "
695 std::vector<bool> already_seen(num_proto_variables,
false);
710 std::vector<std::vector<int>> enforcement_intersection(num_proto_variables);
711 std::set<int> literals_set;
714 if (
ct.enforcement_literal().empty()) {
716 already_seen[
var] =
true;
717 enforcement_intersection[
var].clear();
720 literals_set.clear();
721 literals_set.insert(
ct.enforcement_literal().begin(),
722 ct.enforcement_literal().end());
724 if (!already_seen[
var]) {
725 enforcement_intersection[
var].assign(
ct.enforcement_literal().begin(),
726 ct.enforcement_literal().end());
729 std::vector<int>& vector_ref = enforcement_intersection[
var];
731 for (
const int literal : vector_ref) {
733 vector_ref[new_size++] =
literal;
736 vector_ref.resize(new_size);
738 already_seen[
var] =
true;
744 int num_optionals = 0;
746 for (
int var = 0;
var < num_proto_variables; ++
var) {
751 if (
min == 0 &&
max == 1)
continue;
752 if (enforcement_intersection[
var].empty())
continue;
755 integer_trail->MarkIntegerVariableAsOptional(
756 mapping->Integer(
var),
757 mapping->Literal(enforcement_intersection[
var].front()));
759 VLOG(2) <<
"Auto-detected " << num_optionals <<
" optional variables.";
780 DEFINE_INT_TYPE(ConstraintIndex, int32_t);
783 void Register(ConstraintIndex ct_index,
int variable) {
785 constraint_is_registered_[ct_index] =
true;
786 if (variable_watchers_.size() <= variable) {
787 variable_watchers_.resize(variable + 1);
788 variable_was_added_in_to_propagate_.resize(variable + 1);
790 variable_watchers_[variable].push_back(ct_index);
793 void AddVariableToPropagationQueue(
int variable) {
795 if (variable_was_added_in_to_propagate_.size() <= variable) {
796 variable_watchers_.resize(variable + 1);
797 variable_was_added_in_to_propagate_.resize(variable + 1);
799 if (!variable_was_added_in_to_propagate_[variable]) {
800 variable_was_added_in_to_propagate_[variable] =
true;
801 variables_to_propagate_.push_back(variable);
806 const bool IsFullyEncoded(
int v) {
807 const IntegerVariable variable = mapping_->
Integer(v);
809 return integer_trail_->
IsFixed(variable) ||
813 const bool VariableIsFixed(
int v) {
814 const IntegerVariable variable = mapping_->
Integer(v);
816 return integer_trail_->
IsFixed(variable);
819 void FullyEncode(
int v) {
821 const IntegerVariable variable = mapping_->
Integer(v);
823 if (!integer_trail_->
IsFixed(variable)) {
826 AddVariableToPropagationQueue(v);
829 bool ProcessConstraint(ConstraintIndex ct_index);
830 bool ProcessElement(ConstraintIndex ct_index);
831 bool ProcessTable(ConstraintIndex ct_index);
832 bool ProcessAutomaton(ConstraintIndex ct_index);
833 bool ProcessLinear(ConstraintIndex ct_index);
835 const CpModelProto& model_proto_;
836 const SatParameters& parameters_;
839 CpModelMapping* mapping_;
840 IntegerEncoder* integer_encoder_;
841 IntegerTrail* integer_trail_;
843 std::vector<bool> variable_was_added_in_to_propagate_;
844 std::vector<int> variables_to_propagate_;
845 std::vector<std::vector<ConstraintIndex>> variable_watchers_;
850 absl::flat_hash_map<int, absl::flat_hash_set<int>>
851 variables_to_equal_or_diff_variables_;
859 constraint_is_finished_.assign(num_constraints,
false);
860 constraint_is_registered_.assign(num_constraints,
false);
863 for (ConstraintIndex ct_index(0); ct_index < num_constraints; ++ct_index) {
864 constraint_is_finished_[ct_index] = ProcessConstraint(ct_index);
874 int num_variables_fully_encoded_by_heuristics = 0;
875 for (
int var = 0;
var < num_vars; ++
var) {
879 int64_t domain_size = domain.
Size();
880 int64_t num_diff_or_equal_var_constraints = 0;
881 int64_t num_potential_encoded_values_without_bounds = 0;
883 if (domain_size <= 2)
continue;
885 const absl::flat_hash_set<int64_t>& value_set =
887 for (
const int value : value_set) {
890 num_potential_encoded_values_without_bounds++;
894 const auto& it = variables_to_equal_or_diff_variables_.find(
var);
895 if (it != variables_to_equal_or_diff_variables_.end()) {
896 num_diff_or_equal_var_constraints = it->second.size();
899 if (num_potential_encoded_values_without_bounds >= domain_size / 2 ||
900 (num_diff_or_equal_var_constraints >= domain_size / 2 &&
903 <<
" is encoded with "
904 << num_potential_encoded_values_without_bounds
905 <<
" unary constraints, and " << num_diff_or_equal_var_constraints
906 <<
" binary constraints on a domain of size " << domain_size;
908 num_variables_fully_encoded_by_heuristics++;
911 if (num_variables_fully_encoded_by_heuristics > 0) {
912 VLOG(2) << num_variables_fully_encoded_by_heuristics
913 <<
" variables fully encoded after model introspection.";
917 for (
int v = 0; v < variable_watchers_.size(); v++) {
918 if (!variable_watchers_[v].empty() && IsFullyEncoded(v)) {
919 AddVariableToPropagationQueue(v);
924 while (!variables_to_propagate_.empty()) {
925 const int variable = variables_to_propagate_.back();
926 variables_to_propagate_.pop_back();
927 for (
const ConstraintIndex ct_index : variable_watchers_[variable]) {
928 if (constraint_is_finished_[ct_index])
continue;
929 constraint_is_finished_[ct_index] = ProcessConstraint(ct_index);
935bool FullEncodingFixedPointComputer::ProcessConstraint(
936 ConstraintIndex ct_index) {
938 switch (
ct.constraint_case()) {
939 case ConstraintProto::ConstraintProto::kElement:
940 return ProcessElement(ct_index);
941 case ConstraintProto::ConstraintProto::kTable:
942 return ProcessTable(ct_index);
943 case ConstraintProto::ConstraintProto::kAutomaton:
944 return ProcessAutomaton(ct_index);
945 case ConstraintProto::ConstraintProto::kLinear:
946 return ProcessLinear(ct_index);
952bool FullEncodingFixedPointComputer::ProcessElement(ConstraintIndex ct_index) {
953 const ConstraintProto&
ct = model_proto_.
constraints(ct_index.value());
956 FullyEncode(
ct.element().index());
958 const int target =
ct.element().target();
961 if (VariableIsFixed(target))
return true;
964 if (IsFullyEncoded(target)) {
965 for (
const int v :
ct.element().vars()) FullyEncode(v);
969 bool all_variables_are_fully_encoded =
true;
970 for (
const int v :
ct.element().vars()) {
971 if (v == target)
continue;
972 if (!IsFullyEncoded(v)) {
973 all_variables_are_fully_encoded =
false;
977 if (all_variables_are_fully_encoded) {
978 if (!IsFullyEncoded(target)) FullyEncode(target);
983 if (constraint_is_registered_[ct_index]) {
984 for (
const int v :
ct.element().vars()) Register(ct_index, v);
985 Register(ct_index, target);
990bool FullEncodingFixedPointComputer::ProcessTable(ConstraintIndex ct_index) {
991 const ConstraintProto&
ct = model_proto_.
constraints(ct_index.value());
993 if (
ct.table().negated())
return true;
995 for (
const int variable :
ct.table().vars()) {
996 FullyEncode(variable);
1002bool FullEncodingFixedPointComputer::ProcessAutomaton(
1003 ConstraintIndex ct_index) {
1004 const ConstraintProto&
ct = model_proto_.
constraints(ct_index.value());
1005 for (
const int variable :
ct.automaton().vars()) {
1006 FullyEncode(variable);
1011bool FullEncodingFixedPointComputer::ProcessLinear(ConstraintIndex ct_index) {
1014 const ConstraintProto&
ct = model_proto_.
constraints(ct_index.value());
1016 ct.linear().vars_size() != 2) {
1020 if (!ConstraintIsEq(
ct.linear()) &&
1021 !ConstraintIsNEq(
ct.linear(), mapping_, integer_trail_,
nullptr)) {
1025 const int var0 =
ct.linear().vars(0);
1026 const int var1 =
ct.linear().vars(1);
1027 if (!IsFullyEncoded(var0)) {
1028 variables_to_equal_or_diff_variables_[var0].insert(var1);
1030 if (!IsFullyEncoded(var1)) {
1031 variables_to_equal_or_diff_variables_[var1].insert(var0);
1048 if (strategy.domain_reduction_strategy() ==
1050 for (
const int ref : strategy.variables()) {
1051 if (!mapping->IsInteger(ref))
return;
1052 const IntegerVariable variable = mapping->Integer(
PositiveRef(ref));
1053 if (!integer_trail->IsFixed(variable)) {
1067 std::vector<Literal> literals = mapping->
Literals(
ct.bool_or().literals());
1068 for (
const int ref :
ct.enforcement_literal()) {
1069 literals.push_back(mapping->Literal(ref).Negated());
1076 std::vector<Literal> literals;
1077 for (
const int ref :
ct.enforcement_literal()) {
1078 literals.push_back(mapping->Literal(ref).Negated());
1081 for (
const Literal literal : mapping->Literals(
ct.bool_and().literals())) {
1084 literals.pop_back();
1110void LoadEquivalenceAC(
const std::vector<Literal> enforcement_literal,
1111 IntegerValue coeff1, IntegerVariable var1,
1112 IntegerValue coeff2, IntegerVariable var2,
1113 const IntegerValue rhs, Model* m) {
1114 auto* encoder = m->GetOrCreate<IntegerEncoder>();
1115 CHECK(encoder->VariableIsFullyEncoded(var1));
1116 CHECK(encoder->VariableIsFullyEncoded(var2));
1117 absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
1118 for (
const auto value_literal : encoder->FullDomainEncoding(var1)) {
1119 term1_value_to_literal[coeff1 * value_literal.value] =
1120 value_literal.literal;
1122 for (
const auto value_literal : encoder->FullDomainEncoding(var2)) {
1123 const IntegerValue target = rhs - value_literal.value * coeff2;
1126 {value_literal.literal.Negated()}));
1128 const Literal target_literal = term1_value_to_literal[target];
1130 {value_literal.literal.Negated(), target_literal}));
1132 {value_literal.literal, target_literal.Negated()}));
1136 term1_value_to_literal.erase(target);
1142 std::vector<Literal> implied_false;
1143 for (
const auto entry : term1_value_to_literal) {
1144 implied_false.push_back(entry.second);
1146 std::sort(implied_false.begin(), implied_false.end());
1147 for (
const Literal l : implied_false) {
1154void LoadEquivalenceNeqAC(
const std::vector<Literal> enforcement_literal,
1155 IntegerValue coeff1, IntegerVariable var1,
1156 IntegerValue coeff2, IntegerVariable var2,
1157 const IntegerValue rhs, Model* m) {
1158 auto* encoder = m->GetOrCreate<IntegerEncoder>();
1159 CHECK(encoder->VariableIsFullyEncoded(var1));
1160 CHECK(encoder->VariableIsFullyEncoded(var2));
1161 absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
1162 for (
const auto value_literal : encoder->FullDomainEncoding(var1)) {
1163 term1_value_to_literal[coeff1 * value_literal.value] =
1164 value_literal.literal;
1166 for (
const auto value_literal : encoder->FullDomainEncoding(var2)) {
1167 const IntegerValue target_value = rhs - value_literal.value * coeff2;
1168 const auto& it = term1_value_to_literal.find(target_value);
1169 if (it != term1_value_to_literal.end()) {
1170 const Literal target_literal = it->second;
1172 enforcement_literal,
1173 {value_literal.literal.Negated(), target_literal.Negated()}));
1182 if (
ct.linear().vars().empty()) {
1186 std::vector<Literal> clause;
1187 for (
const int ref :
ct.enforcement_literal()) {
1188 clause.push_back(mapping->Literal(ref).Negated());
1192 VLOG(1) <<
"Trivially UNSAT constraint: " <<
ct.DebugString();
1199 const std::vector<IntegerVariable> vars =
1200 mapping->Integers(
ct.linear().vars());
1201 const std::vector<int64_t> coeffs = ValuesFromProto(
ct.linear().coeffs());
1207 IntegerValue min_sum(0);
1208 IntegerValue max_sum(0);
1209 IntegerValue max_domain_size(0);
1210 bool all_booleans =
true;
1211 for (
int i = 0; i < vars.size(); ++i) {
1212 if (all_booleans && !mapping->IsBoolean(
ct.linear().vars(i))) {
1213 all_booleans =
false;
1215 const IntegerValue lb = integer_trail->LowerBound(vars[i]);
1216 const IntegerValue ub = integer_trail->UpperBound(vars[i]);
1217 max_domain_size =
std::max(max_domain_size, ub - lb + 1);
1218 const IntegerValue term_a = coeffs[i] * lb;
1219 const IntegerValue term_b = coeffs[i] * ub;
1220 min_sum +=
std::min(term_a, term_b);
1221 max_sum +=
std::max(term_a, term_b);
1225 const IntegerValue domain_size_limit(
1227 if (
ct.linear().vars_size() == 2 && !integer_trail->IsFixed(vars[0]) &&
1228 !integer_trail->IsFixed(vars[1]) &&
1229 max_domain_size <= domain_size_limit) {
1232 ct.linear().domain(0) != min_sum &&
ct.linear().domain(0) != max_sum &&
1233 encoder->VariableIsFullyEncoded(vars[0]) &&
1234 encoder->VariableIsFullyEncoded(vars[1])) {
1235 VLOG(3) <<
"Load AC version of " <<
ct.DebugString() <<
", var0 domain = "
1236 << integer_trail->InitialVariableDomain(vars[0])
1237 <<
", var1 domain = "
1238 << integer_trail->InitialVariableDomain(vars[1]);
1239 return LoadEquivalenceAC(mapping->Literals(
ct.enforcement_literal()),
1240 IntegerValue(coeffs[0]), vars[0],
1241 IntegerValue(coeffs[1]), vars[1],
1242 IntegerValue(
ct.linear().domain(0)), m);
1245 int64_t single_value = 0;
1247 ConstraintIsNEq(
ct.linear(), mapping, integer_trail, &single_value) &&
1248 single_value != min_sum && single_value != max_sum &&
1249 encoder->VariableIsFullyEncoded(vars[0]) &&
1250 encoder->VariableIsFullyEncoded(vars[1])) {
1251 VLOG(3) <<
"Load NAC version of " <<
ct.DebugString()
1252 <<
", var0 domain = "
1253 << integer_trail->InitialVariableDomain(vars[0])
1254 <<
", var1 domain = "
1255 << integer_trail->InitialVariableDomain(vars[1])
1256 <<
", value = " << single_value;
1257 return LoadEquivalenceNeqAC(mapping->Literals(
ct.enforcement_literal()),
1258 IntegerValue(coeffs[0]), vars[0],
1259 IntegerValue(coeffs[1]), vars[1],
1260 IntegerValue(single_value), m);
1264 if (
ct.linear().domain_size() == 2) {
1265 int64_t lb =
ct.linear().domain(0);
1266 int64_t ub =
ct.linear().domain(1);
1274 std::vector<LiteralWithCoeff> cst;
1275 for (
int i = 0; i < vars.size(); ++i) {
1276 const int ref =
ct.linear().vars(i);
1277 cst.push_back({mapping->Literal(ref), coeffs[i]});
1289 const std::vector<Literal> enforcement_literals =
1290 mapping->Literals(
ct.enforcement_literal());
1303 const bool special_case =
1304 ct.enforcement_literal().empty() &&
ct.linear().domain_size() == 4;
1306 std::vector<Literal> clause;
1307 for (
int i = 0; i <
ct.linear().domain_size(); i += 2) {
1308 int64_t lb =
ct.linear().domain(i);
1309 int64_t ub =
ct.linear().domain(i + 1);
1313 const Literal subdomain_literal(
1314 special_case && i > 0 ? clause.back().Negated()
1316 clause.push_back(subdomain_literal);
1327 for (
const int ref :
ct.enforcement_literal()) {
1328 clause.push_back(mapping->Literal(ref).Negated());
1336 const std::vector<IntegerVariable> vars =
1342 int num_fully_encoded = 0;
1343 int64_t max_domain_size = 0;
1344 for (
const IntegerVariable variable : vars) {
1345 if (encoder->VariableIsFullyEncoded(variable)) num_fully_encoded++;
1347 IntegerValue lb = integer_trail->
LowerBound(variable);
1348 IntegerValue ub = integer_trail->
UpperBound(variable);
1349 const int64_t domain_size = ub.value() - lb.value() + 1;
1350 max_domain_size =
std::max(max_domain_size, domain_size);
1353 if (num_fully_encoded == vars.size() && max_domain_size < 1024) {
1363 const IntegerVariable prod = mapping->
Integer(
ct.int_prod().target());
1364 const std::vector<IntegerVariable> vars =
1365 mapping->Integers(
ct.int_prod().vars());
1366 CHECK_EQ(vars.size(), 2) <<
"General int_prod not supported yet.";
1372 const IntegerVariable div = mapping->
Integer(
ct.int_div().target());
1373 const std::vector<IntegerVariable> vars =
1374 mapping->Integers(
ct.int_div().vars());
1376 const IntegerValue denom(m->
Get(
Value(vars[1])));
1389 const IntegerVariable
min = mapping->Integer(
ct.int_min().target());
1390 const std::vector<IntegerVariable> vars =
1391 mapping->Integers(
ct.int_min().vars());
1396 if (
ct.lin_max().exprs().empty()) {
1403 std::vector<LinearExpression> negated_exprs;
1404 negated_exprs.reserve(
ct.lin_max().exprs_size());
1405 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
1406 negated_exprs.push_back(
1407 NegationOf(mapping->GetExprFromProto(
ct.lin_max().exprs(i))));
1415 const IntegerVariable
max = mapping->Integer(
ct.int_max().target());
1416 const std::vector<IntegerVariable> vars =
1417 mapping->Integers(
ct.int_max().vars());
1427 if (
ct.no_overlap_2d().x_intervals().empty())
return;
1429 const std::vector<IntervalVariable> x_intervals =
1430 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
1431 const std::vector<IntervalVariable> y_intervals =
1432 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
1434 x_intervals, y_intervals,
1435 !
ct.no_overlap_2d().boxes_with_null_area_can_overlap()));
1440 const std::vector<IntervalVariable> intervals =
1443 std::vector<AffineExpression> demands;
1444 for (
const IntegerVariable
var :
1445 mapping->Integers(
ct.cumulative().demands())) {
1454 std::vector<AffineExpression> times;
1455 std::vector<IntegerValue> deltas;
1456 std::vector<Literal> presences;
1457 const int size =
ct.reservoir().times().size();
1458 for (
int i = 0; i < size; ++i) {
1459 times.push_back(mapping->Integer(
ct.reservoir().times(i)));
1460 deltas.push_back(IntegerValue(
ct.reservoir().demands(i)));
1461 if (!
ct.reservoir().actives().empty()) {
1462 presences.push_back(mapping->Literal(
ct.reservoir().actives(i)));
1464 presences.push_back(encoder->GetTrueLiteral());
1468 ct.reservoir().max_level(), m);
1480 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1481 const IntegerVariable target = mapping->Integer(
ct.element().target());
1482 const std::vector<IntegerVariable> vars =
1483 mapping->Integers(
ct.element().vars());
1487 Domain union_of_non_constant_domains;
1488 std::map<IntegerValue, int> constant_to_num;
1490 const int i = literal_value.value.value();
1493 constant_to_num[
value]++;
1495 union_of_non_constant_domains = union_of_non_constant_domains.
UnionWith(
1496 integer_trail->InitialVariableDomain(vars[i]));
1501 for (
const auto entry : constant_to_num) {
1502 if (union_of_non_constant_domains.
Contains(entry.first.value())) {
1503 constant_to_num[entry.first]++;
1509 bool is_one_to_one_mapping =
true;
1511 const int i = literal_value.value.value();
1513 is_one_to_one_mapping =
false;
1518 if (constant_to_num[
value] == 1) {
1519 const Literal r = literal_value.literal;
1520 encoder->AssociateToIntegerEqualValue(r, target,
value);
1522 is_one_to_one_mapping =
false;
1526 return is_one_to_one_mapping;
1534 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1535 const IntegerVariable target = mapping->Integer(
ct.element().target());
1536 const std::vector<IntegerVariable> vars =
1537 mapping->Integers(
ct.element().vars());
1542 std::vector<Literal> selectors;
1543 std::vector<IntegerVariable> possible_vars;
1544 for (
const auto literal_value : encoding) {
1545 const int i = literal_value.value.value();
1548 possible_vars.push_back(vars[i]);
1549 selectors.push_back(literal_value.literal);
1550 const Literal r = literal_value.literal;
1552 if (vars[i] == target)
continue;
1586 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1587 const IntegerVariable target = mapping->Integer(
ct.element().target());
1588 const std::vector<IntegerVariable> vars =
1589 mapping->Integers(
ct.element().vars());
1593 absl::flat_hash_map<IntegerValue, Literal> target_map;
1595 for (
const auto literal_value : target_encoding) {
1596 target_map[literal_value.value] = literal_value.literal;
1601 absl::flat_hash_map<IntegerValue, std::vector<Literal>> value_to_literals;
1604 for (
const auto literal_value : index_encoding) {
1605 const int i = literal_value.value.value();
1606 const Literal i_lit = literal_value.literal;
1610 value_to_literals[integer_trail->
LowerBound(vars[i])].push_back(i_lit);
1615 std::vector<Literal> var_selected_literals;
1616 for (
const auto var_literal_value : var_encoding) {
1617 const IntegerValue
value = var_literal_value.value;
1618 const Literal var_is_value = var_literal_value.literal;
1627 const Literal var_is_value_and_selected =
1630 value_to_literals[
value].push_back(var_is_value_and_selected);
1631 var_selected_literals.push_back(var_is_value_and_selected);
1638 for (
const auto& entry : target_map) {
1639 const IntegerValue
value = entry.first;
1640 const Literal target_is_value = entry.second;
1658void LoadElementConstraintHalfAC(
const ConstraintProto&
ct, Model* m) {
1659 auto* mapping = m->GetOrCreate<CpModelMapping>();
1660 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1661 const IntegerVariable target = mapping->Integer(
ct.element().target());
1662 const std::vector<IntegerVariable> vars =
1663 mapping->Integers(
ct.element().vars());
1669 const int i = value_literal.value.value();
1671 LoadEquivalenceAC({value_literal.literal}, IntegerValue(1), vars[i],
1672 IntegerValue(-1), target, IntegerValue(0), m);
1676void LoadBooleanElement(
const ConstraintProto&
ct, Model* m) {
1677 auto* mapping = m->GetOrCreate<CpModelMapping>();
1678 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1679 const std::vector<Literal> literals = mapping->Literals(
ct.element().vars());
1680 const Literal target = mapping->Literal(
ct.element().target());
1687 std::vector<Literal> all_true;
1688 std::vector<Literal> all_false;
1690 const Literal a_lit = literals[value_literal.value.value()];
1691 const Literal i_lit = value_literal.literal;
1694 all_true.push_back(a_lit.Negated());
1695 all_false.push_back(a_lit);
1697 all_true.push_back(target);
1698 all_false.push_back(target.Negated());
1708 const IntegerVariable
index = mapping->Integer(
ct.element().index());
1710 bool boolean_array =
true;
1711 for (
const int ref :
ct.element().vars()) {
1712 if (!mapping->IsBoolean(ref)) {
1713 boolean_array =
false;
1717 if (boolean_array && !mapping->IsBoolean(
ct.element().target())) {
1719 VLOG(1) <<
"Fix boolean_element not propagated on target";
1720 boolean_array =
false;
1725 if (boolean_array) {
1726 LoadBooleanElement(
ct, m);
1730 const IntegerVariable target = mapping->Integer(
ct.element().target());
1731 const std::vector<IntegerVariable> vars =
1732 mapping->Integers(
ct.element().vars());
1761 int num_AC_variables = 0;
1762 const int num_vars =
ct.element().vars().size();
1763 for (
const int v :
ct.element().vars()) {
1764 IntegerVariable variable = mapping->Integer(v);
1765 const bool is_full =
1767 if (is_full) num_AC_variables++;
1772 (target_is_AC || num_AC_variables >= num_vars - 1)) {
1776 LoadElementConstraintHalfAC(
ct, m);
1785 const std::vector<IntegerVariable> vars =
1787 const std::vector<int64_t> values = ValuesFromProto(
ct.table().values());
1788 const int num_vars = vars.size();
1789 const int num_tuples = values.size() / num_vars;
1790 std::vector<std::vector<int64_t>> tuples(num_tuples);
1792 for (
int i = 0; i < num_tuples; ++i) {
1793 for (
int j = 0; j < num_vars; ++j) {
1794 tuples[i].push_back(values[count++]);
1797 if (
ct.table().negated()) {
1806 const std::vector<IntegerVariable> vars =
1809 const int num_transitions =
ct.automaton().transition_tail_size();
1810 std::vector<std::vector<int64_t>> transitions;
1811 transitions.reserve(num_transitions);
1812 for (
int i = 0; i < num_transitions; ++i) {
1813 transitions.push_back({
ct.automaton().transition_tail(i),
1814 ct.automaton().transition_label(i),
1815 ct.automaton().transition_head(i)});
1818 const int64_t starting_state =
ct.automaton().starting_state();
1819 const std::vector<int64_t> final_states =
1820 ValuesFromProto(
ct.automaton().final_states());
1827 const std::vector<IntegerVariable>& vars,
Model* m) {
1828 const int n = vars.size();
1833 std::vector<std::vector<Literal>> matrix(
1834 n, std::vector<Literal>(n, kFalseLiteral));
1835 for (
int i = 0; i < n; i++) {
1836 for (
int j = 0; j < n; j++) {
1841 matrix[i][
value] = kTrueLiteral;
1844 for (
const auto& entry : encoding) {
1845 const int value = entry.value.value();
1848 matrix[i][
value] = entry.literal;
1857 const auto& circuit =
ct.circuit();
1858 if (circuit.tails().empty())
return;
1860 std::vector<int> tails(circuit.tails().begin(), circuit.tails().end());
1861 std::vector<int> heads(circuit.heads().begin(), circuit.heads().end());
1862 std::vector<Literal> literals =
1864 const int num_nodes =
ReindexArcs(&tails, &heads);
1869 const auto& routes =
ct.routes();
1870 if (routes.tails().empty())
return;
1872 std::vector<int> tails(routes.tails().begin(), routes.tails().end());
1873 std::vector<int> heads(routes.heads().begin(), routes.heads().end());
1874 std::vector<Literal> literals =
1876 const int num_nodes =
ReindexArcs(&tails, &heads);
1882 switch (
ct.constraint_case()) {
1883 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
1885 case ConstraintProto::ConstraintCase::kBoolOr:
1888 case ConstraintProto::ConstraintCase::kBoolAnd:
1891 case ConstraintProto::ConstraintCase::kAtMostOne:
1894 case ConstraintProto::ConstraintCase::kExactlyOne:
1897 case ConstraintProto::ConstraintCase::kBoolXor:
1900 case ConstraintProto::ConstraintProto::kLinear:
1903 case ConstraintProto::ConstraintProto::kAllDiff:
1906 case ConstraintProto::ConstraintProto::kIntProd:
1909 case ConstraintProto::ConstraintProto::kIntDiv:
1912 case ConstraintProto::ConstraintProto::kIntMin:
1915 case ConstraintProto::ConstraintProto::kLinMax:
1918 case ConstraintProto::ConstraintProto::kIntMax:
1921 case ConstraintProto::ConstraintProto::kInterval:
1924 case ConstraintProto::ConstraintProto::kNoOverlap:
1927 case ConstraintProto::ConstraintProto::kNoOverlap2D:
1930 case ConstraintProto::ConstraintProto::kCumulative:
1933 case ConstraintProto::ConstraintProto::kReservoir:
1936 case ConstraintProto::ConstraintProto::kElement:
1939 case ConstraintProto::ConstraintProto::kTable:
1942 case ConstraintProto::ConstraintProto::kAutomaton:
1945 case ConstraintProto::ConstraintProto::kCircuit:
1948 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)
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.
const absl::flat_hash_set< int64_t > & PotentialEncodedValues(int var)
bool IsInteger(int ref) const
std::vector< IntegerVariable > Integers(const List &list) const
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
IntegerVariable Integer(int ref) const
std::vector< sat::Literal > Literals(const ProtoIndices &indices) const
const ::operations_research::sat::CpObjectiveProto & objective() const
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
const ::operations_research::sat::DecisionStrategyProto & search_strategy(int index) const
bool has_objective() const
const ::operations_research::sat::SymmetryProto & symmetry() const
int variables_size() const
int constraints_size() const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
::PROTOBUF_NAMESPACE_ID::int32 vars(int index) const
static constexpr DomainReductionStrategy SELECT_MEDIAN_VALUE
FullEncodingFixedPointComputer(const CpModelProto &model_proto, Model *model)
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)
::PROTOBUF_NAMESPACE_ID::int64 domain(int index) const
Literal(int signed_value)
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 enumerate_all_solutions() const
::PROTOBUF_NAMESPACE_ID::int32 max_domain_size_when_encoding_eq_neq_constraints() const
::PROTOBUF_NAMESPACE_ID::int32 boolean_encoding_level() const
bool use_optional_variables() const
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 *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
std::function< void(Model *)> AllDifferentAC(const std::vector< IntegerVariable > &variables)
std::function< void(Model *)> LiteralXorIs(const std::vector< Literal > &literals, bool value)
std::function< void(Model *)> Equality(IntegerVariable v, int64_t value)
void LoadExactlyOneConstraint(const ConstraintProto &ct, Model *m)
void AddTableConstraint(absl::Span< const IntegerVariable > vars, std::vector< std::vector< int64_t > > tuples, Model *model)
std::function< void(Model *)> ReifiedBoolOr(const std::vector< Literal > &literals, Literal r)
void LoadVariables(const CpModelProto &model_proto, bool view_all_booleans_as_integers, Model *m)
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)
void MaybeFullyEncodeMoreVariables(const CpModelProto &model_proto, Model *m)
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
const LiteralIndex kNoLiteralIndex(-1)
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
std::function< void(Model *)> EnforcedClause(absl::Span< const Literal > enforcement_literals, absl::Span< const Literal > clause)
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)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
std::function< void(Model *)> DivisionConstraint(IntegerVariable num, IntegerVariable denom, IntegerVariable div)
bool HasEnforcementLiteral(const ConstraintProto &ct)
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> PartialIsOneOfVar(IntegerVariable target_var, const std::vector< IntegerVariable > &vars, const std::vector< Literal > &selectors)
void LoadBooleanSymmetries(const CpModelProto &model_proto, Model *m)
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
std::function< void(Model *)> ConditionalWeightedSumGreaterOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
bool DetectEquivalencesInElementConstraint(const ConstraintProto &ct, Model *m)
void LoadCumulativeConstraint(const ConstraintProto &ct, Model *m)
std::function< IntervalVariable(Model *)> NewInterval(int64_t min_start, int64_t max_end, int64_t size)
void LoadRoutesConstraint(const ConstraintProto &ct, Model *m)
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)
const IntegerVariable kNoIntegerVariable(-1)
const IntervalVariable kNoIntervalVariable(-1)
std::function< void(Model *)> ConditionalWeightedSumLowerOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
std::function< void(Model *)> Cumulative(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
std::function< void(Model *)> IsEqualToMaxOf(IntegerVariable max_var, const std::vector< IntegerVariable > &vars)
void LoadIntDivConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> Implication(const std::vector< Literal > &enforcement_literals, IntegerLiteral i)
void AddNegatedTableConstraint(absl::Span< const IntegerVariable > vars, std::vector< std::vector< int64_t > > tuples, Model *model)
std::function< void(Model *)> ProductConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable p)
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64_t min_start, int64_t max_end, int64_t size, Literal is_present)
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> AtMostOneConstraint(const std::vector< Literal > &literals)
int ReindexArcs(IntContainer *tails, IntContainer *heads)
std::function< void(Model *)> FixedDivisionConstraint(IntegerVariable a, IntegerValue b, IntegerVariable c)
std::vector< std::vector< Literal > > GetSquareMatrixFromIntegerVariables(const std::vector< IntegerVariable > &vars, Model *m)
std::function< void(Model *)> Disjunctive(const std::vector< IntervalVariable > &vars)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
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 DetectOptionalVariables(const CpModelProto &model_proto, Model *m)
void LoadAllDiffConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ReifiedBoolAnd(const std::vector< Literal > &literals, Literal r)
void LoadElementConstraint(const ConstraintProto &ct, Model *m)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
void LoadAutomatonConstraint(const ConstraintProto &ct, Model *m)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
void LoadNoOverlap2dConstraint(const ConstraintProto &ct, Model *m)
void LoadIntMinConstraint(const ConstraintProto &ct, Model *m)
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)
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)
std::function< void(Model *)> BooleanLinearConstraint(int64_t lower_bound, int64_t upper_bound, std::vector< LiteralWithCoeff > *cst)
void AddFullEncodingFromSearchBranching(const CpModelProto &model_proto, Model *m)
std::function< void(Model *)> ExactlyOneConstraint(const std::vector< Literal > &literals)
std::function< void(Model *)> ImpliesInInterval(Literal in_interval, IntegerVariable v, int64_t lb, int64_t ub)
void ExtractEncoding(const CpModelProto &model_proto, Model *m)
const BooleanVariable kNoBooleanVariable(-1)
void PropagateEncodingFromEquivalenceRelations(const CpModelProto &model_proto, Model *m)
std::function< std::vector< IntegerEncoder::ValueLiteralPair >(Model *)> FullyEncodeVariable(IntegerVariable var)
void LoadElementConstraintAC(const ConstraintProto &ct, Model *m)
void LoadElementConstraintBounds(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ConditionalLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_le)
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)
#define SOLVER_LOG(logger,...)
#define VLOG_IS_ON(verboselevel)