18 #include "absl/container/flat_hash_set.h"
36 if (encoder ==
nullptr)
return false;
37 if (!encoder->VariableIsFullyEncoded(
var))
return false;
48 std::vector<Literal> at_most_one;
50 for (
const auto value_literal : encoding) {
51 const Literal lit = value_literal.literal;
52 const IntegerValue
delta = value_literal.value - var_min;
54 at_most_one.push_back(lit);
55 if (!at_least_one.
AddLiteralTerm(lit, IntegerValue(1)))
return false;
56 if (
delta != IntegerValue(0)) {
70 std::pair<IntegerValue, IntegerValue> GetMinAndMaxNotEncoded(
72 const absl::flat_hash_set<IntegerValue>& encoded_values,
74 const auto* domains =
model.Get<IntegerDomains>();
75 if (domains ==
nullptr ||
var >= domains->size()) {
82 for (
const ClosedInterval
interval : (*domains)[
var]) {
93 const auto& domain = (*domains)[
var];
94 for (
int i = domain.NumIntervals() - 1; i >= 0; --i) {
95 const ClosedInterval
interval = domain[i];
114 if (encoder ==
nullptr || integer_trail ==
nullptr)
return;
116 const std::vector<IntegerEncoder::ValueLiteralPair>& encoding =
117 encoder->PartialDomainEncoding(
var);
118 if (encoding.empty())
return;
120 std::vector<Literal> at_most_one_ct;
121 absl::flat_hash_set<IntegerValue> encoded_values;
122 for (
const auto value_literal : encoding) {
131 at_most_one_ct.push_back(
literal);
132 encoded_values.insert(value_literal.value);
134 if (encoded_values.empty())
return;
140 const auto pair = GetMinAndMaxNotEncoded(
var, encoded_values,
model);
150 for (
const auto value_literal : encoding) {
151 const Literal lit = value_literal.literal;
154 encoding_ct.
AddLiteralTerm(lit, IntegerValue(-value_literal.value)));
162 const IntegerValue d_min = pair.first;
165 for (
const auto value_literal : encoding) {
167 d_min - value_literal.value));
171 const IntegerValue d_max = pair.second;
174 for (
const auto value_literal : encoding) {
176 d_max - value_literal.value));
190 if (integer_trail ==
nullptr || encoder ==
nullptr)
return;
192 const std::map<IntegerValue, Literal>& greater_than_encoding =
193 encoder->PartialGreaterThanEncoding(
var);
194 if (greater_than_encoding.empty())
return;
199 IntegerValue prev_used_bound = integer_trail->
LowerBound(
var);
204 for (
const auto entry : greater_than_encoding) {
205 if (entry.first <= prev_used_bound)
continue;
207 const LiteralIndex literal_index = entry.second.Index();
208 const IntegerValue diff = prev_used_bound - entry.first;
217 prev_used_bound = entry.first;
218 prev_literal_index = literal_index;
226 IntegerValue prev_used_bound = integer_trail->LowerBound(
NegationOf(
var));
230 for (
const auto entry :
232 if (entry.first <= prev_used_bound)
continue;
233 const IntegerValue diff = prev_used_bound - entry.first;
237 prev_used_bound = entry.first;
245 void AppendEnforcedUpperBound(
const Literal enforcing_lit,
246 const IntegerVariable target,
247 const IntegerVariable bounding_var, Model*
model,
248 LinearRelaxation* relaxation) {
249 IntegerTrail* integer_trail =
model->GetOrCreate<IntegerTrail>();
250 const IntegerValue max_target_value = integer_trail->UpperBound(target);
251 const IntegerValue min_var_value = integer_trail->LowerBound(bounding_var);
252 const IntegerValue max_term_value = max_target_value - min_var_value;
254 lc.AddTerm(target, IntegerValue(1));
255 lc.AddTerm(bounding_var, IntegerValue(-1));
256 CHECK(lc.AddLiteralTerm(enforcing_lit, max_term_value));
257 relaxation->linear_constraints.push_back(lc.Build());
262 void AppendEnforcedLinearExpression(
263 const std::vector<Literal>& enforcing_literals,
264 const LinearExpression& expr,
const IntegerValue rhs_domain_min,
265 const IntegerValue rhs_domain_max,
const Model&
model,
266 LinearRelaxation* relaxation) {
267 CHECK_EQ(expr.offset, IntegerValue(0));
269 const IntegerTrail* integer_trail =
model.Get<IntegerTrail>();
270 const IntegerValue min_expr_value =
273 if (rhs_domain_min > min_expr_value) {
278 for (
const Literal&
literal : enforcing_literals) {
280 rhs_domain_min - min_expr_value));
282 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
283 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
285 relaxation->linear_constraints.push_back(lc.Build());
287 const IntegerValue max_expr_value =
289 if (rhs_domain_max < max_expr_value) {
294 for (
const Literal&
literal : enforcing_literals) {
296 rhs_domain_max - max_expr_value));
298 for (
int i = 0; i < canonical_expr.vars.size(); i++) {
299 lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
301 relaxation->linear_constraints.push_back(lc.Build());
317 int linearization_level,
322 if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) {
323 if (linearization_level < 2)
return;
325 for (
const int enforcement_ref :
ct.enforcement_literal()) {
329 for (
const int ref :
ct.bool_or().literals()) {
333 }
else if (
ct.constraint_case() ==
334 ConstraintProto::ConstraintCase::kBoolAnd) {
338 if (linearization_level < 2)
return;
340 if (
ct.enforcement_literal().size() == 1) {
342 for (
const int ref :
ct.bool_and().literals()) {
344 {enforcement, mapping->
Literal(ref).Negated()});
351 int num_literals =
ct.bool_and().literals_size();
354 for (
const int ref :
ct.bool_and().literals()) {
357 for (
const int enforcement_ref :
ct.enforcement_literal()) {
359 IntegerValue(num_literals)));
362 }
else if (
ct.constraint_case() ==
363 ConstraintProto::ConstraintCase::kAtMostOne) {
365 std::vector<Literal> at_most_one;
366 for (
const int ref :
ct.at_most_one().literals()) {
367 at_most_one.push_back(mapping->Literal(ref));
370 }
else if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMax) {
372 const IntegerVariable target = mapping->Integer(
ct.int_max().target());
373 const std::vector<IntegerVariable> vars =
374 mapping->Integers(
ct.int_max().vars());
377 }
else if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMin) {
379 const IntegerVariable negative_target =
381 const std::vector<IntegerVariable> negative_vars =
385 }
else if (
ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) {
388 }
else if (
ct.constraint_case() ==
389 ConstraintProto::ConstraintCase::kCircuit) {
391 const int num_arcs =
ct.circuit().literals_size();
392 CHECK_EQ(num_arcs,
ct.circuit().tails_size());
393 CHECK_EQ(num_arcs,
ct.circuit().heads_size());
397 std::map<int, std::vector<Literal>> incoming_arc_constraints;
398 std::map<int, std::vector<Literal>> outgoing_arc_constraints;
399 for (
int i = 0; i < num_arcs; i++) {
401 const int tail =
ct.circuit().tails(i);
402 const int head =
ct.circuit().heads(i);
406 outgoing_arc_constraints[
tail].push_back(arc);
407 incoming_arc_constraints[
head].push_back(arc);
409 for (
const auto* node_map :
410 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
411 for (
const auto& entry : *node_map) {
412 const std::vector<Literal>& exactly_one = entry.second;
413 if (exactly_one.size() > 1) {
416 for (
const Literal l : exactly_one) {
426 }
else if (
ct.constraint_case() ==
427 ConstraintProto::ConstraintCase::kElement) {
428 const IntegerVariable
index = mapping->Integer(
ct.element().index());
429 const IntegerVariable target = mapping->Integer(
ct.element().target());
430 const std::vector<IntegerVariable> vars =
431 mapping->Integers(
ct.element().vars());
436 constraint.
AddTerm(target, IntegerValue(-1));
439 const IntegerVariable
var = vars[literal_value.value.value()];
449 }
else if (
ct.constraint_case() ==
450 ConstraintProto::ConstraintCase::kInterval) {
451 if (linearization_level < 2)
return;
452 const IntegerVariable start = mapping->Integer(
ct.interval().start());
453 const IntegerVariable size = mapping->Integer(
ct.interval().size());
454 const IntegerVariable end = mapping->Integer(
ct.interval().end());
456 const bool size_is_fixed = integer_trail->
IsFixed(size);
457 const IntegerValue rhs =
458 size_is_fixed ? -integer_trail->
LowerBound(size) : IntegerValue(0);
460 lc.
AddTerm(start, IntegerValue(1));
461 if (!size_is_fixed) {
462 lc.
AddTerm(size, IntegerValue(1));
464 lc.
AddTerm(end, IntegerValue(-1));
470 AppendEnforcedLinearExpression(
471 mapping->Literals(
ct.enforcement_literal()), expr, tmp_lc.
ub,
472 tmp_lc.
ub, *
model, relaxation);
476 }
else if (
ct.constraint_case() ==
477 ConstraintProto::ConstraintCase::kNoOverlap) {
480 }
else if (
ct.constraint_case() ==
481 ConstraintProto::ConstraintCase::kCumulative) {
488 const std::vector<IntegerVariable>& demands,
489 IntegerValue capacity_lower_bound,
Model*
model,
492 const int num_intervals = helper.
NumTasks();
499 int num_variable_sizes = 0;
500 int num_optionals = 0;
511 (!demands.empty() && !integer_trail->
IsFixed(demands[
index]))) {
512 num_variable_sizes++;
516 VLOG(2) <<
"Span [" << min_of_starts <<
".." << max_of_ends <<
"] with "
517 << num_optionals <<
" optional intervals, and " << num_variable_sizes
518 <<
" variable size intervals out of " << num_intervals
521 if (num_variable_sizes + num_optionals == 0)
return;
523 const IntegerVariable span_start =
526 IntegerValue(0), max_of_ends - min_of_starts);
527 const IntegerVariable span_end =
530 IntervalVariable span_var;
531 if (num_optionals < num_intervals) {
535 span_var =
model->Add(
542 lc.
AddTerm(span_size, -capacity_lower_bound);
543 for (
int i = 0; i < num_intervals; ++i) {
544 const IntegerValue demand_lower_bound =
545 demands.empty() ? IntegerValue(1)
547 const bool demand_is_fixed =
548 demands.empty() || integer_trail->
IsFixed(demands[i]);
552 }
else if (demand_is_fixed) {
568 helper.
SizeMin(i) * demand_lower_bound)) {
577 const ConstraintProto&
ct,
581 if (linearization_level < 2)
return;
585 const std::vector<IntegerVariable> demands =
587 std::vector<IntervalVariable> intervals =
588 mapping->Intervals(
ct.cumulative().intervals());
589 const IntegerValue capacity_lower_bound =
591 mapping->Integer(
ct.cumulative().capacity()));
596 const ConstraintProto&
ct,
600 if (linearization_level < 2)
return;
604 std::vector<IntervalVariable> intervals =
607 IntegerValue(1),
model, relaxation);
611 const std::vector<IntegerVariable>& vars,
616 for (
const IntegerVariable
var : vars) {
619 if (target ==
var)
continue;
622 lc.
AddTerm(target, IntegerValue(-1));
627 if (linearization_level < 2)
return;
631 if (vars.size() == 2) {
634 encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
635 AppendEnforcedUpperBound(y_lit, target, vars[0],
model, relaxation);
640 {y_lit}, {target, vars[0]}, {IntegerValue(1), IntegerValue(-1)},
641 IntegerValue(0),
model);
643 model->TakeOwnership(upper_bound1);
644 AppendEnforcedUpperBound(y_lit.
Negated(), target, vars[1],
model,
647 {y_lit.
Negated()}, {target, vars[1]},
648 {IntegerValue(1), IntegerValue(-1)}, IntegerValue(0),
model);
650 model->TakeOwnership(upper_bound2);
659 std::vector<Literal> exactly_one_literals;
660 exactly_one_literals.reserve(vars.size());
661 for (
const IntegerVariable
var : vars) {
662 if (target ==
var)
continue;
668 encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
670 AppendEnforcedUpperBound(y_lit, target,
var,
model, relaxation);
672 {y_lit}, {target,
var}, {IntegerValue(1), IntegerValue(-1)},
673 IntegerValue(0),
model);
675 model->TakeOwnership(upper_bound_constraint);
676 exactly_one_literals.push_back(y_lit);
685 IntegerVariable target,
const std::vector<LinearExpression>& exprs,
691 for (
int i = 0; i < expr.vars.size(); ++i) {
692 lc.
AddTerm(expr.vars[i], expr.coeffs[i]);
694 lc.
AddTerm(target, IntegerValue(-1));
702 const int num_exprs = exprs.size();
707 std::vector<IntegerVariable> z_vars;
708 std::vector<Literal> z_lits;
709 z_vars.reserve(num_exprs);
710 z_lits.reserve(num_exprs);
713 std::vector<Literal> exactly_one_literals;
714 for (
int i = 0; i < num_exprs; ++i) {
719 z_lits.push_back(z_lit);
722 local_expr.
vars.push_back(target);
723 local_expr.
coeffs = exprs[i].coeffs;
724 local_expr.
coeffs.push_back(IntegerValue(1));
728 model->TakeOwnership(upper_bound);
738 std::vector<IntegerVariable> x_vars;
739 for (
int i = 0; i < num_exprs; ++i) {
740 x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end());
744 DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable
var) {
745 return VariableIsPositive(var);
748 std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
749 num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
752 for (
int i = 0; i < num_exprs; ++i) {
753 for (
int j = 0; j < num_exprs; ++j) {
754 if (i == j)
continue;
755 for (
const IntegerVariable x_var : x_vars) {
758 const IntegerValue diff =
760 sum_of_max_corner_diff[i][j] +=
std::max(diff * lb, diff * ub);
764 for (
int i = 0; i < num_exprs; ++i) {
766 lc.
AddTerm(target, IntegerValue(1));
767 for (
int j = 0; j < exprs[i].vars.size(); ++j) {
768 lc.
AddTerm(exprs[i].vars[j], -exprs[i].coeffs[j]);
770 for (
int j = 0; j < num_exprs; ++j) {
772 -exprs[j].offset - sum_of_max_corner_diff[i][j]));
782 const int linearization_level,
794 const IntegerValue rhs_domain_min =
795 IntegerValue(constraint_proto.linear().domain(0));
796 const IntegerValue rhs_domain_max =
797 IntegerValue(constraint_proto.linear().domain(
798 constraint_proto.linear().domain_size() - 1));
803 for (
int i = 0; i < constraint_proto.linear().vars_size(); i++) {
804 const int ref = constraint_proto.linear().vars(i);
805 const int64 coeff = constraint_proto.linear().coeffs(i);
806 lc.
AddTerm(mapping->Integer(ref), IntegerValue(coeff));
813 if (linearization_level < 2)
return;
817 if (!mapping->IsHalfEncodingConstraint(&constraint_proto) &&
818 constraint_proto.linear().vars_size() <= 1) {
822 std::vector<Literal> enforcing_literals;
823 enforcing_literals.reserve(constraint_proto.enforcement_literal_size());
824 for (
const int enforcement_ref : constraint_proto.enforcement_literal()) {
825 enforcing_literals.push_back(mapping->Literal(enforcement_ref));
828 expr.
vars.reserve(constraint_proto.linear().vars_size());
829 expr.
coeffs.reserve(constraint_proto.linear().vars_size());
830 for (
int i = 0; i < constraint_proto.linear().vars_size(); i++) {
831 int ref = constraint_proto.linear().vars(i);
832 IntegerValue coeff(constraint_proto.linear().coeffs(i));
837 const IntegerVariable int_var = mapping->Integer(ref);
838 expr.
vars.push_back(int_var);
839 expr.
coeffs.push_back(coeff);
841 AppendEnforcedLinearExpression(enforcing_literals, expr, rhs_domain_min,
842 rhs_domain_max,
model, relaxation);