21#include "absl/container/flat_hash_set.h"
45 if (encoder ==
nullptr)
return false;
46 if (!encoder->VariableIsFullyEncoded(
var))
return false;
57 std::vector<Literal> at_most_one;
59 for (
const auto value_literal : encoding) {
60 const Literal lit = value_literal.literal;
61 const IntegerValue
delta = value_literal.value - var_min;
63 at_most_one.push_back(lit);
64 if (!at_least_one.
AddLiteralTerm(lit, IntegerValue(1)))
return false;
65 if (
delta != IntegerValue(0)) {
78std::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 for (
const int64_t v : (*domains)[
NegationOf(
var)].Values()) {
99 if (!encoded_values.contains(IntegerValue(-v))) {
100 max = IntegerValue(-v);
108bool LinMaxContainsOnlyOneVarInExpressions(
const ConstraintProto&
ct) {
109 CHECK_EQ(
ct.constraint_case(), ConstraintProto::ConstraintCase::kLinMax);
110 int current_var = -1;
111 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
112 if (expr.vars().empty())
continue;
113 if (expr.vars().size() > 1)
return false;
115 if (current_var == -1) {
117 }
else if (
var != current_var) {
129void CollectAffineExpressionWithSingleVariable(
130 const ConstraintProto&
ct, CpModelMapping* mapping, IntegerVariable*
var,
131 std::vector<std::pair<IntegerValue, IntegerValue>>* affines) {
132 DCHECK(LinMaxContainsOnlyOneVarInExpressions(
ct));
133 CHECK_EQ(
ct.constraint_case(), ConstraintProto::ConstraintCase::kLinMax);
136 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
137 if (expr.vars().empty()) {
138 affines->push_back({IntegerValue(0), IntegerValue(expr.offset())});
141 const IntegerVariable affine_var = mapping->Integer(expr.vars(0));
148 {IntegerValue(expr.coeffs(0)), IntegerValue(expr.offset())});
152 {IntegerValue(-expr.coeffs(0)), IntegerValue(expr.offset())});
163 int* num_tight,
int* num_loose) {
166 if (encoder ==
nullptr || integer_trail ==
nullptr)
return;
168 std::vector<Literal> at_most_one_ct;
169 absl::flat_hash_set<IntegerValue> encoded_values;
170 std::vector<ValueLiteralPair> encoding;
172 const std::vector<ValueLiteralPair>& initial_encoding =
173 encoder->PartialDomainEncoding(
var);
174 if (initial_encoding.empty())
return;
175 for (
const auto value_literal : initial_encoding) {
184 encoding.push_back(value_literal);
185 at_most_one_ct.push_back(
literal);
186 encoded_values.insert(value_literal.value);
189 if (encoded_values.empty())
return;
196 const auto [min_not_encoded, max_not_encoded] =
197 GetMinAndMaxNotEncoded(
var, encoded_values,
model);
202 const IntegerValue rhs = encoding[0].value;
207 for (
const auto value_literal : encoding) {
208 const Literal lit = value_literal.literal;
211 const IntegerValue
delta = value_literal.value - rhs;
212 if (
delta != IntegerValue(0)) {
227 if (min_not_encoded == max_not_encoded) {
228 const IntegerValue rhs = min_not_encoded;
231 for (
const auto value_literal : encoding) {
233 rhs - value_literal.value));
242 const IntegerValue d_min = min_not_encoded;
245 for (
const auto value_literal : encoding) {
247 d_min - value_literal.value));
251 const IntegerValue d_max = max_not_encoded;
254 for (
const auto value_literal : encoding) {
256 d_max - value_literal.value));
271 if (integer_trail ==
nullptr || encoder ==
nullptr)
return;
273 const std::map<IntegerValue, Literal>& greater_than_encoding =
274 encoder->PartialGreaterThanEncoding(
var);
275 if (greater_than_encoding.empty())
return;
280 IntegerValue prev_used_bound = integer_trail->
LowerBound(
var);
285 for (
const auto entry : greater_than_encoding) {
286 if (entry.first <= prev_used_bound)
continue;
288 const LiteralIndex literal_index = entry.second.Index();
289 const IntegerValue diff = prev_used_bound - entry.first;
298 prev_used_bound = entry.first;
299 prev_literal_index = literal_index;
307 IntegerValue prev_used_bound = integer_trail->LowerBound(
NegationOf(
var));
311 for (
const auto entry :
313 if (entry.first <= prev_used_bound)
continue;
314 const IntegerValue diff = prev_used_bound - entry.first;
318 prev_used_bound = entry.first;
326void AppendEnforcedUpperBound(
const Literal enforcing_lit,
327 const IntegerVariable target,
328 const IntegerVariable bounding_var, Model*
model,
329 LinearRelaxation* relaxation) {
330 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
331 const IntegerValue max_target_value = integer_trail->UpperBound(target);
332 const IntegerValue min_var_value = integer_trail->LowerBound(bounding_var);
333 const IntegerValue max_term_value = max_target_value - min_var_value;
335 lc.AddTerm(target, IntegerValue(1));
336 lc.AddTerm(bounding_var, IntegerValue(-1));
337 CHECK(lc.AddLiteralTerm(enforcing_lit, max_term_value));
338 relaxation->linear_constraints.push_back(lc.Build());
343void AppendEnforcedLinearExpression(
344 const std::vector<Literal>& enforcing_literals,
345 const LinearExpression& expr,
const IntegerValue rhs_domain_min,
346 const IntegerValue rhs_domain_max,
const Model&
model,
347 LinearRelaxation* relaxation) {
348 CHECK_EQ(expr.offset, IntegerValue(0));
350 const IntegerTrail* integer_trail =
model.Get<IntegerTrail>();
351 const IntegerValue min_expr_value =
354 if (rhs_domain_min > min_expr_value) {
359 for (
const Literal&
literal : enforcing_literals) {
361 rhs_domain_min - min_expr_value));
363 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
364 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
366 relaxation->linear_constraints.push_back(lc.Build());
368 const IntegerValue max_expr_value =
370 if (rhs_domain_max < max_expr_value) {
375 for (
const Literal&
literal : enforcing_literals) {
377 rhs_domain_max - max_expr_value));
379 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
380 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
382 relaxation->linear_constraints.push_back(lc.Build());
386bool AllLiteralsHaveViews(
const IntegerEncoder& encoder,
387 const std::vector<Literal>& literals) {
388 for (
const Literal lit : literals) {
389 if (!encoder.LiteralOrNegationHasView(lit))
return false;
400 for (
const int enforcement_ref :
ct.enforcement_literal()) {
404 for (
const int ref :
ct.bool_or().literals()) {
405 CHECK(lc.AddLiteralTerm(mapping->Literal(ref), IntegerValue(1)));
418 if (
ct.enforcement_literal().size() == 1) {
420 for (
const int ref :
ct.bool_and().literals()) {
422 {enforcement, mapping->
Literal(ref).Negated()});
429 int num_literals =
ct.bool_and().literals_size();
432 for (
const int ref :
ct.bool_and().literals()) {
435 for (
const int enforcement_ref :
ct.enforcement_literal()) {
437 IntegerValue(num_literals)));
448 mapping->Literals(
ct.at_most_one().literals()));
457 const std::vector<Literal> literals =
458 mapping->Literals(
ct.exactly_one().literals());
459 if (AllLiteralsHaveViews(*encoder, literals)) {
461 for (
const Literal lit : literals) {
476 if (num_literals == 1) {
481 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
485 if (num_literals == 2) {
488 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
494 encoder->AssociateToIntegerEqualValue(lit.
Negated(), var2, IntegerValue(1));
499 std::vector<Literal> literals;
501 for (
int i = 0; i < num_literals; ++i) {
504 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
505 literals.push_back(lit);
517 const int num_arcs =
ct.circuit().literals_size();
518 CHECK_EQ(num_arcs,
ct.circuit().tails_size());
519 CHECK_EQ(num_arcs,
ct.circuit().heads_size());
523 std::map<int, std::vector<Literal>> incoming_arc_constraints;
524 std::map<int, std::vector<Literal>> outgoing_arc_constraints;
525 for (
int i = 0; i < num_arcs; i++) {
527 const int tail =
ct.circuit().tails(i);
528 const int head =
ct.circuit().heads(i);
532 outgoing_arc_constraints[
tail].push_back(arc);
533 incoming_arc_constraints[
head].push_back(arc);
535 for (
const auto* node_map :
536 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
537 for (
const auto& entry : *node_map) {
538 const std::vector<Literal>& exactly_one = entry.second;
539 if (exactly_one.size() > 1) {
542 for (
const Literal l : exactly_one) {
558 const int num_arcs =
ct.routes().literals_size();
566 std::map<int, std::vector<Literal>> incoming_arc_constraints;
567 std::map<int, std::vector<Literal>> outgoing_arc_constraints;
568 for (
int i = 0; i < num_arcs; i++) {
570 const int tail =
ct.routes().tails(i);
571 const int head =
ct.routes().heads(i);
575 outgoing_arc_constraints[
tail].push_back(arc);
576 incoming_arc_constraints[
head].push_back(arc);
578 for (
const auto* node_map :
579 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
580 for (
const auto& entry : *node_map) {
581 if (entry.first == 0)
continue;
582 const std::vector<Literal>& exactly_one = entry.second;
583 if (exactly_one.size() > 1) {
586 for (
const Literal l : exactly_one) {
598 for (
const Literal& incoming_arc : incoming_arc_constraints[0]) {
601 for (
const Literal& outgoing_arc : outgoing_arc_constraints[0]) {
608 const std::vector<AffineExpression>& demands,
609 const std::vector<LinearExpression>& energies,
610 IntegerValue capacity_upper_bound,
Model*
model,
615 model->TakeOwnership(helper);
616 const int num_intervals = helper->NumTasks();
623 int num_variable_sizes = 0;
624 int num_optionals = 0;
627 min_of_starts =
std::min(min_of_starts, helper->StartMin(
index));
630 if (helper->IsOptional(
index)) {
634 if (!helper->SizeIsFixed(
index) ||
635 (!demands.empty() && !integer_trail->
IsFixed(demands[
index]))) {
636 num_variable_sizes++;
640 VLOG(2) <<
"Span [" << min_of_starts <<
".." << max_of_ends <<
"] with "
641 << num_optionals <<
" optional intervals, and " << num_variable_sizes
642 <<
" variable size intervals out of " << num_intervals
645 if (num_variable_sizes + num_optionals == 0)
return;
647 const IntegerVariable span_start =
650 IntegerValue(0), max_of_ends - min_of_starts);
651 const IntegerVariable span_end =
654 IntervalVariable span_var;
655 if (num_optionals < num_intervals) {
659 span_var =
model->Add(
666 lc.
AddTerm(span_size, -capacity_upper_bound);
667 for (
int i = 0; i < num_intervals; ++i) {
668 const IntegerValue demand_lower_bound =
669 demands.empty() ? IntegerValue(1)
671 const bool demand_is_fixed =
672 demands.empty() || integer_trail->
IsFixed(demands[i]);
673 if (!helper->IsOptional(i)) {
674 if (demand_is_fixed) {
675 lc.
AddTerm(helper->Sizes()[i], demand_lower_bound);
676 }
else if (!helper->SizeIsFixed(i) &&
677 (!energies[i].vars.empty() || energies[i].offset != -1)) {
687 helper->SizeMin(i) * demand_lower_bound)) {
702 std::vector<IntervalVariable> intervals =
704 const IntegerValue capacity_upper_bound =
706 mapping->Affine(
ct.cumulative().capacity()));
712 std::vector<LinearExpression> energies;
713 std::vector<AffineExpression> demands;
714 std::vector<AffineExpression> sizes;
715 for (
int i = 0; i <
ct.cumulative().demands_size(); ++i) {
716 demands.push_back(mapping->Affine(
ct.cumulative().demands(i)));
717 sizes.push_back(intervals_repository->
Size(intervals[i]));
731 std::vector<IntervalVariable> intervals =
734 IntegerValue(1),
model,
745 std::vector<IntervalVariable> x_intervals =
746 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
747 std::vector<IntervalVariable> y_intervals =
748 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
757 std::vector<AffineExpression> x_sizes;
758 std::vector<AffineExpression> y_sizes;
759 for (
int i = 0; i <
ct.no_overlap_2d().x_intervals_size(); ++i) {
760 x_sizes.push_back(intervals_repository->Size(x_intervals[i]));
761 y_sizes.push_back(intervals_repository->Size(y_intervals[i]));
762 x_min =
std::min(x_min, integer_trail->LevelZeroLowerBound(
763 intervals_repository->Start(x_intervals[i])));
764 x_max =
std::max(x_max, integer_trail->LevelZeroUpperBound(
765 intervals_repository->End(x_intervals[i])));
766 y_min =
std::min(y_min, integer_trail->LevelZeroLowerBound(
767 intervals_repository->Start(y_intervals[i])));
768 y_max =
std::max(y_max, integer_trail->LevelZeroUpperBound(
769 intervals_repository->End(y_intervals[i])));
772 const IntegerValue max_area =
774 CapSub(y_max.value(), y_min.value())));
778 for (
int i = 0; i <
ct.no_overlap_2d().x_intervals_size(); ++i) {
779 if (intervals_repository->IsPresent(x_intervals[i]) &&
780 intervals_repository->IsPresent(y_intervals[i])) {
788 }
else if (intervals_repository->IsPresent(x_intervals[i]) ||
789 intervals_repository->IsPresent(y_intervals[i]) ||
790 (intervals_repository->PresenceLiteral(x_intervals[i]) ==
791 intervals_repository->PresenceLiteral(y_intervals[i]))) {
793 const Literal presence_literal =
794 intervals_repository->IsPresent(x_intervals[i])
795 ? intervals_repository->PresenceLiteral(y_intervals[i])
796 : intervals_repository->PresenceLiteral(x_intervals[i]);
797 const IntegerValue area_min =
799 integer_trail->LevelZeroLowerBound(y_sizes[i]);
816 NegationOf(mapping->GetExprFromProto(
ct.lin_max().target()));
817 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
819 mapping->GetExprFromProto(
ct.lin_max().exprs(i));
834 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
836 CollectAffineExpressionWithSingleVariable(
ct, mapping, &
var, &affines);
852 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
854 CollectAffineExpressionWithSingleVariable(
ct, mapping, &
var, &affines);
861 if (
ct.lin_max().target().vars().empty())
return;
866 target_expr,
var, affines,
"AffineMax",
model));
874 IntegerVariable target,
const std::vector<Literal>& alternative_literals,
875 const std::vector<LinearExpression>& exprs,
Model*
model,
877 const int num_exprs = exprs.size();
881 for (
int i = 0; i < num_exprs; ++i) {
884 local_expr.
vars.push_back(target);
885 local_expr.
coeffs = exprs[i].coeffs;
886 local_expr.
coeffs.push_back(IntegerValue(1));
899 std::vector<IntegerVariable> x_vars;
900 for (
int i = 0; i < num_exprs; ++i) {
901 x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end());
906 DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable
var) {
907 return VariableIsPositive(var);
910 std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
911 num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
914 for (
int i = 0; i < num_exprs; ++i) {
915 for (
int j = 0; j < num_exprs; ++j) {
916 if (i == j)
continue;
917 for (
const IntegerVariable x_var : x_vars) {
920 const IntegerValue diff =
922 sum_of_max_corner_diff[i][j] +=
std::max(diff * lb, diff * ub);
926 for (
int i = 0; i < num_exprs; ++i) {
928 lc.
AddTerm(target, IntegerValue(1));
929 for (
int j = 0; j < exprs[i].vars.size(); ++j) {
930 lc.
AddTerm(exprs[i].vars[j], -exprs[i].coeffs[j]);
932 for (
int j = 0; j < num_exprs; ++j) {
934 -exprs[j].offset - sum_of_max_corner_diff[i][j]));
941 bool linearize_enforced_constraints,
953 const IntegerValue rhs_domain_min = IntegerValue(
ct.linear().domain(0));
954 const IntegerValue rhs_domain_max =
955 IntegerValue(
ct.linear().domain(
ct.linear().domain_size() - 1));
962 for (
int i = 0; i <
ct.linear().vars_size(); i++) {
963 const int ref =
ct.linear().vars(i);
964 const int64_t
coeff =
ct.linear().coeffs(i);
972 if (!linearize_enforced_constraints)
return;
976 if (!mapping->IsHalfEncodingConstraint(&
ct) &&
ct.linear().vars_size() <= 1) {
980 std::vector<Literal> enforcing_literals;
981 enforcing_literals.reserve(
ct.enforcement_literal_size());
982 for (
const int enforcement_ref :
ct.enforcement_literal()) {
983 enforcing_literals.push_back(mapping->Literal(enforcement_ref));
986 expr.
vars.reserve(
ct.linear().vars_size());
987 expr.
coeffs.reserve(
ct.linear().vars_size());
988 for (
int i = 0; i <
ct.linear().vars_size(); i++) {
989 int ref =
ct.linear().vars(i);
990 IntegerValue
coeff(
ct.linear().coeffs(i));
995 const IntegerVariable int_var = mapping->Integer(ref);
996 expr.
vars.push_back(int_var);
999 AppendEnforcedLinearExpression(enforcing_literals, expr, rhs_domain_min,
1000 rhs_domain_max, *
model, relaxation);
1021 switch (
ct.constraint_case()) {
1022 case ConstraintProto::ConstraintCase::kBoolOr: {
1023 if (linearization_level > 1) {
1028 case ConstraintProto::ConstraintCase::kBoolAnd: {
1029 if (linearization_level > 1) {
1034 case ConstraintProto::ConstraintCase::kAtMostOne: {
1038 case ConstraintProto::ConstraintCase::kExactlyOne: {
1042 case ConstraintProto::ConstraintCase::kIntProd: {
1047 case ConstraintProto::ConstraintCase::kLinMax: {
1049 const bool is_affine_max = LinMaxContainsOnlyOneVarInExpressions(
ct);
1050 if (is_affine_max) {
1055 if (linearization_level > 1) {
1056 if (is_affine_max) {
1064 case ConstraintProto::ConstraintCase::kAllDiff: {
1065 if (linearization_level > 1) {
1070 case ConstraintProto::ConstraintCase::kLinear: {
1072 ct, linearization_level > 1,
model,
1076 case ConstraintProto::ConstraintCase::kCircuit: {
1078 if (linearization_level > 1) {
1083 case ConstraintProto::ConstraintCase::kRoutes: {
1085 if (linearization_level > 1) {
1090 case ConstraintProto::ConstraintCase::kNoOverlap: {
1091 if (linearization_level > 1) {
1097 case ConstraintProto::ConstraintCase::kCumulative: {
1098 if (linearization_level > 1) {
1104 case ConstraintProto::ConstraintCase::kNoOverlap2D: {
1107 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().exprs_size() != 2)
return;
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_exprs =
ct.all_diff().exprs_size();
1217 if (num_exprs <= m->GetOrCreate<SatParameters>()->max_all_diff_cut_size()) {
1218 std::vector<AffineExpression> exprs(num_exprs);
1220 exprs.push_back(mapping->Affine(expr));
1253 const std::vector<IntervalVariable> intervals =
1261 std::vector<LinearExpression> energies;
1262 std::vector<AffineExpression> demands;
1263 std::vector<AffineExpression> sizes;
1264 for (
int i = 0; i < intervals.size(); ++i) {
1265 demands.push_back(mapping->Affine(
ct.cumulative().demands(i)));
1266 sizes.push_back(intervals_repository->
Size(intervals[i]));
1280 bool has_variable_part =
false;
1282 for (
int i = 0; i < intervals.size(); ++i) {
1284 has_variable_part =
true;
1288 if (!integer_trail->
IsFixed(demands[i])) {
1289 has_variable_part =
true;
1293 if (has_variable_part) {
1295 intervals,
capacity, demands, energies, m));
1304 std::vector<IntervalVariable> intervals =
1314 bool has_variable_part =
false;
1315 for (
int i = 0; i < intervals.size(); ++i) {
1317 has_variable_part =
true;
1321 if (has_variable_part) {
1332 std::vector<IntervalVariable> x_intervals =
1333 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
1334 std::vector<IntervalVariable> y_intervals =
1335 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
1342 bool has_variable_part =
false;
1343 for (
int i = 0; i < x_intervals.size(); ++i) {
1345 if (intervals_repository->
IsAbsent(x_intervals[i]) ||
1346 intervals_repository->
IsAbsent(y_intervals[i])) {
1351 if (!intervals_repository->
IsPresent(x_intervals[i]) ||
1352 !intervals_repository->
IsPresent(y_intervals[i])) {
1353 has_variable_part =
true;
1358 if (intervals_repository->
MinSize(x_intervals[i]) !=
1359 intervals_repository->
MaxSize(x_intervals[i]) ||
1360 intervals_repository->
MinSize(y_intervals[i]) !=
1361 intervals_repository->
MaxSize(y_intervals[i])) {
1362 has_variable_part =
true;
1366 if (has_variable_part) {
1379 if (
ct.lin_max().target().vars_size() != 1)
return;
1380 if (
ct.lin_max().target().coeffs(0) != 1)
return;
1381 if (
ct.lin_max().target().offset() != 0)
return;
1383 const IntegerVariable target =
1384 mapping->
Integer(
ct.lin_max().target().vars(0));
1385 std::vector<LinearExpression> exprs;
1386 exprs.reserve(
ct.lin_max().exprs_size());
1387 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
1394 const std::vector<Literal> alternative_literals =
1404 std::vector<IntegerVariable> z_vars;
1406 for (
const Literal lit : alternative_literals) {
1407 z_vars.push_back(encoder->GetLiteralView(lit));
1426 int num_exactly_one_elements = 0;
1428 for (
const IntegerVariable
var :
1429 implied_bounds->GetElementEncodedVariables()) {
1430 for (
const auto& [
index, literal_value_list] :
1431 implied_bounds->GetElementEncodings(
var)) {
1437 absl::flat_hash_set<IntegerValue> values;
1438 for (
const auto& literal_value : literal_value_list) {
1439 min_value =
std::min(min_value, literal_value.value);
1440 values.insert(literal_value.value);
1442 if (values.size() == literal_value_list.size())
continue;
1446 linear_encoding.
AddTerm(
var, IntegerValue(-1));
1447 for (
const auto& [
value,
literal] : literal_value_list) {
1448 const IntegerValue delta_min =
value - min_value;
1449 if (delta_min != 0) {
1456 ++num_exactly_one_elements;
1461 if (num_exactly_one_elements != 0) {
1464 "[ElementLinearRelaxation]"
1465 " #from_exactly_one:",
1466 num_exactly_one_elements);
1482 int num_loose_equality_encoding_relaxations = 0;
1483 int num_tight_equality_encoding_relaxations = 0;
1484 int num_inequality_encoding_relaxations = 0;
1487 if (mapping->IsBoolean(i))
continue;
1489 const IntegerVariable
var = mapping->Integer(i);
1494 var, *m, &relaxation, &num_tight_equality_encoding_relaxations,
1495 &num_loose_equality_encoding_relaxations);
1510 ++num_inequality_encoding_relaxations;
1528 if (num_tight_equality_encoding_relaxations != 0 ||
1529 num_loose_equality_encoding_relaxations != 0 ||
1530 num_inequality_encoding_relaxations != 0) {
1532 "[EncodingLinearRelaxation]"
1533 " #tight_equality:",
1534 num_tight_equality_encoding_relaxations,
1535 " #loose_equality:", num_loose_equality_encoding_relaxations,
1536 " #inequality:", num_inequality_encoding_relaxations);
1541 "[LinearRelaxationBeforeCliqueExpansion]"
1551 for (
const std::vector<Literal>& at_most_one : relaxation.
at_most_ones) {
1552 if (at_most_one.empty())
continue;
1558 const bool unused ABSL_ATTRIBUTE_UNUSED =
1584 if (!mapping->IsBoolean(i))
continue;
1588 const bool unused ABSL_ATTRIBUTE_UNUSED =
1594 if (!expr.
vars.empty()) {
1603 "[FinalLinearRelaxation]"
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define DCHECK_GE(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
IntegerVariable Integer(int ref) const
std::vector< sat::Literal > Literals(const ProtoIndices &indices) const
int variables_size() const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
bool IsFixed(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
IntegerValue LowerBound(IntegerVariable i) const
IntegerValue MaxSize(IntervalVariable i) const
IntegerValue MinSize(IntervalVariable i) const
bool IsPresent(IntervalVariable i) const
AffineExpression Size(IntervalVariable i) const
bool IsAbsent(IntervalVariable i) const
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
void AddLinearExpression(const LinearExpression &expr)
void AddQuadraticLowerBound(AffineExpression left, AffineExpression right, IntegerTrail *integer_trail)
LinearExpression BuildExpression()
void AddTerm(IntegerVariable var, IntegerValue coeff)
Literal(int signed_value)
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 * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
int32_t linearization_level() const
double merge_at_most_one_work_limit() const
bool add_lin_max_cuts() const
bool add_clique_cuts() const
int CurrentDecisionLevel() const
CpModelProto const * model_proto
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void AddCumulativeCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
CutGenerator CreateCumulativeEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, const AffineExpression &capacity, const std::vector< AffineExpression > &demands, const std::vector< LinearExpression > &energies, Model *model)
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
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)
CutGenerator CreateNoOverlap2dEnergyCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void AppendLinMaxRelaxationPart1(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendBoolOrRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
CutGenerator CreateNoOverlapCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
void TryToLinearizeConstraint(const CpModelProto &model_proto, const ConstraintProto &ct, int linearization_level, Model *model, LinearRelaxation *relaxation)
bool AppendFullEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
bool RefIsPositive(int ref)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
CutGenerator CreateAllDifferentCutGenerator(const std::vector< AffineExpression > &exprs, Model *model)
void AppendNoOverlapRelaxation(const CpModelProto &model_proto, const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
const LiteralIndex kNoLiteralIndex(-1)
void AddMaxAffineCutGenerator(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendAtMostOneRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendCumulativeRelaxation(const CpModelProto &model_proto, const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
void AddNoOverlapCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
std::function< BooleanVariable(Model *)> NewBooleanVariable()
bool HasEnforcementLiteral(const ConstraintProto &ct)
void LinearizeInnerProduct(const std::vector< AffineExpression > &left, const std::vector< AffineExpression > &right, Model *model, std::vector< LinearExpression > *energies)
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
LinearExpression PositiveVarExpr(const LinearExpression &expr)
std::function< IntervalVariable(Model *)> NewInterval(int64_t min_start, int64_t max_end, int64_t size)
void AppendBoolAndRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
const IntegerVariable kNoIntegerVariable(-1)
void AppendLinearConstraintRelaxation(const ConstraintProto &ct, bool linearize_enforced_constraints, Model *model, LinearRelaxation *relaxation)
LinearExpression CanonicalizeExpr(const LinearExpression &expr)
void AddNoOverlap2dCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
CutGenerator CreateCumulativeTimeTableCutGenerator(const std::vector< IntervalVariable > &intervals, const AffineExpression &capacity, const std::vector< AffineExpression > &demands, Model *model)
void AddIntProdCutGenerator(const ConstraintProto &ct, int linearization_level, Model *m, LinearRelaxation *relaxation)
void AddCircuitCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
CutGenerator CreateNoOverlap2dCompletionTimeCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64_t min_start, int64_t max_end, int64_t size, Literal is_present)
IntegerVariable PositiveVariable(IntegerVariable i)
CutGenerator CreateLinMaxCutGenerator(const IntegerVariable target, const std::vector< LinearExpression > &exprs, const std::vector< IntegerVariable > &z_vars, Model *model)
CutGenerator CreatePositiveMultiplicationCutGenerator(AffineExpression z, AffineExpression x, AffineExpression y, int linearization_level, Model *model)
void AppendMaxAffineRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
LinearConstraint BuildMaxAffineUpConstraint(const LinearExpression &target, IntegerVariable var, const std::vector< std::pair< IntegerValue, IntegerValue > > &affines, Model *model)
void AppendExactlyOneRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
bool DetectLinearEncodingOfProducts(const AffineExpression &left, const AffineExpression &right, Model *model, LinearConstraintBuilder *builder)
int ReindexArcs(IntContainer *tails, IntContainer *heads)
CutGenerator CreateSquareCutGenerator(AffineExpression y, AffineExpression x, int linearization_level, Model *model)
std::vector< Literal > CreateAlternativeLiteralsWithView(int num_literals, Model *model, LinearRelaxation *relaxation)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
void AppendElementEncodingRelaxation(const CpModelProto &model_proto, Model *m, LinearRelaxation *relaxation)
void AppendCircuitRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
CutGenerator CreateCumulativeCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, const AffineExpression &capacity, const std::vector< AffineExpression > &demands, const std::vector< LinearExpression > &energies, Model *model)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
void AddAllDiffCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
CutGenerator CreateNoOverlapEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
CutGenerator CreateMaxAffineCutGenerator(LinearExpression target, IntegerVariable var, std::vector< std::pair< IntegerValue, IntegerValue > > affines, const std::string cut_name, Model *model)
std::function< void(Model *)> SpanOfIntervals(IntervalVariable span, const std::vector< IntervalVariable > &intervals)
bool IntervalIsVariable(const IntervalVariable interval, IntervalsRepository *intervals_repository)
void AddLinMaxCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
void AppendRoutesRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
CutGenerator CreateCumulativePrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, const AffineExpression &capacity, const std::vector< AffineExpression > &demands, Model *model)
std::function< void(Model *)> ExactlyOneConstraint(const std::vector< Literal > &literals)
void AppendNoOverlap2dRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
void AppendRelaxationForEqualityEncoding(IntegerVariable var, const Model &model, LinearRelaxation *relaxation, int *num_tight, int *num_loose)
void AddCumulativeRelaxation(const std::vector< IntervalVariable > &x_intervals, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
CutGenerator CreateCliqueCutGenerator(const std::vector< IntegerVariable > &base_variables, Model *model)
bool VariableIsPositive(IntegerVariable i)
void AddRoutesCutGenerator(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)
LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, Model *m)
void AppendLinMaxRelaxationPart2(IntegerVariable target, const std::vector< Literal > &alternative_literals, const std::vector< LinearExpression > &exprs, Model *model, LinearRelaxation *relaxation)
void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
Collection of objects used to extend the Constraint Solver library.
int64_t CapSub(int64_t x, int64_t y)
int64_t CapProd(int64_t x, int64_t y)
AffineExpression Negated() const
std::vector< IntegerValue > coeffs
std::vector< IntegerVariable > vars
std::vector< std::vector< Literal > > at_most_ones
std::vector< LinearConstraint > linear_constraints
std::vector< CutGenerator > cut_generators
#define SOLVER_LOG(logger,...)