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) {
489 const std::vector<IntegerVariable>& demands,
490 IntegerValue capacity_lower_bound,
Model*
model,
495 model->TakeOwnership(helper);
496 const int num_intervals = helper->NumTasks();
503 int num_variable_sizes = 0;
504 int num_optionals = 0;
507 min_of_starts =
std::min(min_of_starts, helper->StartMin(
index));
510 if (helper->IsOptional(
index)) {
514 if (!helper->SizeIsFixed(
index) ||
515 (!demands.empty() && !integer_trail->
IsFixed(demands[
index]))) {
516 num_variable_sizes++;
520 VLOG(2) <<
"Span [" << min_of_starts <<
".." << max_of_ends <<
"] with "
521 << num_optionals <<
" optional intervals, and " << num_variable_sizes
522 <<
" variable size intervals out of " << num_intervals
525 if (num_variable_sizes + num_optionals == 0)
return;
527 const IntegerVariable span_start =
530 IntegerValue(0), max_of_ends - min_of_starts);
531 const IntegerVariable span_end =
534 IntervalVariable span_var;
535 if (num_optionals < num_intervals) {
539 span_var =
model->Add(
546 lc.
AddTerm(span_size, -capacity_lower_bound);
547 for (
int i = 0; i < num_intervals; ++i) {
548 const IntegerValue demand_lower_bound =
549 demands.empty() ? IntegerValue(1)
551 const bool demand_is_fixed =
552 demands.empty() || integer_trail->
IsFixed(demands[i]);
553 if (!helper->IsOptional(i)) {
554 if (helper->SizeIsFixed(i) && !demands.empty()) {
555 lc.
AddTerm(demands[i], helper->SizeMin(i));
556 }
else if (demand_is_fixed) {
557 lc.
AddTerm(helper->Sizes()[i], demand_lower_bound);
566 lc.
AddTerm(helper->Sizes()[i], demand_lower_bound);
567 lc.
AddTerm(demands[i], helper->SizeMin(i));
568 lc.
AddConstant(-helper->SizeMin(i) * demand_lower_bound);
572 helper->SizeMin(i) * demand_lower_bound)) {
581 const ConstraintProto&
ct,
585 if (linearization_level < 2)
return;
589 const std::vector<IntegerVariable> demands =
591 std::vector<IntervalVariable> intervals =
592 mapping->Intervals(
ct.cumulative().intervals());
593 const IntegerValue capacity_lower_bound =
595 mapping->Integer(
ct.cumulative().capacity()));
600 const ConstraintProto&
ct,
604 if (linearization_level < 2)
return;
608 std::vector<IntervalVariable> intervals =
611 IntegerValue(1),
model, relaxation);
615 const std::vector<IntegerVariable>& vars,
620 for (
const IntegerVariable
var : vars) {
623 if (target ==
var)
continue;
626 lc.
AddTerm(target, IntegerValue(-1));
631 if (linearization_level < 2)
return;
635 if (vars.size() == 2) {
638 encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
639 AppendEnforcedUpperBound(y_lit, target, vars[0],
model, relaxation);
644 {y_lit}, {target, vars[0]}, {IntegerValue(1), IntegerValue(-1)},
645 IntegerValue(0),
model);
647 model->TakeOwnership(upper_bound1);
648 AppendEnforcedUpperBound(y_lit.
Negated(), target, vars[1],
model,
651 {y_lit.
Negated()}, {target, vars[1]},
652 {IntegerValue(1), IntegerValue(-1)}, IntegerValue(0),
model);
654 model->TakeOwnership(upper_bound2);
663 std::vector<Literal> exactly_one_literals;
664 exactly_one_literals.reserve(vars.size());
665 for (
const IntegerVariable
var : vars) {
666 if (target ==
var)
continue;
672 encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
674 AppendEnforcedUpperBound(y_lit, target,
var,
model, relaxation);
676 {y_lit}, {target,
var}, {IntegerValue(1), IntegerValue(-1)},
677 IntegerValue(0),
model);
679 model->TakeOwnership(upper_bound_constraint);
680 exactly_one_literals.push_back(y_lit);
689 IntegerVariable target,
const std::vector<LinearExpression>& exprs,
695 for (
int i = 0; i < expr.vars.size(); ++i) {
696 lc.
AddTerm(expr.vars[i], expr.coeffs[i]);
698 lc.
AddTerm(target, IntegerValue(-1));
706 const int num_exprs = exprs.size();
711 std::vector<IntegerVariable> z_vars;
712 std::vector<Literal> z_lits;
713 z_vars.reserve(num_exprs);
714 z_lits.reserve(num_exprs);
717 std::vector<Literal> exactly_one_literals;
718 for (
int i = 0; i < num_exprs; ++i) {
723 z_lits.push_back(z_lit);
726 local_expr.
vars.push_back(target);
727 local_expr.
coeffs = exprs[i].coeffs;
728 local_expr.
coeffs.push_back(IntegerValue(1));
732 model->TakeOwnership(upper_bound);
742 std::vector<IntegerVariable> x_vars;
743 for (
int i = 0; i < num_exprs; ++i) {
744 x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end());
748 DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable
var) {
749 return VariableIsPositive(var);
752 std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
753 num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
756 for (
int i = 0; i < num_exprs; ++i) {
757 for (
int j = 0; j < num_exprs; ++j) {
758 if (i == j)
continue;
759 for (
const IntegerVariable x_var : x_vars) {
762 const IntegerValue diff =
764 sum_of_max_corner_diff[i][j] +=
std::max(diff * lb, diff * ub);
768 for (
int i = 0; i < num_exprs; ++i) {
770 lc.
AddTerm(target, IntegerValue(1));
771 for (
int j = 0; j < exprs[i].vars.size(); ++j) {
772 lc.
AddTerm(exprs[i].vars[j], -exprs[i].coeffs[j]);
774 for (
int j = 0; j < num_exprs; ++j) {
776 -exprs[j].offset - sum_of_max_corner_diff[i][j]));
786 const int linearization_level,
798 const IntegerValue rhs_domain_min =
799 IntegerValue(constraint_proto.linear().domain(0));
800 const IntegerValue rhs_domain_max =
801 IntegerValue(constraint_proto.linear().domain(
802 constraint_proto.linear().domain_size() - 1));
807 for (
int i = 0; i < constraint_proto.linear().vars_size(); i++) {
808 const int ref = constraint_proto.linear().vars(i);
809 const int64 coeff = constraint_proto.linear().coeffs(i);
810 lc.
AddTerm(mapping->Integer(ref), IntegerValue(coeff));
817 if (linearization_level < 2)
return;
821 if (!mapping->IsHalfEncodingConstraint(&constraint_proto) &&
822 constraint_proto.linear().vars_size() <= 1) {
826 std::vector<Literal> enforcing_literals;
827 enforcing_literals.reserve(constraint_proto.enforcement_literal_size());
828 for (
const int enforcement_ref : constraint_proto.enforcement_literal()) {
829 enforcing_literals.push_back(mapping->Literal(enforcement_ref));
832 expr.
vars.reserve(constraint_proto.linear().vars_size());
833 expr.
coeffs.reserve(constraint_proto.linear().vars_size());
834 for (
int i = 0; i < constraint_proto.linear().vars_size(); i++) {
835 int ref = constraint_proto.linear().vars(i);
836 IntegerValue coeff(constraint_proto.linear().coeffs(i));
841 const IntegerVariable int_var = mapping->Integer(ref);
842 expr.
vars.push_back(int_var);
843 expr.
coeffs.push_back(coeff);
845 AppendEnforcedLinearExpression(enforcing_literals, expr, rhs_domain_min,
846 rhs_domain_max,
model, relaxation);