26#include "absl/container/btree_map.h"
27#include "absl/container/btree_set.h"
28#include "absl/container/flat_hash_map.h"
29#include "absl/container/flat_hash_set.h"
30#include "absl/log/check.h"
31#include "absl/meta/type_traits.h"
32#include "absl/strings/str_cat.h"
33#include "absl/types/span.h"
41#include "ortools/sat/cp_model.pb.h"
56#include "ortools/sat/sat_parameters.pb.h"
70template <
typename Values>
71std::vector<int64_t> ValuesFromProto(
const Values& values) {
72 return std::vector<int64_t>(values.begin(), values.end());
75void ComputeLinearBounds(
const LinearConstraintProto&
proto,
76 CpModelMapping* mapping, IntegerTrail* integer_trail,
77 int64_t* sum_min, int64_t* sum_max) {
81 for (
int i = 0;
i <
proto.vars_size(); ++
i) {
82 const int64_t coeff =
proto.coeffs(
i);
83 const IntegerVariable
var = mapping->Integer(
proto.vars(
i));
84 const int64_t lb = integer_trail->LowerBound(
var).value();
85 const int64_t ub = integer_trail->UpperBound(
var).value();
87 (*sum_min) += coeff * lb;
88 (*sum_max) += coeff * ub;
90 (*sum_min) += coeff * ub;
91 (*sum_max) += coeff * lb;
97bool ConstraintIsEq(
const LinearConstraintProto&
proto) {
102bool ConstraintIsNEq(
const LinearConstraintProto&
proto,
103 CpModelMapping* mapping, IntegerTrail* integer_trail,
104 int64_t* single_value) {
107 ComputeLinearBounds(
proto, mapping, integer_trail, &sum_min, &sum_max);
109 const Domain complement =
110 Domain(sum_min, sum_max)
112 if (complement.IsEmpty())
return false;
113 const int64_t
value = complement.Min();
115 if (complement.Size() == 1) {
116 if (single_value !=
nullptr) {
117 *single_value =
value;
127 bool view_all_booleans_as_integers,
Model* m) {
129 const int num_proto_variables = model_proto.variables_size();
135 CHECK_EQ(sat_solver->NumVariables(), 0);
137 BooleanVariable new_var(0);
138 std::vector<BooleanVariable> false_variables;
139 std::vector<BooleanVariable> true_variables;
142 mapping->reverse_boolean_map_.resize(num_proto_variables, -1);
143 for (
int i = 0;
i < num_proto_variables; ++
i) {
144 const auto& domain = model_proto.variables(
i).domain();
145 if (domain.size() != 2)
continue;
146 if (domain[0] >= 0 && domain[1] <= 1) {
147 mapping->booleans_[
i] = new_var;
148 mapping->reverse_boolean_map_[new_var] =
i;
149 if (domain[1] == 0) {
150 false_variables.push_back(new_var);
151 }
else if (domain[0] == 1) {
152 true_variables.push_back(new_var);
158 sat_solver->SetNumVariables(new_var.value());
159 for (
const BooleanVariable
var : true_variables) {
162 for (
const BooleanVariable
var : false_variables) {
169 std::vector<int> var_to_instantiate_as_integer;
170 if (view_all_booleans_as_integers) {
171 var_to_instantiate_as_integer.resize(num_proto_variables);
172 for (
int i = 0;
i < num_proto_variables; ++
i) {
173 var_to_instantiate_as_integer[
i] =
i;
177 absl::flat_hash_set<int> used_variables;
179 const bool some_linerization =
180 m->
GetOrCreate<SatParameters>()->linearization_level() > 0;
183 for (
int c = 0; c < model_proto.constraints_size(); ++c) {
184 const ConstraintProto&
ct = model_proto.constraints(c);
192 if (some_linerization) {
193 if (
ct.constraint_case() == ConstraintProto::kCircuit) {
194 for (
const int ref :
ct.circuit().literals()) {
197 }
else if (
ct.constraint_case() == ConstraintProto::kRoutes) {
198 for (
const int ref :
ct.routes().literals()) {
207 if (model_proto.has_objective()) {
208 for (
const int obj_var : model_proto.objective().vars()) {
215 for (
int i = 0;
i < num_proto_variables; ++
i) {
217 used_variables.insert(
i);
222 var_to_instantiate_as_integer.assign(used_variables.begin(),
223 used_variables.end());
232 int reservation_size = var_to_instantiate_as_integer.size();
233 for (
const ConstraintProto&
ct : model_proto.constraints()) {
234 if (
ct.constraint_case() != ConstraintProto::kLinear)
continue;
235 const int ct_size =
ct.linear().vars().size();
237 reservation_size +=
static_cast<int>(std::round(std::sqrt(ct_size)));
240 if (model_proto.has_objective()) {
241 reservation_size += 1;
242 const int ct_size = model_proto.objective().vars().size() + 1;
244 reservation_size +=
static_cast<int>(std::round(std::sqrt(ct_size)));
252 mapping->reverse_integer_map_.resize(2 * var_to_instantiate_as_integer.size(),
254 for (
const int i : var_to_instantiate_as_integer) {
255 const auto& var_proto = model_proto.variables(
i);
256 mapping->integers_[
i] =
258 DCHECK_LT(mapping->integers_[
i], mapping->reverse_integer_map_.size());
259 mapping->reverse_integer_map_[mapping->integers_[
i]] =
i;
266 for (
int i = 0;
i < num_proto_variables; ++
i) {
271 encoder->AssociateToIntegerEqualValue(
277 mapping->intervals_.resize(model_proto.constraints_size(),
279 for (
int c = 0; c < model_proto.constraints_size(); ++c) {
280 const ConstraintProto&
ct = model_proto.constraints(c);
281 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kInterval) {
286 mapping->
Literal(
ct.enforcement_literal(0));
290 mapping->intervals_[c] = intervals_repository->CreateInterval(
291 mapping->Affine(
ct.interval().start()),
292 mapping->Affine(
ct.interval().end()),
293 mapping->Affine(
ct.interval().size()), enforcement_literal.
Index(),
296 mapping->intervals_[c] = intervals_repository->CreateInterval(
297 mapping->Affine(
ct.interval().start()),
298 mapping->Affine(
ct.interval().end()),
302 mapping->already_loaded_ct_.insert(&
ct);
308 const SymmetryProto& symmetry = model_proto.symmetry();
309 if (symmetry.permutations().empty())
return;
312 const int num_vars = model_proto.variables().size();
313 std::vector<bool> can_be_used_in_symmetry(num_vars,
true);
316 for (
int v = 0; v < num_vars; ++v) {
317 if (!mapping->IsBoolean(v)) can_be_used_in_symmetry[v] =
false;
328 const int num_constraints = model_proto.constraints().size();
329 for (
int c = 0; c < num_constraints; ++c) {
330 const ConstraintProto&
ct = model_proto.constraints(c);
331 if (
ct.constraint_case() != ConstraintProto::kLinear)
continue;
332 if (
ct.linear().domain().size() <= 2)
continue;
337 for (
const int ref :
ct.linear().vars()) {
344 sat_solver->AddPropagator(symmetry_handler);
345 const int num_literals = 2 * sat_solver->NumVariables();
347 for (
const SparsePermutationProto& perm : symmetry.permutations()) {
348 bool can_be_used =
true;
349 for (
const int var : perm.support()) {
350 if (!can_be_used_in_symmetry[
var]) {
355 if (!can_be_used)
continue;
358 auto literal_permutation =
359 std::make_unique<SparsePermutation>(num_literals);
360 int support_index = 0;
361 const int num_cycle = perm.cycle_sizes().size();
362 for (
int i = 0;
i < num_cycle; ++
i) {
363 const int size = perm.cycle_sizes(
i);
364 const int saved_support_index = support_index;
365 for (
int j = 0; j <
size; ++j) {
366 const int var = perm.support(support_index++);
367 literal_permutation->AddToCurrentCycle(
368 mapping->Literal(
var).Index().value());
370 literal_permutation->CloseCurrentCycle();
374 support_index = saved_support_index;
375 for (
int j = 0; j <
size; ++j) {
376 const int var = perm.support(support_index++);
377 literal_permutation->AddToCurrentCycle(
378 mapping->Literal(
var).NegatedIndex().value());
380 literal_permutation->CloseCurrentCycle();
382 symmetry_handler->AddSymmetry(std::move(literal_permutation));
386 symmetry_handler->num_permutations(),
387 " symmetry to the SAT solver.");
404 if (sat_solver->ModelIsUnsat())
return;
409 struct EqualityDetectionHelper {
410 const ConstraintProto*
ct;
415 bool operator<(
const EqualityDetectionHelper& o)
const {
416 if (
literal.Variable() == o.literal.Variable()) {
418 return value < o.value;
420 return literal.Variable() < o.literal.Variable();
423 std::vector<std::vector<EqualityDetectionHelper>> var_to_equalities(
424 model_proto.variables_size());
436 struct InequalityDetectionHelper {
437 const ConstraintProto*
ct;
441 bool operator<(
const InequalityDetectionHelper& o)
const {
442 if (
literal.Variable() == o.literal.Variable()) {
443 return i_lit.
var < o.i_lit.var;
445 return literal.Variable() < o.literal.Variable();
448 std::vector<InequalityDetectionHelper> inequalities;
451 for (
const ConstraintProto&
ct : model_proto.constraints()) {
452 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kLinear) {
455 if (
ct.enforcement_literal().size() != 1)
continue;
456 if (
ct.linear().vars_size() != 1)
continue;
460 mapping->
Literal(
ct.enforcement_literal(0));
461 if (sat_solver->Assignment().LiteralIsFalse(enforcement_literal))
continue;
463 const int ref =
ct.linear().vars(0);
467 const Domain domain_if_enforced =
472 if (domain_if_enforced.
IsEmpty()) {
473 if (!sat_solver->AddUnitClause(enforcement_literal.
Negated()))
return;
479 if (domain_if_enforced.
Max() >= domain.
Max() &&
480 domain_if_enforced.
Min() > domain.
Min()) {
481 inequalities.push_back({&
ct, enforcement_literal,
483 mapping->Integer(
var),
484 IntegerValue(domain_if_enforced.
Min()))});
485 }
else if (domain_if_enforced.
Min() <= domain.
Min() &&
486 domain_if_enforced.
Max() < domain.
Max()) {
487 inequalities.push_back({&
ct, enforcement_literal,
489 mapping->Integer(
var),
490 IntegerValue(domain_if_enforced.
Max()))});
496 if (domain_if_enforced.
Min() > domain.
Min()) {
500 mapping->Integer(
var), IntegerValue(domain_if_enforced.
Min())));
502 if (domain_if_enforced.
Max() < domain.
Max()) {
506 IntegerValue(domain_if_enforced.
Max())));
517 if (inter.
Min() == 0) {
518 detector->ProcessConditionalZero(enforcement_literal,
519 mapping->Integer(
var));
521 var_to_equalities[
var].push_back(
522 {&
ct, enforcement_literal, inter.
Min(),
true});
529 var_to_equalities[
var].push_back(
530 {&
ct, enforcement_literal, inter.
Min(),
false});
536 int num_inequalities = 0;
537 std::sort(inequalities.begin(), inequalities.end());
538 for (
int i = 0;
i + 1 < inequalities.size();
i++) {
546 if (integer_trail->IntegerLiteralIsTrue(inequalities[
i].i_lit) ||
547 integer_trail->IntegerLiteralIsFalse(inequalities[
i].i_lit)) {
550 if (integer_trail->IntegerLiteralIsTrue(inequalities[
i + 1].i_lit) ||
551 integer_trail->IntegerLiteralIsFalse(inequalities[
i + 1].i_lit)) {
555 const auto pair_a = encoder->Canonicalize(inequalities[
i].i_lit);
556 const auto pair_b = encoder->Canonicalize(inequalities[
i + 1].i_lit);
557 if (pair_a.first == pair_b.second) {
559 encoder->AssociateToIntegerLiteral(inequalities[
i].
literal,
560 inequalities[
i].i_lit);
561 mapping->already_loaded_ct_.insert(inequalities[
i].
ct);
562 mapping->already_loaded_ct_.insert(inequalities[
i + 1].
ct);
567 int num_half_inequalities = 0;
568 for (
const auto inequality : inequalities) {
569 if (mapping->ConstraintIsAlreadyLoaded(inequality.ct))
continue;
572 encoder->GetOrCreateAssociatedLiteral(inequality.i_lit)));
573 if (sat_solver->ModelIsUnsat())
return;
575 ++num_half_inequalities;
576 mapping->already_loaded_ct_.insert(inequality.ct);
577 mapping->is_half_encoding_ct_.insert(inequality.ct);
579 if (!inequalities.empty()) {
580 SOLVER_LOG(logger,
"[Encoding] ", num_inequalities,
581 " literals associated to VAR >= value, and ",
582 num_half_inequalities,
" half-associations.");
588 int num_equalities = 0;
589 int num_half_equalities = 0;
590 int num_fully_encoded = 0;
591 int num_partially_encoded = 0;
592 for (
int i = 0;
i < var_to_equalities.size(); ++
i) {
593 std::vector<EqualityDetectionHelper>& encoding = var_to_equalities[
i];
594 std::sort(encoding.begin(), encoding.end());
595 if (encoding.empty())
continue;
597 absl::flat_hash_set<int64_t> values;
598 const IntegerVariable
var = mapping->integers_[
i];
599 for (
int j = 0; j + 1 < encoding.size(); j++) {
600 if ((encoding[j].
value != encoding[j + 1].
value) ||
602 (encoding[j].is_equality !=
true) ||
603 (encoding[j + 1].is_equality !=
false)) {
608 encoder->AssociateToIntegerEqualValue(encoding[j].
literal,
var,
609 IntegerValue(encoding[j].
value));
610 mapping->already_loaded_ct_.insert(encoding[j].
ct);
611 mapping->already_loaded_ct_.insert(encoding[j + 1].
ct);
612 values.insert(encoding[j].
value);
618 if (sat_solver->ModelIsUnsat())
return;
626 for (
const auto equality : encoding) {
627 if (mapping->ConstraintIsAlreadyLoaded(equality.ct))
continue;
628 if (equality.is_equality) {
641 encoder->GetOrCreateAssociatedLiteral(
645 encoder->GetOrCreateAssociatedLiteral(
648 const Literal eq = encoder->GetOrCreateLiteralAssociatedToEquality(
649 var, equality.value);
653 ++num_half_equalities;
654 mapping->already_loaded_ct_.insert(equality.ct);
655 mapping->is_half_encoding_ct_.insert(equality.ct);
659 if (encoder->VariableIsFullyEncoded(
var)) {
662 ++num_partially_encoded;
666 if (num_equalities > 0 || num_half_equalities > 0) {
667 SOLVER_LOG(logger,
"[Encoding] ", num_equalities,
668 " literals associated to VAR == value, and ",
669 num_half_equalities,
" half-associations.");
671 if (num_fully_encoded > 0) {
673 "[Encoding] num_fully_encoded_variables:", num_fully_encoded);
675 if (num_partially_encoded > 0) {
676 SOLVER_LOG(logger,
"[Encoding] num_partially_encoded_variables:",
677 num_partially_encoded);
682 int num_element_encoded = 0;
692 int num_support_clauses = 0;
693 int num_dedicated_propagator = 0;
694 std::vector<Literal> clause;
695 std::vector<Literal> selectors;
696 std::vector<AffineExpression> exprs;
697 std::vector<AffineExpression> negated_exprs;
698 for (
int c = 0; c < model_proto.constraints_size(); ++c) {
699 const ConstraintProto&
ct = model_proto.constraints(c);
700 if (
ct.constraint_case() != ConstraintProto::kExactlyOne)
continue;
703 absl::btree_map<IntegerVariable, std::vector<ValueLiteralPair>>
704 var_to_value_literal_list;
705 for (
const int l :
ct.exactly_one().literals()) {
707 for (
const auto& var_value : implied_bounds->GetImpliedValues(
literal)) {
708 var_to_value_literal_list[var_value.first].push_back(
714 std::vector<IntegerVariable> encoded_variables;
715 std::string encoded_variables_str;
718 for (
auto& [
var, encoding] : var_to_value_literal_list) {
719 if (encoding.size() <
ct.exactly_one().literals_size()) {
720 VLOG(2) <<
"X" <<
var.value() <<
" has " << encoding.size()
721 <<
" implied values, and a domain of size "
723 ->InitialVariableDomain(
var)
729 ++num_element_encoded;
730 element_encodings->
Add(
var, encoding, c);
732 encoded_variables.push_back(
var);
733 absl::StrAppend(&encoded_variables_str,
" X",
var.value());
739 bool need_extra_propagation =
false;
740 std::sort(encoding.begin(), encoding.end(),
742 for (
int i = 0, j = 0;
i < encoding.size();
i = j) {
744 const IntegerValue
value = encoding[
i].value;
745 while (j < encoding.size() && encoding[j].value ==
value) ++j;
749 if (!encoder->IsFixedOrHasAssociatedLiteral(
751 !encoder->IsFixedOrHasAssociatedLiteral(
753 need_extra_propagation =
true;
756 encoder->AssociateToIntegerEqualValue(encoding[
i].
literal,
var,
760 if (encoder->GetAssociatedEqualityLiteral(
var,
value) ==
762 need_extra_propagation =
true;
770 ++num_support_clauses;
772 for (
int k =
i; k < j; ++k) clause.push_back(encoding[k].literal);
774 encoder->GetOrCreateLiteralAssociatedToEquality(
var,
value);
775 clause.push_back(eq_lit.
Negated());
780 sat_solver->AddProblemClause(clause,
false);
783 if (need_extra_propagation) {
784 ++num_dedicated_propagator;
787 negated_exprs.clear();
805 if (encoded_variables.size() > 1 && VLOG_IS_ON(1)) {
806 VLOG(1) <<
"exactly_one(" << c <<
") encodes " << encoded_variables.size()
807 <<
" variables at the same time: " << encoded_variables_str;
811 if (num_element_encoded > 0) {
813 "[Encoding] num_element_encoding: ", num_element_encoded);
815 if (num_support_clauses > 0) {
816 SOLVER_LOG(logger,
"[Encoding] Added ", num_support_clauses,
817 " element support clauses, and ", num_dedicated_propagator,
818 " dedicated propagators.");
829 int64_t num_associations = 0;
830 int64_t num_set_to_false = 0;
831 for (
const ConstraintProto&
ct : model_proto.constraints()) {
832 if (!
ct.enforcement_literal().empty())
continue;
833 if (
ct.constraint_case() != ConstraintProto::kLinear)
continue;
834 if (
ct.linear().vars_size() != 2)
continue;
835 if (!ConstraintIsEq(
ct.linear()))
continue;
837 const IntegerValue rhs(
ct.linear().domain(0));
840 IntegerVariable var1 = mapping->Integer(
ct.linear().vars(0));
841 IntegerVariable var2 = mapping->Integer(
ct.linear().vars(1));
842 IntegerValue coeff1(
ct.linear().coeffs(0));
843 IntegerValue coeff2(
ct.linear().coeffs(1));
855 if (coeff1 == 0 || coeff2 == 0)
continue;
860 for (
int i = 0;
i < 2; ++
i) {
861 for (
const auto [value1, literal1] :
862 encoder->PartialGreaterThanEncoding(var1)) {
863 const IntegerValue bound2 =
FloorRatio(rhs - value1 * coeff1, coeff2);
865 encoder->AssociateToIntegerLiteral(
868 std::swap(var1, var2);
869 std::swap(coeff1, coeff2);
877 for (
int i = 0;
i < 2; ++
i) {
878 const auto copy = encoder->PartialDomainEncoding(var1);
879 for (
const auto value_literal : copy) {
880 const IntegerValue value1 = value_literal.value;
881 const IntegerValue intermediate = rhs - value1 * coeff1;
882 if (intermediate % coeff2 != 0) {
885 if (!sat_solver->AddUnitClause(value_literal.literal.Negated())) {
891 encoder->AssociateToIntegerEqualValue(value_literal.literal, var2,
892 intermediate / coeff2);
894 std::swap(var1, var2);
895 std::swap(coeff1, coeff2);
899 if (num_associations > 0) {
900 VLOG(1) <<
"Num associations from equivalences = " << num_associations;
902 if (num_set_to_false > 0) {
903 VLOG(1) <<
"Num literals set to false from equivalences = "
910 if (!
parameters.use_optional_variables())
return;
911 if (
parameters.enumerate_all_solutions())
return;
914 const int num_proto_variables = model_proto.variables_size();
915 std::vector<bool> already_seen(num_proto_variables,
false);
916 if (model_proto.has_objective()) {
917 for (
const int ref : model_proto.objective().vars()) {
930 std::vector<std::vector<int>> enforcement_intersection(num_proto_variables);
931 absl::btree_set<int> literals_set;
932 for (
int c = 0; c < model_proto.constraints_size(); ++c) {
933 const ConstraintProto&
ct = model_proto.constraints(c);
934 if (
ct.enforcement_literal().empty()) {
936 already_seen[
var] =
true;
937 enforcement_intersection[
var].clear();
940 literals_set.clear();
941 literals_set.insert(
ct.enforcement_literal().begin(),
942 ct.enforcement_literal().end());
944 if (!already_seen[
var]) {
945 enforcement_intersection[
var].assign(
ct.enforcement_literal().begin(),
946 ct.enforcement_literal().end());
949 std::vector<int>& vector_ref = enforcement_intersection[
var];
951 for (
const int literal : vector_ref) {
952 if (literals_set.contains(
literal)) {
953 vector_ref[new_size++] =
literal;
956 vector_ref.resize(new_size);
958 already_seen[
var] =
true;
964 int num_optionals = 0;
965 for (
int var = 0;
var < num_proto_variables; ++
var) {
966 const IntegerVariableProto& var_proto = model_proto.variables(
var);
967 const int64_t
min = var_proto.domain(0);
968 const int64_t
max = var_proto.domain(var_proto.domain().size() - 1);
970 if (
min == 0 &&
max == 1)
continue;
971 if (enforcement_intersection[
var].empty())
continue;
976 if (num_optionals > 0) {
978 " optional variables. Note that for now we DO NOT do anything "
979 "with this information.");
985 if (model_proto.search_strategy().empty())
return;
989 for (
const DecisionStrategyProto& strategy : model_proto.search_strategy()) {
990 if (strategy.domain_reduction_strategy() ==
991 DecisionStrategyProto::SELECT_MEDIAN_VALUE) {
992 for (
const LinearExpressionProto& expr : strategy.exprs()) {
993 const int var = expr.vars(0);
994 if (!mapping->IsInteger(
var))
continue;
995 const IntegerVariable variable = mapping->Integer(
var);
996 if (!integer_trail->IsFixed(variable)) {
1009 auto* mapping = m->GetOrCreate<CpModelMapping>();
1011 std::vector<Literal> literals = mapping->Literals(
ct.bool_or().literals());
1012 for (
const int ref :
ct.enforcement_literal()) {
1013 literals.push_back(mapping->Literal(ref).Negated());
1016 if (literals.size() == 3) {
1017 m->GetOrCreate<ProductDetector>()->ProcessTernaryClause(literals);
1022 auto* mapping = m->GetOrCreate<CpModelMapping>();
1023 std::vector<Literal> literals;
1024 for (
const int ref :
ct.enforcement_literal()) {
1025 literals.push_back(mapping->Literal(ref).Negated());
1027 auto* sat_solver = m->GetOrCreate<SatSolver>();
1028 for (
const Literal
literal : mapping->Literals(
ct.bool_and().literals())) {
1030 sat_solver->AddProblemClause(literals,
false);
1031 literals.pop_back();
1036 auto* mapping = m->GetOrCreate<CpModelMapping>();
1042 auto* mapping = m->GetOrCreate<CpModelMapping>();
1044 const auto& literals = mapping->Literals(
ct.exactly_one().literals());
1046 if (literals.size() == 3) {
1047 m->GetOrCreate<
ProductDetector>()->ProcessTernaryExactlyOne(literals);
1052 auto* mapping = m->GetOrCreate<CpModelMapping>();
1054 m->Add(
LiteralXorIs(mapping->Literals(
ct.bool_xor().literals()),
true));
1061void LoadEquivalenceAC(
const std::vector<Literal> enforcement_literal,
1062 IntegerValue coeff1, IntegerVariable var1,
1063 IntegerValue coeff2, IntegerVariable var2,
1064 const IntegerValue rhs, Model* m) {
1065 auto* encoder = m->GetOrCreate<IntegerEncoder>();
1066 CHECK(encoder->VariableIsFullyEncoded(var1));
1067 CHECK(encoder->VariableIsFullyEncoded(var2));
1068 absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
1069 for (
const auto value_literal : encoder->FullDomainEncoding(var1)) {
1070 term1_value_to_literal[coeff1 * value_literal.value] =
1071 value_literal.literal;
1073 const auto copy = encoder->FullDomainEncoding(var2);
1074 for (
const auto value_literal : copy) {
1075 const IntegerValue target = rhs - value_literal.value * coeff2;
1076 if (!term1_value_to_literal.contains(target)) {
1078 {value_literal.literal.Negated()}));
1080 const Literal target_literal = term1_value_to_literal[target];
1082 {value_literal.literal.Negated(), target_literal}));
1084 {value_literal.literal, target_literal.Negated()}));
1088 term1_value_to_literal.erase(target);
1094 std::vector<Literal> implied_false;
1095 for (
const auto entry : term1_value_to_literal) {
1096 implied_false.push_back(entry.second);
1098 std::sort(implied_false.begin(), implied_false.end());
1099 for (
const Literal l : implied_false) {
1106void LoadEquivalenceNeqAC(
const std::vector<Literal> enforcement_literal,
1107 IntegerValue coeff1, IntegerVariable var1,
1108 IntegerValue coeff2, IntegerVariable var2,
1109 const IntegerValue rhs, Model* m) {
1110 auto* encoder = m->GetOrCreate<IntegerEncoder>();
1111 CHECK(encoder->VariableIsFullyEncoded(var1));
1112 CHECK(encoder->VariableIsFullyEncoded(var2));
1113 absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
1114 for (
const auto value_literal : encoder->FullDomainEncoding(var1)) {
1115 term1_value_to_literal[coeff1 * value_literal.value] =
1116 value_literal.literal;
1118 const auto copy = encoder->FullDomainEncoding(var2);
1119 for (
const auto value_literal : copy) {
1120 const IntegerValue target_value = rhs - value_literal.value * coeff2;
1121 const auto& it = term1_value_to_literal.find(target_value);
1122 if (it != term1_value_to_literal.end()) {
1123 const Literal target_literal = it->second;
1125 enforcement_literal,
1126 {value_literal.literal.Negated(), target_literal.Negated()}));
1131bool IsPartOfProductEncoding(
const ConstraintProto&
ct) {
1132 if (
ct.enforcement_literal().size() != 1)
return false;
1133 if (
ct.linear().vars().size() > 2)
return false;
1134 if (
ct.linear().domain().size() != 2)
return false;
1135 if (
ct.linear().domain(0) != 0)
return false;
1136 if (
ct.linear().domain(1) != 0)
return false;
1137 for (
const int64_t coeff :
ct.linear().coeffs()) {
1138 if (std::abs(coeff) != 1)
return false;
1148 std::vector<IntegerVariable>* vars,
1149 std::vector<int64_t>* coeffs,
1153 if (m->
GetOrCreate<SatParameters>()->enumerate_all_solutions()) {
1158 std::vector<IntegerVariable> bucket_sum_vars;
1159 std::vector<int64_t> bucket_sum_coeffs;
1160 std::vector<IntegerVariable> local_vars;
1161 std::vector<int64_t> local_coeffs;
1164 const int64_t num_vars = vars->size();
1165 const int64_t num_buckets =
static_cast<int>(std::round(std::sqrt(num_vars)));
1167 for (int64_t
b = 0;
b < num_buckets; ++
b) {
1169 local_coeffs.clear();
1170 int64_t bucket_lb = 0;
1171 int64_t bucket_ub = 0;
1173 const int64_t limit = num_vars * (
b + 1);
1174 for (;
i * num_buckets < limit; ++
i) {
1175 const IntegerVariable
var = (*vars)[
i];
1176 const int64_t coeff = (*coeffs)[
i];
1177 gcd = std::gcd(gcd, std::abs(coeff));
1178 local_vars.push_back(
var);
1179 local_coeffs.push_back(coeff);
1180 const int64_t term1 = coeff * integer_trail->LowerBound(
var).value();
1181 const int64_t term2 = coeff * integer_trail->UpperBound(
var).value();
1182 bucket_lb += std::min(term1, term2);
1183 bucket_ub += std::max(term1, term2);
1185 if (gcd == 0)
continue;
1188 for (int64_t& ref : local_coeffs) ref /= gcd;
1193 const IntegerVariable bucket_sum =
1194 integer_trail->AddIntegerVariable(bucket_lb, bucket_ub);
1195 bucket_sum_vars.push_back(bucket_sum);
1196 bucket_sum_coeffs.push_back(gcd);
1197 local_vars.push_back(bucket_sum);
1198 local_coeffs.push_back(-1);
1209 *vars = bucket_sum_vars;
1210 *coeffs = bucket_sum_coeffs;
1214 auto* mapping = m->GetOrCreate<CpModelMapping>();
1215 if (
ct.linear().vars().empty()) {
1219 std::vector<Literal> clause;
1220 for (
const int ref :
ct.enforcement_literal()) {
1221 clause.push_back(mapping->Literal(ref).Negated());
1225 VLOG(1) <<
"Trivially UNSAT constraint: " <<
ct;
1226 m->GetOrCreate<
SatSolver>()->NotifyThatModelIsUnsat();
1231 if (IsPartOfProductEncoding(
ct)) {
1232 const Literal l = mapping->Literal(
ct.enforcement_literal(0));
1233 auto* detector = m->GetOrCreate<ProductDetector>();
1234 if (
ct.linear().vars().size() == 1) {
1237 detector->ProcessConditionalZero(l,
1238 mapping->Integer(
ct.linear().vars(0)));
1239 }
else if (
ct.linear().vars().size() == 2) {
1240 const IntegerVariable
x = mapping->Integer(
ct.linear().vars(0));
1241 const IntegerVariable
y = mapping->Integer(
ct.linear().vars(1));
1242 detector->ProcessConditionalEquality(
1248 auto* integer_trail = m->GetOrCreate<IntegerTrail>();
1249 std::vector<IntegerVariable> vars = mapping->Integers(
ct.linear().vars());
1250 std::vector<int64_t> coeffs = ValuesFromProto(
ct.linear().coeffs());
1256 IntegerValue min_sum(0);
1257 IntegerValue max_sum(0);
1258 IntegerValue max_domain_size(0);
1259 bool all_booleans =
true;
1260 for (
int i = 0;
i < vars.size(); ++
i) {
1261 if (all_booleans && !mapping->IsBoolean(
ct.linear().vars(
i))) {
1262 all_booleans =
false;
1264 const IntegerValue lb = integer_trail->LowerBound(vars[
i]);
1265 const IntegerValue ub = integer_trail->UpperBound(vars[
i]);
1266 max_domain_size = std::max(max_domain_size, ub - lb + 1);
1267 const IntegerValue term_a = coeffs[
i] * lb;
1268 const IntegerValue term_b = coeffs[
i] * ub;
1269 min_sum += std::min(term_a, term_b);
1270 max_sum += std::max(term_a, term_b);
1274 const SatParameters& params = *m->GetOrCreate<SatParameters>();
1275 if (params.auto_detect_greater_than_at_least_one_of() &&
1276 ct.enforcement_literal().size() == 1 && vars.size() <= 2) {
1278 int64_t rhs_min =
ct.linear().domain(0);
1279 int64_t rhs_max =
ct.linear().domain(
ct.linear().domain().size() - 1);
1280 rhs_min = std::max(rhs_min, min_sum.value());
1281 rhs_max = std::min(rhs_max, max_sum.value());
1283 auto* detector = m->GetOrCreate<GreaterThanAtLeastOneOfDetector>();
1284 const Literal
lit = mapping->Literal(
ct.enforcement_literal(0));
1286 if (vars.size() == 1) {
1287 detector->Add(
lit, {vars[0], coeffs[0]}, {}, rhs_min, rhs_max);
1288 }
else if (vars.size() == 2) {
1289 detector->Add(
lit, {vars[0], coeffs[0]}, {vars[1], coeffs[1]}, rhs_min,
1296 auto* precedences = m->GetOrCreate<PrecedenceRelations>();
1300 int64_t rhs_min =
ct.linear().domain(0);
1301 int64_t rhs_max =
ct.linear().domain(
ct.linear().domain().size() - 1);
1302 rhs_min = std::max(rhs_min, min_sum.value());
1303 rhs_max = std::min(rhs_max, max_sum.value());
1305 if (vars.size() == 2) {
1306 if (std::abs(coeffs[0]) == std::abs(coeffs[1])) {
1307 const int64_t magnitude = std::abs(coeffs[0]);
1308 IntegerVariable v1 = vars[0];
1309 IntegerVariable v2 = vars[1];
1314 precedences->Add(v1, v2,
CeilOfRatio(-rhs_max, magnitude));
1317 precedences->Add(v2, v1,
CeilOfRatio(rhs_min, magnitude));
1319 }
else if (vars.size() == 3) {
1320 for (
int i = 0;
i < 3; ++
i) {
1321 for (
int j = 0; j < 3; ++j) {
1322 if (
i == j)
continue;
1323 if (std::abs(coeffs[
i]) != std::abs(coeffs[j]))
continue;
1324 const int other = 3 -
i - j;
1327 const int64_t magnitude = std::abs(coeffs[
i]);
1328 IntegerVariable v1 = vars[
i];
1329 IntegerVariable v2 = vars[j];
1334 const int64_t coeff = coeffs[other];
1335 const int64_t other_lb =
1337 ? coeff * integer_trail->LowerBound(vars[other]).value()
1338 : coeff * integer_trail->UpperBound(vars[other]).value();
1339 precedences->Add(v1, v2,
CeilOfRatio(other_lb - rhs_max, magnitude));
1342 const int64_t other_ub =
1344 ? coeff * integer_trail->UpperBound(vars[other]).value()
1345 : coeff * integer_trail->LowerBound(vars[other]).value();
1346 precedences->Add(v2, v1,
CeilOfRatio(rhs_min - other_ub, magnitude));
1352 const IntegerValue domain_size_limit(
1353 params.max_domain_size_when_encoding_eq_neq_constraints());
1354 if (
ct.linear().vars_size() == 2 && !integer_trail->IsFixed(vars[0]) &&
1355 !integer_trail->IsFixed(vars[1]) &&
1356 max_domain_size <= domain_size_limit) {
1357 auto* encoder = m->GetOrCreate<IntegerEncoder>();
1358 if (params.boolean_encoding_level() > 0 && ConstraintIsEq(
ct.linear()) &&
1359 ct.linear().domain(0) != min_sum &&
ct.linear().domain(0) != max_sum &&
1360 encoder->VariableIsFullyEncoded(vars[0]) &&
1361 encoder->VariableIsFullyEncoded(vars[1])) {
1362 VLOG(3) <<
"Load AC version of " <<
ct <<
", var0 domain = "
1363 << integer_trail->InitialVariableDomain(vars[0])
1364 <<
", var1 domain = "
1365 << integer_trail->InitialVariableDomain(vars[1]);
1366 return LoadEquivalenceAC(mapping->Literals(
ct.enforcement_literal()),
1367 IntegerValue(coeffs[0]), vars[0],
1368 IntegerValue(coeffs[1]), vars[1],
1369 IntegerValue(
ct.linear().domain(0)), m);
1372 int64_t single_value = 0;
1373 if (params.boolean_encoding_level() > 0 &&
1374 ConstraintIsNEq(
ct.linear(), mapping, integer_trail, &single_value) &&
1375 single_value != min_sum && single_value != max_sum &&
1376 encoder->VariableIsFullyEncoded(vars[0]) &&
1377 encoder->VariableIsFullyEncoded(vars[1])) {
1378 VLOG(3) <<
"Load NAC version of " <<
ct <<
", var0 domain = "
1379 << integer_trail->InitialVariableDomain(vars[0])
1380 <<
", var1 domain = "
1381 << integer_trail->InitialVariableDomain(vars[1])
1382 <<
", value = " << single_value;
1383 return LoadEquivalenceNeqAC(mapping->Literals(
ct.enforcement_literal()),
1384 IntegerValue(coeffs[0]), vars[0],
1385 IntegerValue(coeffs[1]), vars[1],
1386 IntegerValue(single_value), m);
1394 ct.linear().domain_size() == 2 && all_booleans;
1395 if (!pseudo_boolean &&
1396 ct.linear().vars().size() > params.linear_split_size()) {
1397 const auto& domain =
ct.linear().domain();
1399 domain.size() > 2 || min_sum < domain[0],
1400 domain.size() > 2 || max_sum > domain[1], &vars, &coeffs, m);
1403 if (
ct.linear().domain_size() == 2) {
1404 const int64_t lb =
ct.linear().domain(0);
1405 const int64_t ub =
ct.linear().domain(1);
1406 const std::vector<Literal> enforcement_literals =
1407 mapping->Literals(
ct.enforcement_literal());
1408 if (all_booleans && enforcement_literals.empty()) {
1411 std::vector<LiteralWithCoeff> cst;
1412 for (
int i = 0;
i < vars.size(); ++
i) {
1413 const int ref =
ct.linear().vars(
i);
1414 cst.push_back({mapping->Literal(ref), coeffs[
i]});
1416 m->GetOrCreate<SatSolver>()->AddLinearConstraint(
1418 (max_sum > ub), ub, &cst);
1434 const bool special_case =
1435 ct.enforcement_literal().empty() &&
ct.linear().domain_size() == 4;
1439 const bool is_linear1 = !special_case && vars.size() == 1 && coeffs[0] == 1;
1441 std::vector<Literal> clause;
1442 std::vector<Literal> for_enumeration;
1443 auto* encoding = m->GetOrCreate<IntegerEncoder>();
1444 for (
int i = 0;
i <
ct.linear().domain_size();
i += 2) {
1445 const int64_t lb =
ct.linear().domain(
i);
1446 const int64_t ub =
ct.linear().domain(
i + 1);
1451 encoding->GetOrCreateLiteralAssociatedToEquality(vars[0], lb));
1453 }
else if (min_sum >= lb) {
1454 clause.push_back(encoding->GetOrCreateAssociatedLiteral(
1457 }
else if (max_sum <= ub) {
1458 clause.push_back(encoding->GetOrCreateAssociatedLiteral(
1464 const Literal subdomain_literal(
1465 special_case &&
i > 0 ? clause.back().Negated()
1467 clause.push_back(subdomain_literal);
1468 for_enumeration.push_back(subdomain_literal);
1478 const std::vector<Literal> enforcement_literals =
1479 mapping->Literals(
ct.enforcement_literal());
1482 if (params.enumerate_all_solutions() && !enforcement_literals.empty()) {
1483 Literal linear_is_enforced;
1484 if (enforcement_literals.size() == 1) {
1485 linear_is_enforced = enforcement_literals[0];
1488 std::vector<Literal> maintain_linear_is_enforced;
1489 for (
const Literal e_lit : enforcement_literals) {
1490 m->Add(
Implication(e_lit.Negated(), linear_is_enforced.Negated()));
1491 maintain_linear_is_enforced.push_back(e_lit.Negated());
1493 maintain_linear_is_enforced.push_back(linear_is_enforced);
1496 for (
const Literal
lit : for_enumeration) {
1497 m->Add(
Implication(linear_is_enforced.Negated(),
lit.Negated()));
1498 if (special_case)
break;
1502 if (!special_case) {
1503 for (
const Literal e_lit : enforcement_literals) {
1504 clause.push_back(e_lit.Negated());
1511 auto* mapping = m->GetOrCreate<CpModelMapping>();
1512 const std::vector<AffineExpression> expressions =
1513 mapping->Affines(
ct.all_diff().exprs());
1518 auto* mapping = m->GetOrCreate<CpModelMapping>();
1520 std::vector<AffineExpression> terms;
1521 for (
const LinearExpressionProto& expr :
ct.int_prod().exprs()) {
1522 terms.push_back(mapping->Affine(expr));
1524 switch (terms.size()) {
1526 auto* integer_trail = m->GetOrCreate<IntegerTrail>();
1527 auto* sat_solver = m->GetOrCreate<SatSolver>();
1530 sat_solver->NotifyThatModelIsUnsat();
1535 LinearConstraintBuilder builder(m, 0, 0);
1536 builder.AddTerm(prod, 1);
1537 builder.AddTerm(terms[0], -1);
1546 LOG(FATAL) <<
"Loading int_prod with arity > 2, should not be here.";
1553 auto* integer_trail = m->GetOrCreate<IntegerTrail>();
1558 if (integer_trail->IsFixed(denom)) {
1561 if (VLOG_IS_ON(1)) {
1562 LinearConstraintBuilder builder(m);
1563 if (m->GetOrCreate<ProductDecomposer>()->TryToLinearize(num, denom,
1565 VLOG(1) <<
"Division " <<
ct <<
" can be linearized";
1573 auto* mapping = m->GetOrCreate<CpModelMapping>();
1579 CHECK(integer_trail->IsFixed(mod));
1580 const IntegerValue fixed_modulo = integer_trail->FixedValue(mod);
1585 if (
ct.lin_max().exprs().empty()) {
1590 auto* mapping = m->GetOrCreate<CpModelMapping>();
1591 const LinearExpression
max = mapping->GetExprFromProto(
ct.lin_max().target());
1592 std::vector<LinearExpression> negated_exprs;
1593 negated_exprs.reserve(
ct.lin_max().exprs_size());
1594 for (
int i = 0;
i <
ct.lin_max().exprs_size(); ++
i) {
1595 negated_exprs.push_back(
1596 NegationOf(mapping->GetExprFromProto(
ct.lin_max().exprs(
i))));
1603 auto* mapping = m->GetOrCreate<CpModelMapping>();
1608 if (
ct.no_overlap_2d().x_intervals().empty())
return;
1610 const std::vector<IntervalVariable> x_intervals =
1611 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
1612 const std::vector<IntervalVariable> y_intervals =
1613 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
1618 auto* mapping = m->GetOrCreate<CpModelMapping>();
1619 const std::vector<IntervalVariable> intervals =
1620 mapping->Intervals(
ct.cumulative().intervals());
1622 const std::vector<AffineExpression> demands =
1623 mapping->Affines(
ct.cumulative().demands());
1624 m->Add(
Cumulative(intervals, demands, capacity));
1628 auto* mapping = m->GetOrCreate<CpModelMapping>();
1630 const std::vector<AffineExpression> times =
1631 mapping->Affines(
ct.reservoir().time_exprs());
1632 const std::vector<AffineExpression> level_changes =
1633 mapping->Affines(
ct.reservoir().level_changes());
1634 std::vector<Literal> presences;
1635 const int size =
ct.reservoir().time_exprs().size();
1636 for (
int i = 0;
i <
size; ++
i) {
1637 if (!
ct.reservoir().active_literals().empty()) {
1638 presences.push_back(mapping->Literal(
ct.reservoir().active_literals(
i)));
1640 presences.push_back(encoder->GetTrueLiteral());
1644 ct.reservoir().min_level(),
ct.reservoir().max_level(),
1649 const auto& circuit =
ct.circuit();
1650 if (circuit.tails().empty())
return;
1652 std::vector<int> tails(circuit.tails().begin(), circuit.tails().end());
1653 std::vector<int> heads(circuit.heads().begin(), circuit.heads().end());
1654 std::vector<Literal> literals =
1656 const int num_nodes =
ReindexArcs(&tails, &heads);
1661 const auto& routes =
ct.routes();
1662 if (routes.tails().empty())
return;
1664 std::vector<int> tails(routes.tails().begin(), routes.tails().end());
1665 std::vector<int> heads(routes.heads().begin(), routes.heads().end());
1666 std::vector<Literal> literals =
1668 const int num_nodes =
ReindexArcs(&tails, &heads);
1674 switch (
ct.constraint_case()) {
1675 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
1677 case ConstraintProto::ConstraintCase::kBoolOr:
1680 case ConstraintProto::ConstraintCase::kBoolAnd:
1683 case ConstraintProto::ConstraintCase::kAtMostOne:
1686 case ConstraintProto::ConstraintCase::kExactlyOne:
1689 case ConstraintProto::ConstraintCase::kBoolXor:
1692 case ConstraintProto::ConstraintProto::kLinear:
1695 case ConstraintProto::ConstraintProto::kAllDiff:
1698 case ConstraintProto::ConstraintProto::kIntProd:
1701 case ConstraintProto::ConstraintProto::kIntDiv:
1704 case ConstraintProto::ConstraintProto::kIntMod:
1707 case ConstraintProto::ConstraintProto::kLinMax:
1710 case ConstraintProto::ConstraintProto::kInterval:
1713 case ConstraintProto::ConstraintProto::kNoOverlap:
1716 case ConstraintProto::ConstraintProto::kNoOverlap2D:
1719 case ConstraintProto::ConstraintProto::kCumulative:
1722 case ConstraintProto::ConstraintProto::kReservoir:
1725 case ConstraintProto::ConstraintProto::kCircuit:
1728 case ConstraintProto::ConstraintProto::kRoutes:
Domain IntersectionWith(const Domain &domain) const
bool Contains(int64_t value) const
Domain Complement() const
Domain InverseMultiplicationBy(int64_t coeff) const
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
void RegisterWith(GenericLiteralWatcher *watcher)
bool Add(Literal literal, IntegerLiteral integer_literal)
void ReserveSpaceForNumVariables(int num_vars)
LiteralIndex Index() const
Literal(int signed_value)
T Add(std::function< T(Model *)> f)
bool AddProblemClause(absl::Span< const Literal > literals, bool is_safe=true)
CpModelProto proto
The output proto.
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
std::function< std::vector< ValueLiteralPair >(Model *)> FullyEncodeVariable(IntegerVariable var)
void LoadBoolXorConstraint(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)
Weighted sum >= constant.
void LoadCumulativeConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> LiteralXorIs(const std::vector< Literal > &literals, bool value)
Enforces the XOR of a set of literals to be equal to the given value.
bool RefIsPositive(int ref)
void LoadLinMaxConstraint(const ConstraintProto &ct, Model *m)
void LoadIntProdConstraint(const ConstraintProto &ct, Model *m)
void SplitAndLoadIntermediateConstraints(bool lb_required, bool ub_required, std::vector< IntegerVariable > *vars, std::vector< int64_t > *coeffs, Model *m)
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
Weighted sum <= constant.
const LiteralIndex kNoLiteralIndex(-1)
std::function< void(Model *)> ProductConstraint(AffineExpression a, AffineExpression b, AffineExpression p)
Adds the constraint: a * b = p.
void DetectOptionalVariables(const CpModelProto &model_proto, Model *m)
Automatically detect optional variables.
void LoadBoolOrConstraint(const ConstraintProto &ct, Model *m)
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)
enforcement_literals => clause.
IntType CeilOfRatio(IntType numerator, IntType denominator)
void LoadSubcircuitConstraint(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, Model *model, bool multiple_subcircuit_through_zero)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Returns the vector of the negated variables.
std::function< void(Model *)> FixedDivisionConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Adds the constraint: a / b = c where b is a constant.
bool HasEnforcementLiteral(const ConstraintProto &ct)
Small utility functions to deal with half-reified constraints.
void LoadVariables(const CpModelProto &model_proto, bool view_all_booleans_as_integers, Model *m)
void LoadIntModConstraint(const ConstraintProto &ct, Model *m)
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> Implication(absl::Span< const Literal > enforcement_literals, IntegerLiteral i)
const IntervalVariable kNoIntervalVariable(-1)
void LoadBooleanSymmetries(const CpModelProto &model_proto, Model *m)
std::function< void(Model *)> Cumulative(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
std::function< void(Model *)> DivisionConstraint(AffineExpression num, AffineExpression denom, AffineExpression div)
Adds the constraint: num / denom = div. (denom > 0).
void LoadRoutesConstraint(const ConstraintProto &ct, Model *m)
void LoadAtMostOneConstraint(const ConstraintProto &ct, Model *m)
void AddFullEncodingFromSearchBranching(const CpModelProto &model_proto, Model *m)
std::vector< int > UsedVariables(const ConstraintProto &ct)
void LoadCircuitConstraint(const ConstraintProto &ct, Model *m)
void ExtractElementEncoding(const CpModelProto &model_proto, Model *m)
std::function< void(Model *)> AtMostOneConstraint(const std::vector< Literal > &literals)
void LoadReservoirConstraint(const ConstraintProto &ct, Model *m)
void AddWeightedSumLowerOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t upper_bound, Model *model)
enforcement_literals => sum <= upper_bound
int ReindexArcs(IntContainer *tails, IntContainer *heads, absl::flat_hash_map< int, int > *mapping_output=nullptr)
void LoadNoOverlapConstraint(const ConstraintProto &ct, Model *m)
void LoadAllDiffConstraint(const ConstraintProto &ct, Model *m)
void AddDisjunctive(const std::vector< IntervalVariable > &intervals, Model *model)
std::vector< Literal > Literals(absl::Span< const int > input)
void LoadNoOverlap2dConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Reads a Domain from the domain field of a proto.
void LoadBoolAndConstraint(const ConstraintProto &ct, Model *m)
void AddNonOverlappingRectangles(const std::vector< IntervalVariable > &x, const std::vector< IntervalVariable > &y, Model *model)
void LoadExactlyOneConstraint(const ConstraintProto &ct, Model *m)
std::function< void(Model *)> ExactlyOneConstraint(const std::vector< Literal > &literals)
bool LoadConstraint(const ConstraintProto &ct, Model *m)
void PropagateEncodingFromEquivalenceRelations(const CpModelProto &model_proto, Model *m)
void AddReservoirConstraint(std::vector< AffineExpression > times, std::vector< AffineExpression > deltas, std::vector< Literal > presences, int64_t min_level, int64_t max_level, Model *model)
std::function< void(Model *)> FixedModuloConstraint(AffineExpression a, IntegerValue b, AffineExpression c)
Adds the constraint: a % b = c where b is a constant.
const BooleanVariable kNoBooleanVariable(-1)
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
void AddWeightedSumGreaterOrEqual(absl::Span< const Literal > enforcement_literals, absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coefficients, int64_t lower_bound, Model *model)
enforcement_literals => sum >= lower_bound
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< AffineExpression > &expressions)
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
void ExtractEncoding(const CpModelProto &model_proto, Model *m)
void LoadIntDivConstraint(const ConstraintProto &ct, Model *m)
In SWIG mode, we don't want anything besides these top-level includes.
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
var * coeff + constant >= bound.
IntegerLiteral LowerOrEqual(IntegerValue bound) const
var * coeff + constant <= bound.
std::vector< int > variables
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
#define SOLVER_LOG(logger,...)