22#include "absl/base/attributes.h"
23#include "absl/container/btree_map.h"
24#include "absl/container/flat_hash_set.h"
30#include "ortools/sat/cp_model.pb.h"
42#include "ortools/sat/sat_parameters.pb.h"
56 if (encoder ==
nullptr)
return false;
57 if (!encoder->VariableIsFullyEncoded(
var))
return false;
68 std::vector<Literal> at_most_one;
70 for (
const auto value_literal : encoding) {
71 const Literal lit = value_literal.literal;
72 const IntegerValue
delta = value_literal.value - var_min;
74 at_most_one.push_back(lit);
75 if (!at_least_one.
AddLiteralTerm(lit, IntegerValue(1)))
return false;
76 if (
delta != IntegerValue(0)) {
89std::pair<IntegerValue, IntegerValue> GetMinAndMaxNotEncoded(
91 const absl::flat_hash_set<IntegerValue>& encoded_values,
93 const auto* domains =
model.Get<IntegerDomains>();
94 if (domains ==
nullptr ||
var >= domains->size()) {
101 for (
const int64_t v : (*domains)[
var].Values()) {
102 if (!encoded_values.contains(IntegerValue(v))) {
103 min = IntegerValue(v);
109 for (
const int64_t v : (*domains)[
NegationOf(
var)].Values()) {
110 if (!encoded_values.contains(IntegerValue(-v))) {
111 max = IntegerValue(-v);
119bool LinMaxContainsOnlyOneVarInExpressions(
const ConstraintProto&
ct) {
120 CHECK_EQ(
ct.constraint_case(), ConstraintProto::ConstraintCase::kLinMax);
121 int current_var = -1;
122 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
123 if (expr.vars().empty())
continue;
124 if (expr.vars().size() > 1)
return false;
126 if (current_var == -1) {
128 }
else if (
var != current_var) {
140void CollectAffineExpressionWithSingleVariable(
141 const ConstraintProto&
ct, CpModelMapping* mapping, IntegerVariable*
var,
142 std::vector<std::pair<IntegerValue, IntegerValue>>* affines) {
143 DCHECK(LinMaxContainsOnlyOneVarInExpressions(
ct));
144 CHECK_EQ(
ct.constraint_case(), ConstraintProto::ConstraintCase::kLinMax);
147 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
148 if (expr.vars().empty()) {
149 affines->push_back({IntegerValue(0), IntegerValue(expr.offset())});
152 const IntegerVariable affine_var = mapping->Integer(expr.vars(0));
159 {IntegerValue(expr.coeffs(0)), IntegerValue(expr.offset())});
163 {IntegerValue(-expr.coeffs(0)), IntegerValue(expr.offset())});
174 int* num_tight,
int* num_loose) {
177 if (encoder ==
nullptr || integer_trail ==
nullptr)
return;
179 std::vector<Literal> at_most_one_ct;
180 absl::flat_hash_set<IntegerValue> encoded_values;
181 std::vector<ValueLiteralPair> encoding;
183 const std::vector<ValueLiteralPair>& initial_encoding =
184 encoder->PartialDomainEncoding(
var);
185 if (initial_encoding.empty())
return;
186 for (
const auto value_literal : initial_encoding) {
195 encoding.push_back(value_literal);
196 at_most_one_ct.push_back(
literal);
197 encoded_values.insert(value_literal.value);
200 if (encoded_values.empty())
return;
207 const auto [min_not_encoded, max_not_encoded] =
208 GetMinAndMaxNotEncoded(
var, encoded_values,
model);
213 const IntegerValue rhs = encoding[0].value;
218 for (
const auto value_literal : encoding) {
219 const Literal lit = value_literal.literal;
222 const IntegerValue
delta = value_literal.value - rhs;
223 if (
delta != IntegerValue(0)) {
238 if (min_not_encoded == max_not_encoded) {
239 const IntegerValue rhs = min_not_encoded;
242 for (
const auto value_literal : encoding) {
244 rhs - value_literal.value));
253 const IntegerValue d_min = min_not_encoded;
256 for (
const auto value_literal : encoding) {
258 d_min - value_literal.value));
262 const IntegerValue d_max = max_not_encoded;
265 for (
const auto value_literal : encoding) {
267 d_max - value_literal.value));
282 if (integer_trail ==
nullptr || encoder ==
nullptr)
return;
284 const absl::btree_map<IntegerValue, Literal>& greater_than_encoding =
285 encoder->PartialGreaterThanEncoding(
var);
286 if (greater_than_encoding.empty())
return;
291 IntegerValue prev_used_bound = integer_trail->
LowerBound(
var);
296 for (
const auto entry : greater_than_encoding) {
297 if (entry.first <= prev_used_bound)
continue;
299 const LiteralIndex literal_index = entry.second.Index();
300 const IntegerValue diff = prev_used_bound - entry.first;
309 prev_used_bound = entry.first;
310 prev_literal_index = literal_index;
318 IntegerValue prev_used_bound = integer_trail->LowerBound(
NegationOf(
var));
322 for (
const auto entry :
324 if (entry.first <= prev_used_bound)
continue;
325 const IntegerValue diff = prev_used_bound - entry.first;
329 prev_used_bound = entry.first;
337void AppendEnforcedUpperBound(
const Literal enforcing_lit,
338 const IntegerVariable target,
339 const IntegerVariable bounding_var, Model*
model,
340 LinearRelaxation* relaxation) {
341 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
342 const IntegerValue max_target_value = integer_trail->UpperBound(target);
343 const IntegerValue min_var_value = integer_trail->LowerBound(bounding_var);
344 const IntegerValue max_term_value = max_target_value - min_var_value;
346 lc.AddTerm(target, IntegerValue(1));
347 lc.AddTerm(bounding_var, IntegerValue(-1));
348 CHECK(lc.AddLiteralTerm(enforcing_lit, max_term_value));
349 relaxation->linear_constraints.push_back(lc.Build());
354void AppendEnforcedLinearExpression(
355 const std::vector<Literal>& enforcing_literals,
356 const LinearExpression& expr,
const IntegerValue rhs_domain_min,
357 const IntegerValue rhs_domain_max,
const Model&
model,
358 LinearRelaxation* relaxation) {
359 CHECK_EQ(expr.offset, IntegerValue(0));
361 const IntegerTrail* integer_trail =
model.Get<IntegerTrail>();
362 const IntegerValue min_expr_value =
365 if (rhs_domain_min > min_expr_value) {
370 for (
const Literal&
literal : enforcing_literals) {
372 rhs_domain_min - min_expr_value));
374 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
375 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
377 relaxation->linear_constraints.push_back(lc.Build());
379 const IntegerValue max_expr_value =
381 if (rhs_domain_max < max_expr_value) {
386 for (
const Literal&
literal : enforcing_literals) {
388 rhs_domain_max - max_expr_value));
390 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
391 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
393 relaxation->linear_constraints.push_back(lc.Build());
397bool AllLiteralsHaveViews(
const IntegerEncoder& encoder,
398 const std::vector<Literal>& literals) {
399 for (
const Literal lit : literals) {
400 if (!encoder.LiteralOrNegationHasView(lit))
return false;
411 for (
const int enforcement_ref :
ct.enforcement_literal()) {
415 for (
const int ref :
ct.bool_or().literals()) {
416 CHECK(lc.AddLiteralTerm(mapping->Literal(ref), IntegerValue(1)));
429 if (
ct.enforcement_literal().size() == 1) {
431 for (
const int ref :
ct.bool_and().literals()) {
433 {enforcement, mapping->
Literal(ref).Negated()});
440 int num_literals =
ct.bool_and().literals_size();
443 for (
const int ref :
ct.bool_and().literals()) {
446 for (
const int enforcement_ref :
ct.enforcement_literal()) {
448 IntegerValue(num_literals)));
459 mapping->Literals(
ct.at_most_one().literals()));
468 const std::vector<Literal> literals =
469 mapping->Literals(
ct.exactly_one().literals());
470 if (AllLiteralsHaveViews(*encoder, literals)) {
472 for (
const Literal lit : literals) {
487 if (num_literals == 1) {
492 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
496 if (num_literals == 2) {
499 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
505 encoder->AssociateToIntegerEqualValue(lit.
Negated(), var2, IntegerValue(1));
510 std::vector<Literal> literals;
512 for (
int i = 0; i < num_literals; ++i) {
515 encoder->GetOrCreateLiteralAssociatedToEquality(
var, IntegerValue(1));
516 literals.push_back(lit);
528 const int num_arcs =
ct.circuit().literals_size();
529 CHECK_EQ(num_arcs,
ct.circuit().tails_size());
530 CHECK_EQ(num_arcs,
ct.circuit().heads_size());
534 absl::btree_map<int, std::vector<Literal>> incoming_arc_constraints;
535 absl::btree_map<int, std::vector<Literal>> outgoing_arc_constraints;
536 for (
int i = 0; i < num_arcs; i++) {
537 const Literal arc = mapping->Literal(
ct.circuit().literals(i));
538 const int tail =
ct.circuit().tails(i);
539 const int head =
ct.circuit().heads(i);
543 outgoing_arc_constraints[
tail].push_back(
arc);
544 incoming_arc_constraints[
head].push_back(
arc);
546 for (
const auto* node_map :
547 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
548 for (
const auto& entry : *node_map) {
549 const std::vector<Literal>& exactly_one = entry.second;
550 if (exactly_one.size() > 1) {
553 for (
const Literal l : exactly_one) {
569 const int num_arcs =
ct.routes().literals_size();
577 absl::btree_map<int, std::vector<Literal>> incoming_arc_constraints;
578 absl::btree_map<int, std::vector<Literal>> outgoing_arc_constraints;
579 for (
int i = 0; i < num_arcs; i++) {
580 const Literal arc = mapping->Literal(
ct.routes().literals(i));
581 const int tail =
ct.routes().tails(i);
582 const int head =
ct.routes().heads(i);
586 outgoing_arc_constraints[
tail].push_back(
arc);
587 incoming_arc_constraints[
head].push_back(
arc);
589 for (
const auto* node_map :
590 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
591 for (
const auto& entry : *node_map) {
592 if (entry.first == 0)
continue;
593 const std::vector<Literal>& exactly_one = entry.second;
594 if (exactly_one.size() > 1) {
597 for (
const Literal l : exactly_one) {
609 for (
const Literal& incoming_arc : incoming_arc_constraints[0]) {
612 for (
const Literal& outgoing_arc : outgoing_arc_constraints[0]) {
619 const std::vector<AffineExpression>& demands,
620 const std::vector<LinearExpression>& energies,
621 IntegerValue capacity_upper_bound,
Model*
model,
626 model->TakeOwnership(helper);
627 const int num_intervals = helper->NumTasks();
634 int num_variable_sizes = 0;
635 int num_optionals = 0;
638 min_of_starts =
std::min(min_of_starts, helper->StartMin(
index));
641 if (helper->IsOptional(
index)) {
645 if (!helper->SizeIsFixed(
index) ||
646 (!demands.empty() && !integer_trail->
IsFixed(demands[
index]))) {
647 num_variable_sizes++;
651 VLOG(2) <<
"Span [" << min_of_starts <<
".." << max_of_ends <<
"] with "
652 << num_optionals <<
" optional intervals, and " << num_variable_sizes
653 <<
" variable size intervals out of " << num_intervals
656 if (num_variable_sizes + num_optionals == 0)
return;
658 const IntegerVariable span_start =
661 IntegerValue(0), max_of_ends - min_of_starts);
662 const IntegerVariable span_end =
665 IntervalVariable span_var;
666 if (num_optionals < num_intervals) {
670 span_var =
model->Add(
677 lc.
AddTerm(span_size, -capacity_upper_bound);
678 for (
int i = 0; i < num_intervals; ++i) {
679 const IntegerValue demand_lower_bound =
680 demands.empty() ? IntegerValue(1)
682 const bool demand_is_fixed =
683 demands.empty() || integer_trail->
IsFixed(demands[i]);
684 if (!helper->IsOptional(i)) {
685 if (demand_is_fixed) {
686 lc.
AddTerm(helper->Sizes()[i], demand_lower_bound);
687 }
else if (!helper->SizeIsFixed(i) &&
688 (!energies[i].vars.empty() || energies[i].offset != -1)) {
698 helper->SizeMin(i) * demand_lower_bound)) {
713 std::vector<IntervalVariable> intervals =
715 const IntegerValue capacity_upper_bound =
717 mapping->Affine(
ct.cumulative().capacity()));
723 std::vector<LinearExpression> energies;
724 std::vector<AffineExpression> demands;
725 std::vector<AffineExpression> sizes;
726 for (
int i = 0; i <
ct.cumulative().demands_size(); ++i) {
727 demands.push_back(mapping->Affine(
ct.cumulative().demands(i)));
728 sizes.push_back(intervals_repository->
Size(intervals[i]));
742 std::vector<IntervalVariable> intervals =
745 IntegerValue(1),
model,
756 std::vector<IntervalVariable> x_intervals =
757 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
758 std::vector<IntervalVariable> y_intervals =
759 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
768 std::vector<AffineExpression> x_sizes;
769 std::vector<AffineExpression> y_sizes;
770 for (
int i = 0; i <
ct.no_overlap_2d().x_intervals_size(); ++i) {
771 x_sizes.push_back(intervals_repository->Size(x_intervals[i]));
772 y_sizes.push_back(intervals_repository->Size(y_intervals[i]));
773 x_min =
std::min(x_min, integer_trail->LevelZeroLowerBound(
774 intervals_repository->Start(x_intervals[i])));
775 x_max =
std::max(x_max, integer_trail->LevelZeroUpperBound(
776 intervals_repository->End(x_intervals[i])));
777 y_min =
std::min(y_min, integer_trail->LevelZeroLowerBound(
778 intervals_repository->Start(y_intervals[i])));
779 y_max =
std::max(y_max, integer_trail->LevelZeroUpperBound(
780 intervals_repository->End(y_intervals[i])));
783 const IntegerValue max_area =
785 CapSub(y_max.value(), y_min.value())));
789 for (
int i = 0; i <
ct.no_overlap_2d().x_intervals_size(); ++i) {
790 if (intervals_repository->IsPresent(x_intervals[i]) &&
791 intervals_repository->IsPresent(y_intervals[i])) {
799 }
else if (intervals_repository->IsPresent(x_intervals[i]) ||
800 intervals_repository->IsPresent(y_intervals[i]) ||
801 (intervals_repository->PresenceLiteral(x_intervals[i]) ==
802 intervals_repository->PresenceLiteral(y_intervals[i]))) {
804 const Literal presence_literal =
805 intervals_repository->IsPresent(x_intervals[i])
806 ? intervals_repository->PresenceLiteral(y_intervals[i])
807 : intervals_repository->PresenceLiteral(x_intervals[i]);
808 const IntegerValue area_min =
810 integer_trail->LevelZeroLowerBound(y_sizes[i]);
827 NegationOf(mapping->GetExprFromProto(
ct.lin_max().target()));
828 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
830 mapping->GetExprFromProto(
ct.lin_max().exprs(i));
845 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
847 CollectAffineExpressionWithSingleVariable(
ct, mapping, &
var, &affines);
863 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
865 CollectAffineExpressionWithSingleVariable(
ct, mapping, &
var, &affines);
872 if (
ct.lin_max().target().vars().empty())
return;
877 target_expr,
var, affines,
"AffineMax",
model));
885 IntegerVariable target,
const std::vector<Literal>& alternative_literals,
886 const std::vector<LinearExpression>& exprs,
Model*
model,
888 const int num_exprs = exprs.size();
892 for (
int i = 0; i < num_exprs; ++i) {
895 local_expr.
vars.push_back(target);
896 local_expr.
coeffs = exprs[i].coeffs;
897 local_expr.
coeffs.push_back(IntegerValue(1));
910 std::vector<IntegerVariable> x_vars;
911 for (
int i = 0; i < num_exprs; ++i) {
912 x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end());
917 DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable
var) {
918 return VariableIsPositive(var);
921 std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
922 num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
925 for (
int i = 0; i < num_exprs; ++i) {
926 for (
int j = 0; j < num_exprs; ++j) {
927 if (i == j)
continue;
928 for (
const IntegerVariable x_var : x_vars) {
931 const IntegerValue diff =
933 sum_of_max_corner_diff[i][j] +=
std::max(diff * lb, diff * ub);
937 for (
int i = 0; i < num_exprs; ++i) {
939 lc.
AddTerm(target, IntegerValue(1));
940 for (
int j = 0; j < exprs[i].vars.size(); ++j) {
941 lc.
AddTerm(exprs[i].vars[j], -exprs[i].coeffs[j]);
943 for (
int j = 0; j < num_exprs; ++j) {
945 -exprs[j].offset - sum_of_max_corner_diff[i][j]));
952 bool linearize_enforced_constraints,
964 const IntegerValue rhs_domain_min = IntegerValue(
ct.linear().domain(0));
965 const IntegerValue rhs_domain_max =
966 IntegerValue(
ct.linear().domain(
ct.linear().domain_size() - 1));
973 for (
int i = 0; i <
ct.linear().vars_size(); i++) {
974 const int ref =
ct.linear().vars(i);
975 const int64_t
coeff =
ct.linear().coeffs(i);
983 if (!linearize_enforced_constraints)
return;
987 if (!mapping->IsHalfEncodingConstraint(&
ct) &&
ct.linear().vars_size() <= 1) {
991 std::vector<Literal> enforcing_literals;
992 enforcing_literals.reserve(
ct.enforcement_literal_size());
993 for (
const int enforcement_ref :
ct.enforcement_literal()) {
994 enforcing_literals.push_back(mapping->Literal(enforcement_ref));
997 expr.
vars.reserve(
ct.linear().vars_size());
998 expr.
coeffs.reserve(
ct.linear().vars_size());
999 for (
int i = 0; i <
ct.linear().vars_size(); i++) {
1000 int ref =
ct.linear().vars(i);
1001 IntegerValue
coeff(
ct.linear().coeffs(i));
1006 const IntegerVariable int_var = mapping->Integer(ref);
1007 expr.
vars.push_back(int_var);
1010 AppendEnforcedLinearExpression(enforcing_literals, expr, rhs_domain_min,
1011 rhs_domain_max, *
model, relaxation);
1026 const ConstraintProto&
ct,
1032 switch (
ct.constraint_case()) {
1033 case ConstraintProto::ConstraintCase::kBoolOr: {
1034 if (linearization_level > 1) {
1039 case ConstraintProto::ConstraintCase::kBoolAnd: {
1040 if (linearization_level > 1) {
1045 case ConstraintProto::ConstraintCase::kAtMostOne: {
1049 case ConstraintProto::ConstraintCase::kExactlyOne: {
1053 case ConstraintProto::ConstraintCase::kIntProd: {
1058 case ConstraintProto::ConstraintCase::kLinMax: {
1060 const bool is_affine_max = LinMaxContainsOnlyOneVarInExpressions(
ct);
1061 if (is_affine_max) {
1066 if (linearization_level > 1) {
1067 if (is_affine_max) {
1075 case ConstraintProto::ConstraintCase::kAllDiff: {
1076 if (linearization_level > 1) {
1081 case ConstraintProto::ConstraintCase::kLinear: {
1083 ct, linearization_level > 1,
model,
1087 case ConstraintProto::ConstraintCase::kCircuit: {
1089 if (linearization_level > 1) {
1094 case ConstraintProto::ConstraintCase::kRoutes: {
1096 if (linearization_level > 1) {
1101 case ConstraintProto::ConstraintCase::kNoOverlap: {
1102 if (linearization_level > 1) {
1108 case ConstraintProto::ConstraintCase::kCumulative: {
1109 if (linearization_level > 1) {
1115 case ConstraintProto::ConstraintCase::kNoOverlap2D: {
1118 if (linearization_level > 1) {
1133 std::vector<int> tails(
ct.circuit().tails().begin(),
1134 ct.circuit().tails().end());
1135 std::vector<int> heads(
ct.circuit().heads().begin(),
1136 ct.circuit().heads().end());
1138 std::vector<Literal> literals = mapping->
Literals(
ct.circuit().literals());
1139 const int num_nodes =
ReindexArcs(&tails, &heads);
1142 num_nodes, tails, heads, literals, m));
1147 std::vector<int> tails(
ct.routes().tails().begin(),
1148 ct.routes().tails().end());
1149 std::vector<int> heads(
ct.routes().heads().begin(),
1150 ct.routes().heads().end());
1152 std::vector<Literal> literals = mapping->
Literals(
ct.routes().literals());
1155 for (
int i = 0; i <
ct.routes().tails_size(); ++i) {
1156 num_nodes =
std::max(num_nodes, 1 +
ct.routes().tails(i));
1157 num_nodes =
std::max(num_nodes, 1 +
ct.routes().heads(i));
1159 if (
ct.routes().demands().empty() ||
ct.routes().capacity() == 0) {
1164 const std::vector<int64_t> demands(
ct.routes().demands().begin(),
1165 ct.routes().demands().end());
1167 num_nodes, tails, heads, literals, demands,
ct.routes().capacity(), m));
1174 if (
ct.int_prod().exprs_size() != 2)
return;
1184 IntegerValue x_lb = integer_trail->
LowerBound(x);
1185 IntegerValue x_ub = integer_trail->
UpperBound(x);
1186 IntegerValue y_lb = integer_trail->
LowerBound(y);
1187 IntegerValue y_ub = integer_trail->
UpperBound(y);
1191 if (x_lb < 0 && x_ub > 0)
return;
1202 if (x_lb < 0 && x_ub > 0)
return;
1203 if (y_lb < 0 && y_ub > 0)
return;
1226 const int num_exprs =
ct.all_diff().exprs_size();
1228 if (num_exprs <= m->GetOrCreate<SatParameters>()->max_all_diff_cut_size()) {
1229 std::vector<AffineExpression> exprs(num_exprs);
1230 for (
const LinearExpressionProto& expr :
ct.all_diff().exprs()) {
1231 exprs.push_back(mapping->Affine(expr));
1264 const std::vector<IntervalVariable> intervals =
1272 std::vector<LinearExpression> energies;
1273 std::vector<AffineExpression> demands;
1274 std::vector<AffineExpression> sizes;
1275 for (
int i = 0; i < intervals.size(); ++i) {
1276 demands.push_back(mapping->Affine(
ct.cumulative().demands(i)));
1277 sizes.push_back(intervals_repository->
Size(intervals[i]));
1291 bool has_variable_part =
false;
1293 for (
int i = 0; i < intervals.size(); ++i) {
1295 has_variable_part =
true;
1299 if (!integer_trail->
IsFixed(demands[i])) {
1300 has_variable_part =
true;
1304 if (has_variable_part) {
1306 intervals,
capacity, demands, energies, m));
1315 std::vector<IntervalVariable> intervals =
1325 bool has_variable_part =
false;
1326 for (
int i = 0; i < intervals.size(); ++i) {
1328 has_variable_part =
true;
1332 if (has_variable_part) {
1343 std::vector<IntervalVariable> x_intervals =
1344 mapping->
Intervals(
ct.no_overlap_2d().x_intervals());
1345 std::vector<IntervalVariable> y_intervals =
1346 mapping->Intervals(
ct.no_overlap_2d().y_intervals());
1353 bool has_variable_part =
false;
1354 for (
int i = 0; i < x_intervals.size(); ++i) {
1356 if (intervals_repository->
IsAbsent(x_intervals[i]) ||
1357 intervals_repository->
IsAbsent(y_intervals[i])) {
1362 if (!intervals_repository->
IsPresent(x_intervals[i]) ||
1363 !intervals_repository->
IsPresent(y_intervals[i])) {
1364 has_variable_part =
true;
1369 if (intervals_repository->
MinSize(x_intervals[i]) !=
1370 intervals_repository->
MaxSize(x_intervals[i]) ||
1371 intervals_repository->
MinSize(y_intervals[i]) !=
1372 intervals_repository->
MaxSize(y_intervals[i])) {
1373 has_variable_part =
true;
1377 if (has_variable_part) {
1385 if (!m->
GetOrCreate<SatParameters>()->add_lin_max_cuts())
return;
1390 if (
ct.lin_max().target().vars_size() != 1)
return;
1391 if (
ct.lin_max().target().coeffs(0) != 1)
return;
1392 if (
ct.lin_max().target().offset() != 0)
return;
1394 const IntegerVariable target =
1395 mapping->
Integer(
ct.lin_max().target().vars(0));
1396 std::vector<LinearExpression> exprs;
1397 exprs.reserve(
ct.lin_max().exprs_size());
1398 for (
int i = 0; i <
ct.lin_max().exprs_size(); ++i) {
1405 const std::vector<Literal> alternative_literals =
1415 std::vector<IntegerVariable> z_vars;
1417 for (
const Literal lit : alternative_literals) {
1418 z_vars.push_back(encoder->GetLiteralView(lit));
1437 int num_exactly_one_elements = 0;
1439 for (
const IntegerVariable
var :
1440 implied_bounds->GetElementEncodedVariables()) {
1441 for (
const auto& [
index, literal_value_list] :
1442 implied_bounds->GetElementEncodings(
var)) {
1448 absl::flat_hash_set<IntegerValue> values;
1449 for (
const auto& literal_value : literal_value_list) {
1450 min_value =
std::min(min_value, literal_value.value);
1451 values.insert(literal_value.value);
1453 if (values.size() == literal_value_list.size())
continue;
1457 linear_encoding.
AddTerm(
var, IntegerValue(-1));
1458 for (
const auto& [
value,
literal] : literal_value_list) {
1459 const IntegerValue delta_min =
value - min_value;
1460 if (delta_min != 0) {
1467 ++num_exactly_one_elements;
1472 if (num_exactly_one_elements != 0) {
1475 "[ElementLinearRelaxation]"
1476 " #from_exactly_one:",
1477 num_exactly_one_elements);
1486 const SatParameters& params = *m->
GetOrCreate<SatParameters>();
1493 int num_loose_equality_encoding_relaxations = 0;
1494 int num_tight_equality_encoding_relaxations = 0;
1495 int num_inequality_encoding_relaxations = 0;
1497 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
1498 if (mapping->IsBoolean(i))
continue;
1500 const IntegerVariable
var = mapping->Integer(i);
1505 var, *m, &relaxation, &num_tight_equality_encoding_relaxations,
1506 &num_loose_equality_encoding_relaxations);
1521 ++num_inequality_encoding_relaxations;
1527 if (params.linearization_level() >= 2) {
1539 if (num_tight_equality_encoding_relaxations != 0 ||
1540 num_loose_equality_encoding_relaxations != 0 ||
1541 num_inequality_encoding_relaxations != 0) {
1543 "[EncodingLinearRelaxation]"
1544 " #tight_equality:",
1545 num_tight_equality_encoding_relaxations,
1546 " #loose_equality:", num_loose_equality_encoding_relaxations,
1547 " #inequality:", num_inequality_encoding_relaxations);
1552 "[LinearRelaxationBeforeCliqueExpansion]"
1561 &relaxation.
at_most_ones, params.merge_at_most_one_work_limit());
1562 for (
const std::vector<Literal>& at_most_one : relaxation.
at_most_ones) {
1563 if (at_most_one.empty())
continue;
1569 const bool unused ABSL_ATTRIBUTE_UNUSED =
1592 if (params.linearization_level() > 1 && params.add_clique_cuts()) {
1594 for (
int i = 0; i <
model_proto.variables_size(); ++i) {
1595 if (!mapping->IsBoolean(i))
continue;
1599 const bool unused ABSL_ATTRIBUTE_UNUSED =
1605 if (!expr.
vars.empty()) {
1614 "[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
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).
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 AddCumulativeRelaxation(const std::vector< IntervalVariable > &intervals, const std::vector< AffineExpression > &demands, const std::vector< LinearExpression > &energies, IntegerValue capacity_upper_bound, 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)
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)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
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)
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,...)