21 #include "absl/container/flat_hash_set.h" 44 if (encoder ==
nullptr)
return false;
45 if (!encoder->VariableIsFullyEncoded(
var))
return false;
56 std::vector<Literal> at_most_one;
58 for (
const auto value_literal : encoding) {
59 const Literal lit = value_literal.literal;
60 const IntegerValue
delta = value_literal.value - var_min;
62 at_most_one.push_back(lit);
63 if (!at_least_one.
AddLiteralTerm(lit, IntegerValue(1)))
return false;
64 if (
delta != IntegerValue(0)) {
78 std::pair<IntegerValue, IntegerValue> GetMinAndMaxNotEncoded(
80 const absl::flat_hash_set<IntegerValue>& encoded_values,
82 const auto* domains =
model.Get<IntegerDomains>();
83 if (domains ==
nullptr ||
var >= domains->size()) {
90 for (
const int64_t v : (*domains)[
var].Values()) {
91 if (!encoded_values.contains(IntegerValue(v))) {
92 min = IntegerValue(v);
98 const auto& domain = (*domains)[
var];
99 for (
int i = domain.NumIntervals() - 1; i >= 0; --i) {
100 const ClosedInterval
interval = domain[i];
102 if (!encoded_values.contains(v)) {
113 bool LinMaxContainsOnlyOneVarInExpressions(
const ConstraintProto&
ct) {
114 CHECK_EQ(
ct.constraint_case(), ConstraintProto::ConstraintCase::kLinMax);
115 int current_var = -1;
116 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
117 if (expr.vars().empty())
continue;
118 if (expr.vars().size() > 1)
return false;
120 if (current_var == -1) {
122 }
else if (
var != current_var) {
129 bool IntMaxIsIntAbs(
const ConstraintProto&
ct) {
130 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kIntMax ||
131 ct.int_max().vars_size() != 2) {
142 void CollectAffineExpressionWithSingleVariable(
143 const ConstraintProto&
ct, CpModelMapping* mapping, IntegerVariable*
var,
144 std::vector<std::pair<IntegerValue, IntegerValue>>* affines) {
145 DCHECK(LinMaxContainsOnlyOneVarInExpressions(
ct));
146 CHECK_EQ(
ct.constraint_case(), ConstraintProto::ConstraintCase::kLinMax);
149 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
150 if (expr.vars().empty()) {
151 affines->push_back({IntegerValue(0), IntegerValue(expr.offset())});
154 const IntegerVariable affine_var = mapping->Integer(expr.vars(0));
161 {IntegerValue(expr.coeffs(0)), IntegerValue(expr.offset())});
165 {IntegerValue(-expr.coeffs(0)), IntegerValue(expr.offset())});
177 if (encoder ==
nullptr || integer_trail ==
nullptr)
return;
179 const std::vector<IntegerEncoder::ValueLiteralPair>& encoding =
180 encoder->PartialDomainEncoding(
var);
181 if (encoding.empty())
return;
183 std::vector<Literal> at_most_one_ct;
184 absl::flat_hash_set<IntegerValue> encoded_values;
185 for (
const auto value_literal : encoding) {
194 at_most_one_ct.push_back(
literal);
195 encoded_values.insert(value_literal.value);
197 if (encoded_values.empty())
return;
203 const auto pair = GetMinAndMaxNotEncoded(
var, encoded_values,
model);
213 for (
const auto value_literal : encoding) {
214 const Literal lit = value_literal.literal;
217 encoding_ct.
AddLiteralTerm(lit, IntegerValue(-value_literal.value)));
225 const IntegerValue d_min = pair.first;
228 for (
const auto value_literal : encoding) {
230 d_min - value_literal.value));
234 const IntegerValue d_max = pair.second;
237 for (
const auto value_literal : encoding) {
239 d_max - value_literal.value));
253 if (integer_trail ==
nullptr || encoder ==
nullptr)
return;
255 const std::map<IntegerValue, Literal>& greater_than_encoding =
256 encoder->PartialGreaterThanEncoding(
var);
257 if (greater_than_encoding.empty())
return;
262 IntegerValue prev_used_bound = integer_trail->
LowerBound(
var);
267 for (
const auto entry : greater_than_encoding) {
268 if (entry.first <= prev_used_bound)
continue;
270 const LiteralIndex literal_index = entry.second.Index();
271 const IntegerValue diff = prev_used_bound - entry.first;
280 prev_used_bound = entry.first;
281 prev_literal_index = literal_index;
289 IntegerValue prev_used_bound = integer_trail->LowerBound(
NegationOf(
var));
293 for (
const auto entry :
295 if (entry.first <= prev_used_bound)
continue;
296 const IntegerValue diff = prev_used_bound - entry.first;
300 prev_used_bound = entry.first;
308 void AppendEnforcedUpperBound(
const Literal enforcing_lit,
309 const IntegerVariable target,
310 const IntegerVariable bounding_var, Model*
model,
311 LinearRelaxation* relaxation) {
312 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
313 const IntegerValue max_target_value = integer_trail->UpperBound(target);
314 const IntegerValue min_var_value = integer_trail->LowerBound(bounding_var);
315 const IntegerValue max_term_value = max_target_value - min_var_value;
317 lc.AddTerm(target, IntegerValue(1));
318 lc.AddTerm(bounding_var, IntegerValue(-1));
319 CHECK(lc.AddLiteralTerm(enforcing_lit, max_term_value));
320 relaxation->linear_constraints.push_back(lc.Build());
325 void AppendEnforcedLinearExpression(
326 const std::vector<Literal>& enforcing_literals,
327 const LinearExpression& expr,
const IntegerValue rhs_domain_min,
328 const IntegerValue rhs_domain_max,
const Model&
model,
329 LinearRelaxation* relaxation) {
330 CHECK_EQ(expr.offset, IntegerValue(0));
332 const IntegerTrail* integer_trail =
model.Get<IntegerTrail>();
333 const IntegerValue min_expr_value =
336 if (rhs_domain_min > min_expr_value) {
341 for (
const Literal&
literal : enforcing_literals) {
343 rhs_domain_min - min_expr_value));
345 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
346 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
348 relaxation->linear_constraints.push_back(lc.Build());
350 const IntegerValue max_expr_value =
352 if (rhs_domain_max < max_expr_value) {
357 for (
const Literal&
literal : enforcing_literals) {
359 rhs_domain_max - max_expr_value));
361 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
362 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
364 relaxation->linear_constraints.push_back(lc.Build());
368 bool AllLiteralsHaveViews(
const IntegerEncoder& encoder,
369 const std::vector<Literal>& literals) {
370 for (
const Literal lit : literals) {
371 if (!encoder.LiteralOrNegationHasView(lit))
return false;
382 for (
const int enforcement_ref :
ct.enforcement_literal()) {
386 for (
const int ref :
ct.bool_or().literals()) {
387 CHECK(lc.AddLiteralTerm(mapping->Literal(ref), IntegerValue(1)));
400 if (
ct.enforcement_literal().size() == 1) {
402 for (
const int ref :
ct.bool_and().literals()) {
404 {enforcement, mapping->
Literal(ref).Negated()});
411 int num_literals =
ct.bool_and().literals_size();
414 for (
const int ref :
ct.bool_and().literals()) {
417 for (
const int enforcement_ref :
ct.enforcement_literal()) {
419 IntegerValue(num_literals)));
430 mapping->Literals(
ct.at_most_one().literals()));
439 const std::vector<Literal> literals =
440 mapping->Literals(
ct.exactly_one().literals());
441 if (AllLiteralsHaveViews(*encoder, literals)) {
443 for (
const Literal lit : literals) {
458 if (num_literals == 1) {
463 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
467 if (num_literals == 2) {
470 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
476 encoder->AssociateToIntegerEqualValue(lit.
Negated(), var2, IntegerValue(1));
481 std::vector<Literal> literals;
483 for (
int i = 0; i < num_literals; ++i) {
486 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
487 literals.push_back(lit);
497 void AddIntMaxLowerRelaxation(IntegerVariable target,
498 const std::vector<IntegerVariable>& vars,
499 Model*
model, LinearRelaxation* relaxation) {
502 for (
const IntegerVariable
var : vars) {
505 if (target ==
var)
continue;
507 lc.AddTerm(
var, IntegerValue(1));
508 lc.AddTerm(target, IntegerValue(-1));
509 relaxation->linear_constraints.push_back(lc.Build());
513 void AddIntAbsUpperRelaxation(IntegerVariable target, IntegerVariable
var,
514 Model*
model, LinearRelaxation* relaxation) {
515 LinearExpression target_expr;
516 target_expr.vars.push_back(target);
517 target_expr.coeffs.push_back(IntegerValue(1));
518 const std::vector<std::pair<IntegerValue, IntegerValue>> affines = {
519 {IntegerValue(1), IntegerValue(0)}, {IntegerValue(-1), IntegerValue(0)}};
520 relaxation->linear_constraints.push_back(
524 void AddIntMaxUpperRelaxation(IntegerVariable target,
525 const std::vector<IntegerVariable>& vars,
526 Model*
model, LinearRelaxation* relaxation) {
530 GenericLiteralWatcher* watcher =
model->GetOrCreate<GenericLiteralWatcher>();
531 std::vector<Literal> literals =
533 for (
int i = 0; i < vars.size(); ++i) {
539 AppendEnforcedUpperBound(literals[i], target, vars[i],
model, relaxation);
540 IntegerSumLE* upper_bound_constraint =
new IntegerSumLE(
541 {literals[i]}, {target, vars[i]}, {IntegerValue(1), IntegerValue(-1)},
542 IntegerValue(0),
model);
543 upper_bound_constraint->RegisterWith(watcher);
544 model->TakeOwnership(upper_bound_constraint);
557 const IntegerVariable target = mapping->
Integer(
ct.int_max().target());
558 const std::vector<IntegerVariable> vars =
559 mapping->Integers(
ct.int_max().vars());
561 AddIntMaxLowerRelaxation(target, vars,
model, relaxation);
562 if (IntMaxIsIntAbs(
ct)) {
566 }
else if (linearization_level > 1) {
567 AddIntMaxUpperRelaxation(target, vars,
model, relaxation);
575 const int num_arcs =
ct.circuit().literals_size();
576 CHECK_EQ(num_arcs,
ct.circuit().tails_size());
577 CHECK_EQ(num_arcs,
ct.circuit().heads_size());
581 std::map<int, std::vector<Literal>> incoming_arc_constraints;
582 std::map<int, std::vector<Literal>> outgoing_arc_constraints;
583 for (
int i = 0; i < num_arcs; i++) {
585 const int tail =
ct.circuit().tails(i);
586 const int head =
ct.circuit().heads(i);
590 outgoing_arc_constraints[
tail].push_back(arc);
591 incoming_arc_constraints[
head].push_back(arc);
593 for (
const auto* node_map :
594 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
595 for (
const auto& entry : *node_map) {
596 const std::vector<Literal>& exactly_one = entry.second;
597 if (exactly_one.size() > 1) {
600 for (
const Literal l : exactly_one) {
616 const int num_arcs =
ct.routes().literals_size();
624 std::map<int, std::vector<Literal>> incoming_arc_constraints;
625 std::map<int, std::vector<Literal>> outgoing_arc_constraints;
626 for (
int i = 0; i < num_arcs; i++) {
628 const int tail =
ct.routes().tails(i);
629 const int head =
ct.routes().heads(i);
633 outgoing_arc_constraints[
tail].push_back(arc);
634 incoming_arc_constraints[
head].push_back(arc);
636 for (
const auto* node_map :
637 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
638 for (
const auto& entry : *node_map) {
639 if (entry.first == 0)
continue;
640 const std::vector<Literal>& exactly_one = entry.second;
641 if (exactly_one.size() > 1) {
644 for (
const Literal l : exactly_one) {
656 for (
const Literal& incoming_arc : incoming_arc_constraints[0]) {
659 for (
const Literal& outgoing_arc : outgoing_arc_constraints[0]) {
669 if (
ct.interval().has_start_view())
return;
672 const IntegerVariable start = mapping->
Integer(
ct.interval().start());
673 const IntegerVariable size = mapping->Integer(
ct.interval().size());
674 const IntegerVariable end = mapping->Integer(
ct.interval().end());
676 const bool size_is_fixed = integer_trail->
IsFixed(size);
677 const IntegerValue rhs =
678 size_is_fixed ? -integer_trail->
LowerBound(size) : IntegerValue(0);
680 lc.
AddTerm(start, IntegerValue(1));
681 if (!size_is_fixed) {
682 lc.
AddTerm(size, IntegerValue(1));
684 lc.
AddTerm(end, IntegerValue(-1));
690 AppendEnforcedLinearExpression(mapping->Literals(
ct.enforcement_literal()),
700 const std::vector<IntegerVariable>& demands,
701 const std::vector<LinearExpression>& energies,
702 IntegerValue capacity_upper_bound,
Model*
model,
707 model->TakeOwnership(helper);
708 const int num_intervals = helper->NumTasks();
715 int num_variable_sizes = 0;
716 int num_optionals = 0;
719 min_of_starts =
std::min(min_of_starts, helper->StartMin(
index));
722 if (helper->IsOptional(
index)) {
726 if (!helper->SizeIsFixed(
index) ||
727 (!demands.empty() && !integer_trail->
IsFixed(demands[
index]))) {
728 num_variable_sizes++;
732 VLOG(2) <<
"Span [" << min_of_starts <<
".." << max_of_ends <<
"] with " 733 << num_optionals <<
" optional intervals, and " << num_variable_sizes
734 <<
" variable size intervals out of " << num_intervals
737 if (num_variable_sizes + num_optionals == 0)
return;
739 const IntegerVariable span_start =
742 IntegerValue(0), max_of_ends - min_of_starts);
743 const IntegerVariable span_end =
746 IntervalVariable span_var;
747 if (num_optionals < num_intervals) {
751 span_var =
model->Add(
758 lc.
AddTerm(span_size, -capacity_upper_bound);
759 for (
int i = 0; i < num_intervals; ++i) {
760 const IntegerValue demand_lower_bound =
761 demands.empty() ? IntegerValue(1)
763 const bool demand_is_fixed =
764 demands.empty() || integer_trail->
IsFixed(demands[i]);
765 if (!helper->IsOptional(i)) {
766 if (demand_is_fixed) {
767 lc.
AddTerm(helper->Sizes()[i], demand_lower_bound);
768 }
else if (!helper->SizeIsFixed(i) && !energies.empty()) {
778 helper->SizeMin(i) * demand_lower_bound)) {
793 const std::vector<IntegerVariable> demands =
795 std::vector<IntervalVariable> intervals =
796 mapping->Intervals(
ct.cumulative().intervals());
797 const IntegerValue capacity_upper_bound =
799 mapping->Integer(
ct.cumulative().capacity()));
800 std::vector<LinearExpression> energies;
801 energies.reserve(
ct.cumulative().energies_size());
802 for (
int i = 0; i <
ct.cumulative().energies_size(); ++i) {
805 energies.push_back(mapping->GetExprFromProto(
ct.cumulative().energies(i)));
819 std::vector<IntervalVariable> intervals =
822 IntegerValue(1),
model,
833 NegationOf(mapping->GetExprFromProto(
ct.lin_max().target()));
834 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
836 mapping->GetExprFromProto(
ct.lin_max().exprs(i));
851 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
853 CollectAffineExpressionWithSingleVariable(
ct, mapping, &
var, &affines);
869 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
871 CollectAffineExpressionWithSingleVariable(
ct, mapping, &
var, &affines);
877 CHECK_EQ(1,
ct.lin_max().target().vars_size());
881 target_expr,
var, affines,
"AffineMax",
model));
887 const IntegerVariable
var =
891 target_expr.
vars.push_back(mapping->Integer(
ct.int_max().target()));
892 target_expr.
coeffs.push_back(IntegerValue(1));
893 const std::vector<std::pair<IntegerValue, IntegerValue>> affines = {
894 {IntegerValue(1), IntegerValue(0)}, {IntegerValue(-1), IntegerValue(0)}};
905 IntegerVariable target,
const std::vector<Literal>& alternative_literals,
906 const std::vector<LinearExpression>& exprs,
Model*
model,
908 const int num_exprs = exprs.size();
912 for (
int i = 0; i < num_exprs; ++i) {
915 local_expr.
vars.push_back(target);
916 local_expr.
coeffs = exprs[i].coeffs;
917 local_expr.
coeffs.push_back(IntegerValue(1));
930 std::vector<IntegerVariable> x_vars;
931 for (
int i = 0; i < num_exprs; ++i) {
932 x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end());
937 DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable
var) {
941 std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
942 num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
945 for (
int i = 0; i < num_exprs; ++i) {
946 for (
int j = 0; j < num_exprs; ++j) {
947 if (i == j)
continue;
948 for (
const IntegerVariable x_var : x_vars) {
951 const IntegerValue diff =
953 sum_of_max_corner_diff[i][j] +=
std::max(diff * lb, diff * ub);
957 for (
int i = 0; i < num_exprs; ++i) {
959 lc.
AddTerm(target, IntegerValue(1));
960 for (
int j = 0; j < exprs[i].vars.size(); ++j) {
961 lc.
AddTerm(exprs[i].vars[j], -exprs[i].coeffs[j]);
963 for (
int j = 0; j < num_exprs; ++j) {
965 -exprs[j].offset - sum_of_max_corner_diff[i][j]));
972 bool linearize_enforced_constraints,
984 const IntegerValue rhs_domain_min = IntegerValue(
ct.linear().domain(0));
985 const IntegerValue rhs_domain_max =
986 IntegerValue(
ct.linear().domain(
ct.linear().domain_size() - 1));
993 for (
int i = 0; i <
ct.linear().vars_size(); i++) {
994 const int ref =
ct.linear().vars(i);
995 const int64_t coeff =
ct.linear().coeffs(i);
996 lc.
AddTerm(mapping->Integer(ref), IntegerValue(coeff));
1003 if (!linearize_enforced_constraints)
return;
1007 if (!mapping->IsHalfEncodingConstraint(&
ct) &&
ct.linear().vars_size() <= 1) {
1011 std::vector<Literal> enforcing_literals;
1012 enforcing_literals.reserve(
ct.enforcement_literal_size());
1013 for (
const int enforcement_ref :
ct.enforcement_literal()) {
1014 enforcing_literals.push_back(mapping->Literal(enforcement_ref));
1017 expr.
vars.reserve(
ct.linear().vars_size());
1018 expr.
coeffs.reserve(
ct.linear().vars_size());
1019 for (
int i = 0; i <
ct.linear().vars_size(); i++) {
1020 int ref =
ct.linear().vars(i);
1021 IntegerValue coeff(
ct.linear().coeffs(i));
1026 const IntegerVariable int_var = mapping->Integer(ref);
1027 expr.
vars.push_back(int_var);
1028 expr.
coeffs.push_back(coeff);
1030 AppendEnforcedLinearExpression(enforcing_literals, expr, rhs_domain_min,
1031 rhs_domain_max, *
model, relaxation);
1049 switch (
ct.constraint_case()) {
1050 case ConstraintProto::ConstraintCase::kBoolOr: {
1051 if (linearization_level > 1) {
1056 case ConstraintProto::ConstraintCase::kBoolAnd: {
1057 if (linearization_level > 1) {
1062 case ConstraintProto::ConstraintCase::kAtMostOne: {
1066 case ConstraintProto::ConstraintCase::kExactlyOne: {
1070 case ConstraintProto::ConstraintCase::kIntMax: {
1074 case ConstraintProto::ConstraintCase::kLinMax: {
1076 if (LinMaxContainsOnlyOneVarInExpressions(
ct)) {
1081 case ConstraintProto::ConstraintCase::kLinear: {
1083 ct, linearization_level > 1,
model,
1087 case ConstraintProto::ConstraintCase::kCircuit: {
1091 case ConstraintProto::ConstraintCase::kRoutes: {
1095 case ConstraintProto::ConstraintCase::kInterval: {
1096 if (linearization_level > 1) {
1101 case ConstraintProto::ConstraintCase::kNoOverlap: {
1102 if (linearization_level > 1) {
1107 case ConstraintProto::ConstraintCase::kCumulative: {
1108 if (linearization_level > 1) {
1122 std::vector<int> tails(
ct.circuit().tails().begin(),
1123 ct.circuit().tails().end());
1124 std::vector<int> heads(
ct.circuit().heads().begin(),
1125 ct.circuit().heads().end());
1127 std::vector<Literal> literals = mapping->Literals(
ct.circuit().literals());
1128 const int num_nodes =
ReindexArcs(&tails, &heads);
1131 num_nodes, tails, heads, literals, m));
1136 std::vector<int> tails(
ct.routes().tails().begin(),
1137 ct.routes().tails().end());
1138 std::vector<int> heads(
ct.routes().heads().begin(),
1139 ct.routes().heads().end());
1141 std::vector<Literal> literals = mapping->Literals(
ct.routes().literals());
1144 for (
int i = 0; i <
ct.routes().tails_size(); ++i) {
1145 num_nodes =
std::max(num_nodes, 1 +
ct.routes().tails(i));
1146 num_nodes =
std::max(num_nodes, 1 +
ct.routes().heads(i));
1148 if (
ct.routes().demands().empty() ||
ct.routes().capacity() == 0) {
1153 const std::vector<int64_t> demands(
ct.routes().demands().begin(),
1154 ct.routes().demands().end());
1156 num_nodes, tails, heads, literals, demands,
ct.routes().capacity(), m));
1163 if (
ct.int_prod().vars_size() != 2)
return;
1168 IntegerVariable z = mapping->
Integer(
ct.int_prod().target());
1169 IntegerVariable x = mapping->Integer(
ct.int_prod().vars(0));
1170 IntegerVariable y = mapping->Integer(
ct.int_prod().vars(1));
1173 IntegerValue x_lb = integer_trail->
LowerBound(x);
1174 IntegerValue x_ub = integer_trail->
UpperBound(x);
1175 IntegerValue y_lb = integer_trail->
LowerBound(y);
1176 IntegerValue y_ub = integer_trail->
UpperBound(y);
1180 if (x_lb < 0 && x_ub > 0)
return;
1191 if (x_lb < 0 && x_ub > 0)
return;
1192 if (y_lb < 0 && y_ub > 0)
return;
1215 const int num_vars =
ct.all_diff().vars_size();
1216 if (num_vars <= m->GetOrCreate<SatParameters>()->max_all_diff_cut_size()) {
1217 std::vector<IntegerVariable> vars = mapping->Integers(
ct.all_diff().vars());
1228 const std::vector<IntegerVariable> demands =
1229 mapping->
Integers(
ct.cumulative().demands());
1230 const std::vector<IntervalVariable> intervals =
1231 mapping->Intervals(
ct.cumulative().intervals());
1232 const IntegerVariable
capacity = mapping->Integer(
ct.cumulative().capacity());
1233 std::vector<LinearExpression> energies;
1234 energies.reserve(
ct.cumulative().energies_size());
1235 for (
int i = 0; i <
ct.cumulative().energies_size(); ++i) {
1238 energies.push_back(mapping->GetExprFromProto(
ct.cumulative().energies(i)));
1244 intervals,
capacity, demands, energies, m));
1257 std::vector<IntervalVariable> intervals =
1272 std::vector<IntervalVariable> x_intervals =
1273 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
1274 std::vector<IntervalVariable> y_intervals =
1275 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
1289 if (
ct.lin_max().target().vars_size() != 1)
return;
1290 if (
ct.lin_max().target().coeffs(0) != 1)
return;
1291 if (
ct.lin_max().target().offset() != 0)
return;
1293 const IntegerVariable target =
1294 mapping->
Integer(
ct.lin_max().target().vars(0));
1295 std::vector<LinearExpression> exprs;
1296 exprs.reserve(
ct.lin_max().exprs_size());
1297 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
1304 const std::vector<Literal> alternative_literals =
1314 std::vector<IntegerVariable> z_vars;
1316 for (
const Literal lit : alternative_literals) {
1317 z_vars.push_back(encoder->GetLiteralView(lit));
1327 switch (
ct.constraint_case()) {
1328 case ConstraintProto::ConstraintCase::kCircuit: {
1329 if (linearization_level > 1) {
1334 case ConstraintProto::ConstraintCase::kRoutes: {
1335 if (linearization_level > 1) {
1340 case ConstraintProto::ConstraintCase::kIntProd: {
1344 case ConstraintProto::ConstraintCase::kAllDiff: {
1345 if (linearization_level > 1) {
1350 case ConstraintProto::ConstraintCase::kCumulative: {
1351 if (linearization_level > 1) {
1356 case ConstraintProto::ConstraintCase::kNoOverlap: {
1357 if (linearization_level > 1) {
1362 case ConstraintProto::ConstraintCase::kNoOverlap2D: {
1363 if (linearization_level > 1) {
1368 case ConstraintProto::ConstraintCase::kIntMax: {
1369 if (linearization_level > 1 && IntMaxIsIntAbs(
ct)) {
1374 case ConstraintProto::ConstraintCase::kLinMax: {
1375 if (linearization_level > 1) {
1376 if (LinMaxContainsOnlyOneVarInExpressions(
ct)) {
1399 if (
ct.constraint_case() != ConstraintProto::ConstraintCase::kExactlyOne) {
1404 absl::flat_hash_map<IntegerVariable,
1405 std::vector<std::pair<Literal, IntegerValue>>>
1406 var_to_literal_value_list;
1407 for (
const int l :
ct.exactly_one().literals()) {
1409 for (
const auto& var_value : implied_bounds->GetImpliedValues(
literal)) {
1410 var_to_literal_value_list[var_value.first].push_back(
1411 std::make_pair(
literal, var_value.second));
1416 for (
const auto& var_encoding : var_to_literal_value_list) {
1417 if (var_encoding.second.size() <
ct.exactly_one().literals_size()) {
1426 absl::flat_hash_set<IntegerValue> values;
1427 for (
const auto& literal_value : var_encoding.second) {
1428 min_value =
std::min(min_value, literal_value.second);
1429 values.insert(literal_value.second);
1431 if (values.size() ==
ct.exactly_one().literals_size())
continue;
1435 linear_encoding.
AddTerm(var_encoding.first, IntegerValue(-1));
1436 for (
const auto& literal_value : var_encoding.second) {
1437 const IntegerValue delta_min = literal_value.second - min_value;
1438 if (delta_min != 0) {
1439 if (!linear_encoding.
AddLiteralTerm(literal_value.first, delta_min)) {
1450 int linearization_level,
Model* m,
1452 CHECK(relaxation !=
nullptr);
1455 absl::flat_hash_set<int> used_integer_variable;
1466 int num_full_encoding_relaxations = 0;
1467 int num_partial_encoding_relaxations = 0;
1469 if (mapping->IsBoolean(i))
continue;
1471 const IntegerVariable
var = mapping->Integer(i);
1482 if (encoder->VariableIsFullyEncoded(
var)) {
1484 ++num_full_encoding_relaxations;
1498 ++num_partial_encoding_relaxations;
1504 if (linearization_level >= 2) {
1514 for (
const std::vector<Literal>& at_most_one : relaxation->
at_most_ones) {
1515 if (at_most_one.empty())
continue;
1521 const bool unused ABSL_ATTRIBUTE_UNUSED =
1539 VLOG(3) <<
"num_full_encoding_relaxations: " << num_full_encoding_relaxations;
1540 VLOG(3) <<
"num_partial_encoding_relaxations: " 1541 << num_partial_encoding_relaxations;
1543 <<
" constraints in the LP relaxation.";
CutGenerator CreateNoOverlapEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
void AddAllDiffCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
void AppendLinMaxRelaxationPart1(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
bool AppendFullEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
bool add_lin_max_cuts() const
void ComputeLinearRelaxation(const CpModelProto &model_proto, int linearization_level, Model *m, LinearRelaxation *relaxation)
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
CutGenerator CreateCumulativeTimeTableCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, Model *model)
Class that owns everything related to a particular optimization model.
Literal(int signed_value)
void AddIntAbsCutGenerator(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
std::vector< IntegerValue > coeffs
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
LinearConstraint BuildMaxAffineUpConstraint(const LinearExpression &target, IntegerVariable var, const std::vector< std::pair< IntegerValue, IntegerValue >> &affines, Model *model)
void AppendCircuitRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendElementEncodingRelaxation(const CpModelProto &model_proto, Model *m, LinearRelaxation *relaxation)
#define VLOG(verboselevel)
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
IntegerValue LowerBound(IntegerVariable i) const
CutGenerator CreateMaxAffineCutGenerator(LinearExpression target, IntegerVariable var, std::vector< std::pair< IntegerValue, IntegerValue >> affines, const std::string cut_name, Model *model)
CutGenerator CreateCumulativePrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, IntegerVariable capacity, const std::vector< IntegerVariable > &demands, Model *model)
void AppendIntervalRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AddLinearExpression(const LinearExpression &expr)
void AppendIntMaxRelaxation(const ConstraintProto &ct, int linearization_level, Model *model, LinearRelaxation *relaxation)
LinearExpression PositiveVarExpr(const LinearExpression &expr)
void AddTerm(IntegerVariable var, IntegerValue coeff)
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
std::vector< Literal > CreateAlternativeLiteralsWithView(int num_literals, Model *model, LinearRelaxation *relaxation)
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
void AppendAtMostOneRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
CutGenerator CreateSquareCutGenerator(IntegerVariable y, IntegerVariable x, int linearization_level, Model *model)
#define DCHECK_GT(val1, val2)
int variables_size() const
CutGenerator CreateCVRPCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, const std::vector< int64_t > &demands, int64_t capacity, Model *model)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::vector< IntegerValue > coeffs
void AddCumulativeRelaxation(const std::vector< IntervalVariable > &x_intervals, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
LinearExpression CanonicalizeExpr(const LinearExpression &expr)
std::vector< IntegerVariable > vars
std::vector< IntegerVariable > vars
IntegerVariable PositiveVariable(IntegerVariable i)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
CutGenerator CreateLinMaxCutGenerator(const IntegerVariable target, const std::vector< LinearExpression > &exprs, const std::vector< IntegerVariable > &z_vars, Model *model)
int ReindexArcs(IntContainer *tails, IntContainer *heads)
void AddCumulativeCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
std::vector< std::vector< Literal > > at_most_ones
void AddRoutesCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
std::function< IntervalVariable(Model *)> NewInterval(int64_t min_start, int64_t max_end, int64_t size)
T Get(std::function< T(const Model &)> f) const
Similar to Add() but this is const.
void AddNoOverlap2dCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
CutGenerator CreateStronglyConnectedGraphCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, Model *model)
void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
void AppendLinearConstraintRelaxation(const ConstraintProto &ct, bool linearize_enforced_constraints, Model *model, LinearRelaxation *relaxation)
const ::operations_research::sat::ConstraintProto & constraints(int index) const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
void AppendBoolAndRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64_t min_start, int64_t max_end, int64_t size, Literal is_present)
bool VariableIsPositive(IntegerVariable i)
#define DCHECK_GE(val1, val2)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
void TryToLinearizeConstraint(const CpModelProto &model_proto, const ConstraintProto &ct, int linearization_level, Model *model, LinearRelaxation *relaxation)
void AddNoOverlapCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
#define CHECK_EQ(val1, val2)
void AppendExactlyOneRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
CutGenerator CreateAllDifferentCutGenerator(const std::vector< IntegerVariable > &vars, Model *model)
void AppendMaxAffineRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendBoolOrRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
CpModelProto const * model_proto
void TryToAddCutGenerators(const ConstraintProto &ct, int linearization_level, Model *m, LinearRelaxation *relaxation)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
#define DCHECK(condition)
void AppendNoOverlapRelaxation(const CpModelProto &model_proto, const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AddCircuitCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
void AppendPartialEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
bool HasEnforcementLiteral(const ConstraintProto &ct)
std::vector< CutGenerator > cut_generators
IntegerValue UpperBound(IntegerVariable i) const
int CurrentDecisionLevel() const
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
Collection of objects used to extend the Constraint Solver library.
CutGenerator CreateNoOverlap2dCompletionTimeCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
const IntegerVariable kNoIntegerVariable(-1)
void AppendRoutesRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
CutGenerator CreateCumulativeCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, const std::vector< LinearExpression > &energies, Model *model)
void AddIntProdCutGenerator(const ConstraintProto &ct, int linearization_level, Model *m, LinearRelaxation *relaxation)
bool RefIsPositive(int ref)
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
std::function< void(Model *)> SpanOfIntervals(IntervalVariable span, const std::vector< IntervalVariable > &intervals)
const LiteralIndex kNoLiteralIndex(-1)
void AppendLinMaxRelaxationPart2(IntegerVariable target, const std::vector< Literal > &alternative_literals, const std::vector< LinearExpression > &exprs, Model *model, LinearRelaxation *relaxation)
std::vector< IntegerVariable > Integers(const List &list) const
CutGenerator CreatePositiveMultiplicationCutGenerator(IntegerVariable z, IntegerVariable x, IntegerVariable y, int linearization_level, Model *model)
std::vector< LinearConstraint > linear_constraints
std::function< void(Model *)> ExactlyOneConstraint(const std::vector< Literal > &literals)
CutGenerator CreateNoOverlapCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
void AddLinMaxCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
IntegerVariable Integer(int ref) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
#define CHECK_NE(val1, val2)
bool IsFixed(IntegerVariable i) const
void AddQuadraticLowerBound(AffineExpression left, AffineExpression right, IntegerTrail *integer_trail)
CutGenerator CreateCumulativeEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, const std::vector< LinearExpression > &energies, Model *model)
void AddMaxAffineCutGenerator(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendCumulativeRelaxation(const CpModelProto &model_proto, const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)