24#include "absl/base/attributes.h"
25#include "absl/container/btree_map.h"
26#include "absl/container/flat_hash_map.h"
27#include "absl/container/flat_hash_set.h"
28#include "absl/log/check.h"
29#include "absl/meta/type_traits.h"
30#include "absl/types/span.h"
31#include "google/protobuf/message.h"
38#include "ortools/sat/cp_model.pb.h"
57#include "ortools/sat/sat_parameters.pb.h"
72std::pair<IntegerValue, IntegerValue> GetMinAndMaxNotEncoded(
74 const absl::flat_hash_set<IntegerValue>& encoded_values,
80 if (domains ==
nullptr || index >= domains->size()) {
87 for (
const int64_t v : (*domains)[index].
Values()) {
88 if (!encoded_values.contains(IntegerValue(v))) {
89 min = IntegerValue(v);
95 const Domain negated_domain = (*domains)[index].Negation();
96 for (
const int64_t v : negated_domain.Values()) {
97 if (!encoded_values.contains(IntegerValue(-v))) {
98 max = IntegerValue(-v);
111void CollectAffineExpressionWithSingleVariable(
112 const ConstraintProto& ct,
CpModelMapping* mapping, IntegerVariable* var,
113 std::vector<std::pair<IntegerValue, IntegerValue>>* affines) {
115 CHECK_EQ(ct.constraint_case(), ConstraintProto::ConstraintCase::kLinMax);
118 for (
const LinearExpressionProto& expr : ct.lin_max().exprs()) {
119 if (expr.vars().empty()) {
120 affines->push_back({IntegerValue(0), IntegerValue(expr.offset())});
122 CHECK_EQ(expr.vars().size(), 1);
123 const IntegerVariable affine_var = mapping->Integer(expr.vars(0));
128 CHECK_EQ(affine_var, *var);
130 {IntegerValue(expr.coeffs(0)), IntegerValue(expr.offset())});
134 {IntegerValue(-expr.coeffs(0)), IntegerValue(expr.offset())});
145 int* num_tight,
int* num_loose) {
148 if (encoder ==
nullptr || integer_trail ==
nullptr)
return;
150 std::vector<Literal> at_most_one_ct;
151 absl::flat_hash_set<IntegerValue> encoded_values;
152 std::vector<ValueLiteralPair> encoding;
154 const std::vector<ValueLiteralPair>& initial_encoding =
155 encoder->PartialDomainEncoding(var);
156 if (initial_encoding.empty())
return;
157 for (
const auto value_literal : initial_encoding) {
158 const Literal literal = value_literal.literal;
166 encoding.push_back(value_literal);
167 at_most_one_ct.push_back(literal);
168 encoded_values.insert(value_literal.value);
171 if (encoded_values.empty())
return;
178 const auto [min_not_encoded, max_not_encoded] =
179 GetMinAndMaxNotEncoded(var, encoded_values, model);
184 const IntegerValue rhs = encoding[0].value;
188 encoding_ct.
AddTerm(var, IntegerValue(1));
189 for (
const auto value_literal : encoding) {
190 const Literal lit = value_literal.literal;
193 const IntegerValue delta = value_literal.value - rhs;
194 if (delta != IntegerValue(0)) {
195 CHECK_GE(delta, IntegerValue(0));
216 if (min_not_encoded == max_not_encoded) {
217 const IntegerValue rhs = min_not_encoded;
219 encoding_ct.
AddTerm(var, IntegerValue(1));
220 for (
const auto value_literal : encoding) {
222 rhs - value_literal.value));
236 const IntegerValue d_min = min_not_encoded;
238 lower_bound_ct.
AddTerm(var, IntegerValue(1));
239 for (
const auto value_literal : encoding) {
241 d_min - value_literal.value));
251 const IntegerValue d_max = max_not_encoded;
253 upper_bound_ct.
AddTerm(var, IntegerValue(1));
254 for (
const auto value_literal : encoding) {
256 d_max - value_literal.value));
273 if (integer_trail ==
nullptr || encoder ==
nullptr)
return;
275 const auto& greater_than_encoding = encoder->PartialGreaterThanEncoding(var);
276 if (greater_than_encoding.empty())
return;
281 IntegerValue prev_used_bound = integer_trail->LowerBound(var);
283 builder.
AddTerm(var, IntegerValue(1));
285 for (
const auto entry : greater_than_encoding) {
286 if (entry.value <= prev_used_bound)
continue;
288 const LiteralIndex literal_index = entry.literal.Index();
289 const IntegerValue diff = prev_used_bound - entry.value;
298 prev_used_bound = entry.value;
299 prev_literal_index = literal_index;
309 IntegerValue prev_used_bound = integer_trail->LowerBound(
NegationOf(var));
311 builder.
AddTerm(var, IntegerValue(-1));
312 for (
const auto entry :
313 encoder->PartialGreaterThanEncoding(
NegationOf(var))) {
314 if (entry.value <= prev_used_bound)
continue;
315 const IntegerValue diff = prev_used_bound - entry.value;
319 prev_used_bound = entry.value;
329bool AllLiteralsHaveViews(
const IntegerEncoder& encoder,
330 absl::Span<const Literal> literals) {
331 for (
const Literal lit : literals) {
332 if (!encoder.LiteralOrNegationHasView(lit))
return false;
343 for (
const int enforcement_ref : ct.enforcement_literal()) {
344 CHECK(lc.AddLiteralTerm(mapping->Literal(
NegatedRef(enforcement_ref)),
347 for (
const int ref : ct.bool_or().literals()) {
348 CHECK(lc.AddLiteralTerm(mapping->Literal(ref), IntegerValue(1)));
365 if (ct.enforcement_literal().size() == 1) {
366 const Literal enforcement = mapping->
Literal(ct.enforcement_literal(0));
367 for (
const int ref : ct.bool_and().literals()) {
369 {enforcement, mapping->
Literal(ref).Negated()});
390 if (activity_helper !=
nullptr) {
391 std::vector<int> negated_lits;
392 for (
const int ref : ct.bool_and().literals()) {
395 for (absl::Span<const int> part :
398 for (
const int negated_ref : part) {
401 for (
const int enforcement_ref : ct.enforcement_literal()) {
403 mapping->Literal(
NegatedRef(enforcement_ref)), IntegerValue(-1)));
409 for (
const int ref : ct.bool_and().literals()) {
412 for (
const int enforcement_ref : ct.enforcement_literal()) {
414 mapping->Literal(
NegatedRef(enforcement_ref)), IntegerValue(-1)));
428 mapping->Literals(ct.at_most_one().literals()));
437 const std::vector<Literal> literals =
438 mapping->Literals(ct.exactly_one().literals());
439 if (AllLiteralsHaveViews(*encoder, literals)) {
441 for (
const Literal lit : literals) {
456 if (num_literals == 1) {
461 encoder->GetOrCreateLiteralAssociatedToEquality(var, IntegerValue(1));
465 if (num_literals == 2) {
468 encoder->GetOrCreateLiteralAssociatedToEquality(var, IntegerValue(1));
474 encoder->AssociateToIntegerEqualValue(lit.
Negated(), var2, IntegerValue(1));
479 std::vector<Literal> literals;
481 for (
int i = 0;
i < num_literals; ++
i) {
484 encoder->GetOrCreateLiteralAssociatedToEquality(var, IntegerValue(1));
485 literals.push_back(lit);
497 const int num_arcs = ct.circuit().literals_size();
498 CHECK_EQ(num_arcs, ct.circuit().tails_size());
499 CHECK_EQ(num_arcs, ct.circuit().heads_size());
503 absl::btree_map<int, std::vector<Literal>> incoming_arc_constraints;
504 absl::btree_map<int, std::vector<Literal>> outgoing_arc_constraints;
505 for (
int i = 0;
i < num_arcs;
i++) {
507 const int tail = ct.circuit().tails(
i);
508 const int head = ct.circuit().heads(
i);
509 outgoing_arc_constraints[tail].push_back(arc);
510 incoming_arc_constraints[head].push_back(arc);
512 for (
const auto* node_map :
513 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
514 for (
const auto& entry : *node_map) {
515 const std::vector<Literal>& exactly_one = entry.second;
516 if (exactly_one.size() > 1) {
519 for (
const Literal l : exactly_one) {
535 const int num_arcs = ct.routes().literals_size();
536 CHECK_EQ(num_arcs, ct.routes().tails_size());
537 CHECK_EQ(num_arcs, ct.routes().heads_size());
543 absl::btree_map<int, std::vector<Literal>> incoming_arc_constraints;
544 absl::btree_map<int, std::vector<Literal>> outgoing_arc_constraints;
545 for (
int i = 0;
i < num_arcs;
i++) {
547 const int tail = ct.routes().tails(
i);
548 const int head = ct.routes().heads(
i);
549 outgoing_arc_constraints[tail].push_back(arc);
550 incoming_arc_constraints[head].push_back(arc);
552 for (
const auto* node_map :
553 {&outgoing_arc_constraints, &incoming_arc_constraints}) {
554 for (
const auto& entry : *node_map) {
555 if (entry.first == 0)
continue;
556 const std::vector<Literal>& exactly_one = entry.second;
557 if (exactly_one.size() > 1) {
560 for (
const Literal l : exactly_one) {
572 for (
const Literal& incoming_arc : incoming_arc_constraints[0]) {
573 CHECK(zero_node_balance_lc.
AddLiteralTerm(incoming_arc, IntegerValue(1)));
575 for (
const Literal& outgoing_arc : outgoing_arc_constraints[0]) {
576 CHECK(zero_node_balance_lc.
AddLiteralTerm(outgoing_arc, IntegerValue(-1)));
583 std::vector<int> tails(ct.circuit().tails().begin(),
584 ct.circuit().tails().end());
585 std::vector<int> heads(ct.circuit().heads().begin(),
586 ct.circuit().heads().end());
588 std::vector<Literal> literals = mapping->
Literals(ct.circuit().literals());
592 num_nodes, tails, heads, literals, m));
597 std::vector<int> tails(ct.routes().tails().begin(),
598 ct.routes().tails().end());
599 std::vector<int> heads(ct.routes().heads().begin(),
600 ct.routes().heads().end());
602 std::vector<Literal> literals = mapping->
Literals(ct.routes().literals());
605 for (
int i = 0;
i < ct.routes().tails_size(); ++
i) {
606 num_nodes = std::max(num_nodes, 1 + ct.routes().tails(
i));
607 num_nodes = std::max(num_nodes, 1 + ct.routes().heads(
i));
609 if (ct.routes().demands().empty() || ct.routes().capacity() == 0) {
614 const std::vector<int64_t> demands(ct.routes().demands().begin(),
615 ct.routes().demands().end());
617 num_nodes, tails, heads, literals, demands, ct.routes().capacity(), m));
637 absl::Span<const AffineExpression> demands,
644 if (!integer_trail->
IsFixed(capacity)) {
650 for (
int i = 0;
i < intervals.size(); ++
i) {
651 if (repository->IsAbsent(intervals[
i]))
continue;
653 horizon, integer_trail->
UpperBound(repository->End(intervals[
i])));
656 const IntegerValue capacity_value = integer_trail->
FixedValue(capacity);
657 for (
int i = 0;
i < intervals.size(); ++
i) {
658 if (!repository->IsPresent(intervals[
i]))
continue;
660 if (integer_trail->
IsFixed(demands[
i]) &&
661 integer_trail->
FixedValue(demands[
i]) == capacity_value &&
664 integer_trail->
LowerBound(repository->Size(intervals[
i])) > 0) {
673std::optional<AffineExpression> DetectMakespanFromPrecedences(
674 const SchedulingConstraintHelper& helper,
Model* model) {
675 if (helper.NumTasks() == 0)
return {};
677 const absl::Span<const AffineExpression> ends = helper.Ends();
678 std::vector<IntegerVariable> end_vars;
679 for (
const AffineExpression& end : ends) {
682 if (end.coeff != 1)
return {};
683 end_vars.push_back(end.var);
686 std::vector<FullIntegerPrecedence> output;
689 for (
const auto& p : output) {
691 if (p.indices.size() != ends.size())
continue;
696 for (
int i = 0;
i < p.indices.size(); ++
i) {
706 std::min(min_delta, p.offsets[
i] - ends[p.indices[
i]].constant);
708 VLOG(2) <<
"Makespan detected >= ends + " << min_delta;
723 std::vector<IntervalVariable> intervals =
724 mapping->
Intervals(ct.no_overlap().intervals());
725 const IntegerValue one(1);
726 std::vector<AffineExpression> demands(intervals.size(), one);
729 std::optional<AffineExpression> makespan;
730 const std::optional<int> makespan_index =
732 if (makespan_index.has_value()) {
733 makespan = repository->
Start(intervals[makespan_index.value()]);
735 intervals.erase(intervals.begin() + makespan_index.value());
743 if (!makespan.has_value()) {
744 makespan = DetectMakespanFromPrecedences(*helper, model);
749 if (model->
GetOrCreate<SatParameters>()->linearization_level() > 1) {
759 std::vector<IntervalVariable> intervals =
760 mapping->
Intervals(ct.cumulative().intervals());
761 std::vector<AffineExpression> demands =
762 mapping->Affines(ct.cumulative().demands());
763 const AffineExpression capacity = mapping->Affine(ct.cumulative().capacity());
764 const std::optional<int> makespan_index =
766 std::optional<AffineExpression> makespan;
768 if (makespan_index.has_value()) {
770 makespan = repository->
Start(intervals[makespan_index.value()]);
771 demands.erase(demands.begin() + makespan_index.value());
772 intervals.erase(intervals.begin() + makespan_index.value());
781 if (!makespan.has_value()) {
782 makespan = DetectMakespanFromPrecedences(*helper, model);
788 if (model->
GetOrCreate<SatParameters>()->linearization_level() > 1) {
800 const std::optional<AffineExpression>& makespan,
802 const int num_intervals = helper->
NumTasks();
807 int num_variable_energies = 0;
808 int num_optionals = 0;
809 int64_t sizes_gcd = 0;
810 int64_t demands_gcd = 0;
811 int64_t num_active_intervals = 0;
813 for (
int index = 0; index < num_intervals; ++index) {
814 if (helper->
IsAbsent(index))
continue;
820 if (demands_helper->
EnergyMin(index) > 0) {
828 num_variable_energies++;
830 if (sizes_gcd != 1) {
832 sizes_gcd = std::gcd(helper->
SizeMin(index).value(), sizes_gcd);
837 if (demands_gcd != 1) {
840 std::gcd(demands_helper->
DemandMin(index).value(), demands_gcd);
845 num_active_intervals++;
846 min_of_starts = std::min(min_of_starts, helper->
StartMin(index));
847 max_of_ends = std::max(max_of_ends, helper->
EndMax(index));
850 VLOG(2) <<
"Span [" << min_of_starts <<
".." << max_of_ends <<
"] with "
851 << num_optionals <<
" optional intervals, and "
852 << num_variable_energies <<
" variable energy tasks out of "
853 << num_active_intervals <<
"/" << num_intervals <<
" intervals"
854 << (makespan.has_value() ?
", and 1 makespan" :
"")
855 <<
" sizes_gcd: " << sizes_gcd <<
" demands_gcd: " << demands_gcd;
858 if (num_active_intervals == 0)
return;
862 if (num_variable_energies + num_optionals == 0 && sizes_gcd == 1 &&
868 if (sizes_gcd != 1 && !makespan.has_value()) {
869 VLOG(2) <<
"Cumulative relaxation: sizes_gcd = " << sizes_gcd
870 <<
", demands_gcd = " << demands_gcd
871 <<
", no makespan, capacity is " << capacity.
DebugString();
874 if (!integer_trail->
IsFixed(capacity)) demands_gcd = 1;
876 for (
int index = 0; index < num_intervals; ++index) {
877 if (helper->
IsAbsent(index))
continue;
878 if (helper->
SizeMax(index) == 0 ||
884 const IntegerValue energy_min = demands_helper->
EnergyMin(index);
885 if (energy_min == 0)
continue;
886 DCHECK_EQ(energy_min % (sizes_gcd * demands_gcd), 0);
888 energy_min / sizes_gcd / demands_gcd)) {
893 std::vector<LiteralValueValue> product =
895 if (!product.empty()) {
899 DCHECK_EQ(entry.left_value % sizes_gcd, 0);
900 entry.left_value /= sizes_gcd;
901 DCHECK_EQ(entry.right_value % demands_gcd, 0);
902 entry.right_value /= demands_gcd;
907 const IntegerValue local_size =
909 DCHECK_EQ(local_size % sizes_gcd, 0);
910 if (demands_gcd == 1) {
912 local_size / sizes_gcd);
914 const IntegerValue local_demand =
916 DCHECK_EQ(local_demand % demands_gcd, 0);
917 lc.
AddConstant(local_size * local_demand / sizes_gcd / demands_gcd);
924 if (integer_trail->
IsFixed(capacity)) {
925 const IntegerValue span = max_of_ends - min_of_starts;
926 const IntegerValue fixed_capacity = integer_trail->
FixedValue(capacity);
931 DCHECK_EQ(demands_gcd, 1);
932 lc.
AddTerm(capacity, -(max_of_ends - min_of_starts) / sizes_gcd);
941 for (
int index = 0; index < num_intervals; ++index) {
942 if (helper->
IsAbsent(index))
continue;
944 const IntegerValue energy_min = demands_helper->
EnergyMin(index);
945 if (energy_min == 0)
continue;
950 const std::vector<LiteralValueValue>& product =
952 if (!product.empty()) {
960 demands_helper->
Demands()[index],
971 IntegerValue max_for_overflow_check = std::max(-min_of_starts, max_of_ends);
972 if (makespan.has_value()) {
973 max_for_overflow_check = std::max(
974 max_for_overflow_check, integer_trail->
UpperBound(makespan.value()));
982 makespan.has_value() ? makespan.value() : max_of_ends;
988 absl::Span<const int> component,
Model* model,
991 std::optional<Rectangle> bounding_box;
993 for (
const int b : component) {
996 if (curr_bounding_box.
x_min > curr_bounding_box.
x_max ||
997 curr_bounding_box.
y_min > curr_bounding_box.
y_max) {
1001 if (bounding_box.has_value()) {
1002 bounding_box->GrowToInclude(
1009 if (!bounding_box.has_value()) {
1014 const IntegerValue max_area = bounding_box->CapArea();
1018 for (
const int b : component) {
1024 const std::vector<LiteralValueValue> energy =
1025 product_decomposer->
TryToDecompose(x_size_affine, y_size_affine);
1026 if (!energy.empty()) {
1036 const Literal presence_literal =
1040 const auto& [x_size, y_size] =
1042 const IntegerValue area_min = x_size * y_size;
1051 manager->
Add(std::move(ct));
1057 CHECK(ct.has_no_overlap_2d());
1061 std::vector<IntervalVariable> x_intervals =
1062 mapping->
Intervals(ct.no_overlap_2d().x_intervals());
1063 std::vector<IntervalVariable> y_intervals =
1064 mapping->Intervals(ct.no_overlap_2d().y_intervals());
1068 intervals_repository->GetOrCreate2DHelper(x_intervals, y_intervals);
1072 result.only_run_at_level_zero =
true;
1075 &no_overlap_helper->x_helper(), model, &result.vars,
1078 &no_overlap_helper->y_helper(), model, &result.vars,
1080 result.generate_cuts = [no_overlap_helper, model, product_decomposer,
1081 last_level_zero_bound_change_idx = int64_t{-1}](
1083 if (last_level_zero_bound_change_idx ==
1084 no_overlap_helper->LastLevelZeroChangeIdx()) {
1087 last_level_zero_bound_change_idx =
1088 no_overlap_helper->LastLevelZeroChangeIdx();
1089 for (
const auto& component :
1090 no_overlap_helper->connected_components().AsVectorOfSpan()) {
1092 component, model, no_overlap_helper, manager, product_decomposer);
1105 NegationOf(mapping->GetExprFromProto(ct.lin_max().target()));
1106 for (
int i = 0;
i < ct.lin_max().exprs_size(); ++
i) {
1108 mapping->GetExprFromProto(ct.lin_max().exprs(
i));
1122 IntegerVariable var;
1123 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
1125 CollectAffineExpressionWithSingleVariable(ct, mapping, &var, &affines);
1142 IntegerVariable var;
1143 std::vector<std::pair<IntegerValue, IntegerValue>> affines;
1145 CollectAffineExpressionWithSingleVariable(ct, mapping, &var, &affines);
1152 if (ct.lin_max().target().vars().empty())
return;
1157 target_expr, var, affines,
"AffineMax", model));
1165 absl::Span<const Literal> alternative_literals,
1166 absl::Span<const LinearExpression> exprs,
1168 const int num_exprs = exprs.size();
1172 for (
int i = 0;
i < num_exprs; ++
i) {
1175 local_expr.
vars.push_back(target);
1176 local_expr.
coeffs = exprs[
i].coeffs;
1177 local_expr.
coeffs.push_back(IntegerValue(1));
1180 local_expr.
coeffs, exprs[
i].offset, model);
1187 std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
1188 num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
1192 absl::flat_hash_map<std::pair<int, IntegerVariable>, IntegerValue> cache;
1193 for (
int i = 0;
i < num_exprs; ++
i) {
1194 for (
int j = 0; j < exprs[
i].vars.size(); ++j) {
1195 cache[std::make_pair(
i, exprs[
i].vars[j])] = exprs[
i].coeffs[j];
1198 const auto get_coeff = [&cache](IntegerVariable var,
int index) {
1199 const auto it = cache.find(std::make_pair(index, var));
1200 if (it == cache.end())
return IntegerValue(0);
1205 std::vector<IntegerVariable> active_vars;
1206 for (
int i = 0;
i + 1 < num_exprs; ++
i) {
1207 for (
int j =
i + 1; j < num_exprs; ++j) {
1208 active_vars = exprs[
i].vars;
1209 active_vars.insert(active_vars.end(), exprs[j].vars.begin(),
1210 exprs[j].vars.end());
1212 for (
const IntegerVariable x_var : active_vars) {
1213 const IntegerValue diff = get_coeff(x_var, j) - get_coeff(x_var,
i);
1214 if (diff == 0)
continue;
1218 sum_of_max_corner_diff[
i][j] += std::max(diff * lb, diff * ub);
1219 sum_of_max_corner_diff[j][
i] += std::max(-diff * lb, -diff * ub);
1224 for (
int i = 0;
i < num_exprs; ++
i) {
1226 lc.
AddTerm(target, IntegerValue(1));
1227 for (
int j = 0; j < exprs[
i].vars.size(); ++j) {
1228 lc.
AddTerm(exprs[
i].vars[j], -exprs[
i].coeffs[j]);
1230 for (
int j = 0; j < num_exprs; ++j) {
1232 -exprs[j].offset - sum_of_max_corner_diff[
i][j]));
1239 bool linearize_enforced_constraints,
1252 const IntegerValue rhs_domain_min = IntegerValue(ct.linear().domain(0));
1253 const IntegerValue rhs_domain_max =
1254 IntegerValue(ct.linear().domain(ct.linear().domain_size() - 1));
1255 if (rhs_domain_min == std::numeric_limits<int64_t>::min() &&
1256 rhs_domain_max == std::numeric_limits<int64_t>::max())
1261 for (
int i = 0;
i < ct.linear().vars_size();
i++) {
1262 const int ref = ct.linear().vars(
i);
1263 const int64_t coeff = ct.linear().coeffs(
i);
1264 lc.
AddTerm(mapping->Integer(ref), IntegerValue(coeff));
1271 if (!linearize_enforced_constraints)
return;
1279 if (!mapping->IsHalfEncodingConstraint(&ct) && ct.linear().vars_size() <= 1 &&
1280 ct.enforcement_literal().size() <= 1) {
1284 std::vector<Literal> enforcing_literals;
1285 enforcing_literals.reserve(ct.enforcement_literal_size());
1286 for (
const int enforcement_ref : ct.enforcement_literal()) {
1287 enforcing_literals.push_back(mapping->Literal(enforcement_ref));
1291 std::vector<std::pair<int, int64_t>> bool_terms;
1292 IntegerValue min_activity(0);
1293 IntegerValue max_activity(0);
1295 for (
int i = 0;
i < ct.linear().vars_size();
i++) {
1296 const int ref = ct.linear().vars(
i);
1297 const IntegerValue coeff(ct.linear().coeffs(
i));
1298 const IntegerVariable int_var = mapping->Integer(ref);
1303 const IntegerValue lb = integer_trail->LowerBound(int_var);
1304 const IntegerValue ub = integer_trail->UpperBound(int_var);
1305 if (lb == 0 && ub == 1 && activity_helper !=
nullptr) {
1306 bool_terms.push_back({ref, coeff.value()});
1309 min_activity += coeff * lb;
1310 max_activity += coeff * ub;
1312 min_activity += coeff * ub;
1313 max_activity += coeff * lb;
1317 if (activity_helper !=
nullptr) {
1324 if (rhs_domain_min > min_activity) {
1329 const IntegerValue term =
CapSubI(rhs_domain_min, min_activity);
1331 for (
const Literal& literal : enforcing_literals) {
1334 for (
int i = 0;
i < ct.linear().vars_size();
i++) {
1335 const int ref = ct.linear().vars(
i);
1336 const IntegerValue coeff(ct.linear().coeffs(
i));
1337 const IntegerVariable int_var = mapping->Integer(ref);
1345 if (rhs_domain_max < max_activity) {
1350 const IntegerValue term =
CapSubI(rhs_domain_max, max_activity);
1352 for (
const Literal& literal : enforcing_literals) {
1355 for (
int i = 0;
i < ct.linear().vars_size();
i++) {
1356 const int ref = ct.linear().vars(
i);
1357 const IntegerValue coeff(ct.linear().coeffs(
i));
1358 const IntegerVariable int_var = mapping->Integer(ref);
1380 const ConstraintProto& ct,
1381 int linearization_level,
Model* model,
1385 DCHECK_GT(linearization_level, 0);
1388 switch (ct.constraint_case()) {
1389 case ConstraintProto::ConstraintCase::kBoolOr: {
1390 if (linearization_level > 1) {
1395 case ConstraintProto::ConstraintCase::kBoolAnd: {
1396 if (linearization_level > 1) {
1401 case ConstraintProto::ConstraintCase::kAtMostOne: {
1405 case ConstraintProto::ConstraintCase::kExactlyOne: {
1409 case ConstraintProto::ConstraintCase::kIntProd: {
1410 const LinearArgumentProto& int_prod = ct.int_prod();
1411 if (int_prod.exprs_size() == 2 &&
1413 int_prod.exprs(1))) {
1422 case ConstraintProto::ConstraintCase::kLinMax: {
1424 const bool is_affine_max =
1426 if (is_affine_max) {
1431 if (linearization_level > 1) {
1432 if (is_affine_max) {
1434 }
else if (ct.lin_max().exprs().size() < 100) {
1440 case ConstraintProto::ConstraintCase::kAllDiff: {
1445 case ConstraintProto::ConstraintCase::kLinear: {
1447 ct, linearization_level > 1, model,
1448 relaxation, activity_helper);
1451 case ConstraintProto::ConstraintCase::kCircuit: {
1453 if (linearization_level > 1) {
1458 case ConstraintProto::ConstraintCase::kRoutes: {
1460 if (linearization_level > 1) {
1465 case ConstraintProto::ConstraintCase::kNoOverlap: {
1469 case ConstraintProto::ConstraintCase::kCumulative: {
1473 case ConstraintProto::ConstraintCase::kNoOverlap2D: {
1480 if (linearization_level > 1) {
1496 LOG(INFO) <<
"Possible overflow in linearization of: "
1497 << google::protobuf::ShortFormat(ct);
1508 if (ct.int_prod().exprs_size() != 2)
return;
1517 IntegerValue x_lb = integer_trail->
LowerBound(x);
1518 IntegerValue x_ub = integer_trail->
UpperBound(x);
1519 IntegerValue y_lb = integer_trail->
LowerBound(y);
1520 IntegerValue y_ub = integer_trail->
UpperBound(y);
1523 if (x_lb < 0 && x_ub > 0)
return;
1524 if (y_lb < 0 && y_ub > 0)
return;
1538 z, x, y, linearization_level, m));
1550 IntegerValue x_lb = integer_trail->LowerBound(x);
1551 IntegerValue x_ub = integer_trail->UpperBound(x);
1553 if (x_lb == x_ub)
return;
1556 if (x_lb < 0 && x_ub > 0)
return;
1561 const IntegerValue tmp = x_ub;
1567 if (x_ub > (int64_t{1} << 31))
return;
1576 if (x_lb + 1 < x_ub) {
1592 const IntegerValue x_lb = integer_trail->LowerBound(x);
1593 const IntegerValue x_ub = integer_trail->UpperBound(x);
1596 if (x_lb < 0 && x_ub > 0)
return;
1608 int linearization_level,
Model* m,
1613 const int num_exprs = ct.all_diff().exprs_size();
1615 const std::vector<AffineExpression> exprs =
1616 mapping->Affines(ct.all_diff().exprs());
1622 if (integer_trail->IsFixed(expr)) {
1623 union_of_domains = union_of_domains.
UnionWith(
1624 Domain(integer_trail->FixedValue(expr).value()));
1626 union_of_domains = union_of_domains.
UnionWith(
1627 integer_trail->InitialVariableDomain(expr.var)
1628 .MultiplicationBy(expr.coeff.value())
1629 .AdditionWith(
Domain(expr.constant.value())));
1633 if (union_of_domains.
Size() == num_exprs) {
1635 int64_t sum_of_values = 0;
1636 for (
const int64_t v : union_of_domains.
Values()) {
1644 }
else if (num_exprs <=
1645 m->
GetOrCreate<SatParameters>()->max_all_diff_cut_size() &&
1646 linearization_level > 1) {
1655 if (intervals_repository->
IsAbsent(interval)) {
1660 if (!intervals_repository->
IsPresent(interval)) {
1665 if (intervals_repository->
MinSize(interval) !=
1666 intervals_repository->
MaxSize(interval)) {
1676 const std::optional<AffineExpression>& makespan,
1679 helper, demands_helper, capacity, m));
1684 helper, demands_helper, capacity, m));
1688 bool has_variable_part =
false;
1692 has_variable_part =
true;
1697 has_variable_part =
true;
1701 if (has_variable_part || !integer_trail->
IsFixed(capacity)) {
1703 helper, demands_helper, capacity, makespan, m));
1708 const std::optional<AffineExpression>& makespan,
1716 bool has_variable_or_optional_part =
false;
1720 has_variable_or_optional_part =
true;
1724 if (has_variable_or_optional_part) {
1735 std::vector<IntervalVariable> x_intervals =
1736 mapping->
Intervals(ct.no_overlap_2d().x_intervals());
1737 std::vector<IntervalVariable> y_intervals =
1738 mapping->Intervals(ct.no_overlap_2d().y_intervals());
1749 bool has_variable_part =
false;
1750 for (
int i = 0;
i < x_intervals.size(); ++
i) {
1752 if (intervals_repository->
IsAbsent(x_intervals[
i]) ||
1753 intervals_repository->
IsAbsent(y_intervals[
i])) {
1758 if (!intervals_repository->
IsPresent(x_intervals[
i]) ||
1759 !intervals_repository->
IsPresent(y_intervals[
i])) {
1760 has_variable_part =
true;
1765 if (intervals_repository->
MinSize(x_intervals[
i]) !=
1766 intervals_repository->
MaxSize(x_intervals[
i]) ||
1767 intervals_repository->
MinSize(y_intervals[
i]) !=
1768 intervals_repository->
MaxSize(y_intervals[
i])) {
1769 has_variable_part =
true;
1774 if (!has_variable_part)
return;
1782 if (!m->
GetOrCreate<SatParameters>()->add_lin_max_cuts())
return;
1787 if (ct.lin_max().target().vars_size() != 1)
return;
1788 if (ct.lin_max().target().coeffs(0) != 1)
return;
1789 if (ct.lin_max().target().offset() != 0)
return;
1791 const IntegerVariable target =
1792 mapping->
Integer(ct.lin_max().target().vars(0));
1793 std::vector<LinearExpression> exprs;
1794 exprs.reserve(ct.lin_max().exprs_size());
1795 for (
int i = 0;
i < ct.lin_max().exprs_size(); ++
i) {
1802 const std::vector<Literal> alternative_literals =
1812 std::vector<IntegerVariable> z_vars;
1814 for (
const Literal lit : alternative_literals) {
1815 z_vars.push_back(encoder->GetLiteralView(lit));
1834 int num_exactly_one_elements = 0;
1835 for (
const IntegerVariable var :
1836 element_encodings->GetElementEncodedVariables()) {
1837 for (
const auto& [index, literal_value_list] :
1838 element_encodings->Get(var)) {
1840 for (
const auto& literal_value : literal_value_list) {
1841 min_value = std::min(min_value, literal_value.value);
1845 builder.
AddTerm(var, IntegerValue(-1));
1846 for (
const auto& [value, literal] : literal_value_list) {
1847 const IntegerValue delta_min = value - min_value;
1848 if (delta_min != 0) {
1855 ++num_exactly_one_elements;
1863 if (num_exactly_one_elements != 0) {
1866 "[ElementLinearRelaxation]"
1867 " #from_exactly_one:",
1868 num_exactly_one_elements);
1875 const SatParameters& params = *m->
GetOrCreate<SatParameters>();
1879 if (params.linearization_level() > 1) {
1880 activity_bound_helper.AddAllAtMostOnes(model_proto);
1884 for (
const auto& ct : model_proto.constraints()) {
1886 &relaxation, &activity_bound_helper);
1890 int num_loose_equality_encoding_relaxations = 0;
1891 int num_tight_equality_encoding_relaxations = 0;
1892 int num_inequality_encoding_relaxations = 0;
1894 for (
int i = 0;
i < model_proto.variables_size(); ++
i) {
1895 if (mapping->IsBoolean(
i))
continue;
1897 const IntegerVariable var = mapping->Integer(
i);
1902 var, *m, &relaxation, &num_tight_equality_encoding_relaxations,
1903 &num_loose_equality_encoding_relaxations);
1918 ++num_inequality_encoding_relaxations;
1924 if (params.linearization_level() >= 2) {
1936 if (num_tight_equality_encoding_relaxations != 0 ||
1937 num_loose_equality_encoding_relaxations != 0 ||
1938 num_inequality_encoding_relaxations != 0) {
1940 "[EncodingLinearRelaxation]"
1941 " #tight_equality:",
1942 num_tight_equality_encoding_relaxations,
1943 " #loose_equality:", num_loose_equality_encoding_relaxations,
1944 " #inequality:", num_inequality_encoding_relaxations);
1949 "[LinearRelaxationBeforeCliqueExpansion]"
1960 for (
const std::vector<Literal>& at_most_one : relaxation.
at_most_ones) {
1961 if (at_most_one.empty())
continue;
1964 for (
const Literal literal : at_most_one) {
1967 const bool unused ABSL_ATTRIBUTE_UNUSED =
1984 if (lc.
lb > 0 || lc.
ub < 0) {
2019 "[FinalLinearRelaxation]"
DomainIteratorBeginEnd Values() const &
Domain UnionWith(const Domain &domain) const
static IntegralType FloorOfRatio(IntegralType numerator, IntegralType denominator)
int64_t ComputeMaxActivity(absl::Span< const std::pair< int, int64_t > > terms, std::vector< std::array< int64_t, 2 > > *conditional=nullptr)
int64_t ComputeMinActivity(absl::Span< const std::pair< int, int64_t > > terms, std::vector< std::array< int64_t, 2 > > *conditional=nullptr)
std::vector< absl::Span< const int > > PartitionLiteralsIntoAmo(absl::Span< const int > literals)
Similar algo as above for this simpler case.
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
std::vector< sat::Literal > Literals(const ProtoIndices &indices) const
IntegerVariable Integer(int ref) const
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue FixedValue(IntegerVariable i) const
Checks that the variable is fixed and returns its value.
bool IsFixed(IntegerVariable i) const
Checks if the variable is fixed.
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit)
SchedulingDemandHelper * GetOrCreateDemandHelper(SchedulingConstraintHelper *helper, absl::Span< const AffineExpression > demands)
AffineExpression Start(IntervalVariable i) const
bool IsAbsent(IntervalVariable i) const
IntegerValue MaxSize(IntervalVariable i) const
Return the maximum size of the given IntervalVariable.
IntegerValue MinSize(IntervalVariable i) const
Return the minimum size of the given IntervalVariable.
SchedulingConstraintHelper * GetOrCreateHelper(const std::vector< IntervalVariable > &variables, bool register_as_disjunctive_helper=false)
NoOverlap2DConstraintHelper * GetOrCreate2DHelper(const std::vector< IntervalVariable > &x_variables, const std::vector< IntervalVariable > &y_variables)
bool IsPresent(IntervalVariable i) const
void AddQuadraticLowerBound(AffineExpression left, AffineExpression right, IntegerTrail *integer_trail, bool *is_quadratic=nullptr)
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff=IntegerValue(1))
void AddTerm(IntegerVariable var, IntegerValue coeff)
void AddLinearExpression(const LinearExpression &expr)
void AddConstant(IntegerValue value)
Adds the corresponding term to the current linear expression.
void Clear()
Clears all added terms and constants. Keeps the original bounds.
LinearConstraint BuildConstraint(IntegerValue lb, IntegerValue ub)
ABSL_MUST_USE_RESULT bool AddDecomposedProduct(absl::Span< const LiteralValueValue > product)
ConstraintIndex Add(LinearConstraint ct, bool *added=nullptr, bool *folded=nullptr)
void RegisterWith(GenericLiteralWatcher *watcher)
Literal(int signed_value)
T Add(std::function< T(Model *)> f)
T Get(std::function< T(const Model &)> f) const
Similar to Add() but this is const.
SchedulingConstraintHelper & y_helper() const
Rectangle GetLevelZeroBoundingRectangle(int index) const
bool IsPresent(int index) const
std::pair< IntegerValue, IntegerValue > GetLevelZeroBoxSizesMin(int index) const
SchedulingConstraintHelper & x_helper() const
void ComputeFullPrecedences(absl::Span< const IntegerVariable > vars, std::vector< FullIntegerPrecedence > *output)
Helper class to express a product as a linear constraint.
std::vector< LiteralValueValue > TryToDecompose(const AffineExpression &left, const AffineExpression &right)
void NotifyThatModelIsUnsat()
int CurrentDecisionLevel() const
ABSL_MUST_USE_RESULT bool FinishPropagation()
bool SizeIsFixed(int t) const
int NumTasks() const
Returns the number of task.
absl::Span< const AffineExpression > Sizes() const
bool IsPresent(int t) const
Literal PresenceLiteral(int index) const
IntegerValue SizeMax(int t) const
IntegerValue StartMin(int t) const
IntegerValue SizeMin(int t) const
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
IntegerValue EndMax(int t) const
bool IsAbsent(int t) const
bool IsOptional(int t) const
bool DemandIsFixed(int t) const
bool CacheAllEnergyValues()
const std::vector< std::vector< LiteralValueValue > > & DecomposedEnergies() const
IntegerValue DemandMax(int t) const
const std::vector< AffineExpression > & Demands() const
IntegerValue DemandMin(int t) const
IntegerValue EnergyMin(int t) const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
std::vector< typename Map::mapped_type > Values(const Map &map, const Keys &keys)
void AppendNoOverlapRelaxationAndCutGenerator(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendCumulativeRelaxationAndCutGenerator(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
CutGenerator CreateCumulativeCompletionTimeCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, Model *model)
void AddSquareCutGenerator(const ConstraintProto &ct, int linearization_level, Model *m, LinearRelaxation *relaxation)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void AppendExactlyOneRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
bool BuildMaxAffineUpConstraint(const LinearExpression &target, IntegerVariable var, absl::Span< const std::pair< IntegerValue, IntegerValue > > affines, Model *model, LinearConstraintBuilder *builder)
std::optional< int > DetectMakespan(absl::Span< const IntervalVariable > intervals, absl::Span< const AffineExpression > demands, const AffineExpression &capacity, Model *model)
void AddCumulativeCutGenerator(const AffineExpression &capacity, SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const std::optional< AffineExpression > &makespan, Model *m, LinearRelaxation *relaxation)
void AppendLinMaxRelaxationPart2(IntegerVariable target, absl::Span< const Literal > alternative_literals, absl::Span< const LinearExpression > exprs, Model *model, LinearRelaxation *relaxation)
void AppendRoutesRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
CutGenerator CreatePositiveMultiplicationCutGenerator(AffineExpression z, AffineExpression x, AffineExpression y, int linearization_level, Model *model)
A cut generator for z = x * y (x and y >= 0).
CutGenerator CreateStronglyConnectedGraphCutGenerator(int num_nodes, absl::Span< const int > tails, absl::Span< const int > heads, absl::Span< const Literal > literals, Model *model)
bool ProdOverflow(IntegerValue t, IntegerValue value)
CutGenerator CreateNoOverlap2dEnergyCutGenerator(NoOverlap2DConstraintHelper *helper, Model *model)
const LiteralIndex kNoLiteralIndex(-1)
void AddMaxAffineCutGenerator(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AddCircuitCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
LinearConstraint ComputeHyperplanBelowSquare(AffineExpression x, AffineExpression square, IntegerValue x_value, Model *model)
CutGenerator CreateCumulativePrecedenceCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, Model *model)
LinearRelaxation ComputeLinearRelaxation(const CpModelProto &model_proto, Model *m)
Builds the linear relaxation of a CpModelProto.
bool HasEnforcementLiteral(const ConstraintProto &ct)
Small utility functions to deal with half-reified constraints.
void AppendLinearConstraintRelaxation(const ConstraintProto &ct, bool linearize_enforced_constraints, Model *model, LinearRelaxation *relaxation, ActivityBoundHelper *activity_helper)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Returns the vector of the negated variables.
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
void AddIntProdCutGenerator(const ConstraintProto &ct, int linearization_level, Model *m, LinearRelaxation *relaxation)
Cut generators.
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
void AddRoutesCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
CutGenerator CreateCumulativeEnergyCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, const std::optional< AffineExpression > &makespan, Model *model)
const IntegerVariable kNoIntegerVariable(-1)
CutGenerator CreateCVRPCutGenerator(int num_nodes, absl::Span< const int > tails, absl::Span< const int > heads, absl::Span< const Literal > literals, absl::Span< const int64_t > demands, int64_t capacity, Model *model)
bool PossibleOverflow(const IntegerTrail &integer_trail, const LinearConstraint &constraint)
CutGenerator CreateLinMaxCutGenerator(const IntegerVariable target, absl::Span< const LinearExpression > exprs, absl::Span< const IntegerVariable > z_vars, Model *model)
void AddIntegerVariableFromIntervals(const SchedulingConstraintHelper *helper, Model *model, std::vector< IntegerVariable > *vars, int mask)
CutGenerator CreateAllDifferentCutGenerator(absl::Span< const AffineExpression > exprs, Model *model)
void AddCumulativeRelaxation(const AffineExpression &capacity, SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const std::optional< AffineExpression > &makespan, Model *model, LinearRelaxation *relaxation)
Scheduling relaxations and cut generators.
CutGenerator CreateSquareCutGenerator(AffineExpression y, AffineExpression x, int linearization_level, Model *model)
void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
void TryToLinearizeConstraint(const CpModelProto &, const ConstraintProto &ct, int linearization_level, Model *model, LinearRelaxation *relaxation, ActivityBoundHelper *activity_helper)
Adds linearization of different types of constraints.
IntegerVariable PositiveVariable(IntegerVariable i)
CutGenerator CreateCumulativeTimeTableCutGenerator(SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands_helper, const AffineExpression &capacity, Model *model)
int64_t SafeDoubleToInt64(double value)
void AppendLinMaxRelaxationPart1(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
CutGenerator CreateNoOverlapCompletionTimeCutGenerator(SchedulingConstraintHelper *helper, Model *model)
CutGenerator CreateMaxAffineCutGenerator(LinearExpression target, IntegerVariable var, std::vector< std::pair< IntegerValue, IntegerValue > > affines, const std::string cut_name, Model *model)
int ReindexArcs(IntContainer *tails, IntContainer *heads, absl::flat_hash_map< int, int > *mapping_output=nullptr)
void AppendCircuitRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
Routing relaxation and cut generators.
CutGenerator CreateNoOverlap2dCompletionTimeCutGenerator(NoOverlap2DConstraintHelper *helper, Model *model)
void AppendElementEncodingRelaxation(Model *m, LinearRelaxation *relaxation)
LinearConstraint ComputeHyperplanAboveSquare(AffineExpression x, AffineExpression square, IntegerValue x_lb, IntegerValue x_ub, Model *model)
void AppendMaxAffineRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendNoOverlap2dRelaxationForComponent(absl::Span< const int > component, Model *model, NoOverlap2DConstraintHelper *no_overlap_helper, LinearConstraintManager *manager, ProductDecomposer *product_decomposer)
bool ExpressionsContainsOnlyOneVar(const ExpressionList &exprs)
Returns true if there exactly one variable appearing in all the expressions.
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
CutGenerator CreateNoOverlapEnergyCutGenerator(SchedulingConstraintHelper *helper, const std::optional< AffineExpression > &makespan, Model *model)
bool IntervalIsVariable(const IntervalVariable interval, IntervalsRepository *intervals_repository)
void AppendSquareRelaxation(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(SchedulingConstraintHelper *helper, Model *model)
void AddLinMaxCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
std::function< void(Model *)> ExactlyOneConstraint(absl::Span< const Literal > literals)
LinearExpression PositiveVarExpr(const LinearExpression &expr)
Returns the same expression with positive variables.
void AppendBoolAndRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation, ActivityBoundHelper *activity_helper)
void AddAllDiffRelaxationAndCutGenerator(const ConstraintProto &ct, int linearization_level, Model *m, LinearRelaxation *relaxation)
void AppendNoOverlap2dRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
Adds the energetic relaxation sum(areas) <= bounding box area.
PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var)
void AppendAtMostOneRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AddNoOverlapCutGenerator(SchedulingConstraintHelper *helper, const std::optional< AffineExpression > &makespan, Model *m, LinearRelaxation *relaxation)
void AddNoOverlap2dCutGenerator(const ConstraintProto &ct, Model *m, LinearRelaxation *relaxation)
int NegatedRef(int ref)
Small utility functions to deal with negative variable/literal references.
bool VariableIsPositive(IntegerVariable i)
std::vector< Literal > CreateAlternativeLiteralsWithView(int num_literals, Model *model, LinearRelaxation *relaxation)
IntegerValue CapSubI(IntegerValue a, IntegerValue b)
bool LinearExpressionProtosAreEqual(const LinearExpressionProto &a, const LinearExpressionProto &b, int64_t b_scaling)
Returns true iff a == b * b_scaling.
bool AtMinOrMaxInt64I(IntegerValue t)
LinearConstraintPropagator< false > IntegerSumLE
void AppendBoolOrRelaxation(const ConstraintProto &ct, Model *model, LinearRelaxation *relaxation)
void AppendRelaxationForEqualityEncoding(IntegerVariable var, const Model &model, LinearRelaxation *relaxation, int *num_tight, int *num_loose)
In SWIG mode, we don't want anything besides these top-level includes.
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
var * coeff + constant >= bound.
AffineExpression Negated() const
std::string DebugString() const
IntegerLiteral LowerOrEqual(IntegerValue bound) const
var * coeff + constant <= bound.
std::unique_ptr< IntegerValue[]> coeffs
std::unique_ptr< IntegerVariable[]> vars
std::vector< IntegerVariable > vars
std::vector< IntegerValue > coeffs
std::vector< CutGenerator > cut_generators
std::vector< std::vector< Literal > > at_most_ones
std::vector< LinearConstraint > linear_constraints
#define SOLVER_LOG(logger,...)