45const double kMinCutViolation = 1e-4;
48double GetLiteralLpValue(
51 const IntegerEncoder* encoder) {
52 const IntegerVariable direct_view = encoder->GetLiteralView(lit);
54 return lp_values[direct_view];
56 const IntegerVariable opposite_view = encoder->GetLiteralView(lit.Negated());
58 return 1.0 - lp_values[opposite_view];
61void AddIntegerVariableFromIntervals(SchedulingConstraintHelper* helper,
63 std::vector<IntegerVariable>* vars) {
64 IntegerEncoder* encoder =
model->GetOrCreate<IntegerEncoder>();
65 for (
int t = 0; t < helper->NumTasks(); ++t) {
67 vars->push_back(helper->Starts()[t].var);
70 vars->push_back(helper->Sizes()[t].var);
73 vars->push_back(helper->Ends()[t].var);
75 if (helper->IsOptional(t) && !helper->IsAbsent(t) &&
76 !helper->IsPresent(t)) {
77 const Literal l = helper->PresenceLiteral(t);
82 const IntegerVariable direct_view = encoder->GetLiteralView(l);
84 vars->push_back(direct_view);
86 vars->push_back(encoder->GetLiteralView(l.Negated()));
97 LinearConstraintManager*)>
100 const std::vector<AffineExpression>& demands,
101 const std::vector<LinearExpression>& energies,
107 return [
capacity, demands, energies, trail, integer_trail, helper,
model,
113 const auto demand_is_fixed = [integer_trail, &demands](
int i) {
114 return demands.empty() || integer_trail->IsFixed(demands[i]);
116 const auto demand_min = [integer_trail, &demands](
int i) {
117 return demands.empty() ? IntegerValue(1)
118 : integer_trail->LowerBound(demands[i]);
120 const auto demand_max = [integer_trail, &demands](
int i) {
121 return demands.empty() ? IntegerValue(1)
122 : integer_trail->UpperBound(demands[i]);
125 std::vector<int> active_intervals;
126 for (
int i = 0; i < helper->
NumTasks(); ++i) {
127 if (!helper->
IsAbsent(i) && demand_max(i) > 0 && helper->
SizeMin(i) > 0) {
128 active_intervals.push_back(i);
132 if (active_intervals.size() < 2)
return true;
134 std::sort(active_intervals.begin(), active_intervals.end(),
135 [helper](
int a,
int b) {
136 return helper->StartMin(a) < helper->StartMin(b) ||
137 (helper->StartMin(a) == helper->StartMin(b) &&
138 helper->EndMax(a) < helper->EndMax(b));
141 const IntegerValue capacity_max = integer_trail->UpperBound(
capacity);
143 for (
int i1 = 0; i1 + 1 < active_intervals.size(); ++i1) {
144 const int start_index = active_intervals[i1];
149 if (helper->
StartMin(start_index) == processed_start) {
152 processed_start = helper->
StartMin(start_index);
157 int end_index_of_max_violation = -1;
158 double max_relative_violation = 1.01;
159 IntegerValue start_of_max_violation(0);
160 IntegerValue end_of_max_violation(0);
161 std::vector<int> lifted_intervals_of_max_violation;
164 double energy_lp = 0.0;
170 std::vector<int> residual_intervals(active_intervals.begin() + i1,
171 active_intervals.end());
174 std::set<int> intervals_not_visited(active_intervals.begin(),
175 active_intervals.end());
177 residual_intervals.begin(), residual_intervals.end(),
178 [&](
int a,
int b) { return helper->EndMax(a) < helper->EndMax(b); });
183 for (
int i2 = 0; i2 < residual_intervals.size(); ++i2) {
184 const int t = residual_intervals[i2];
185 intervals_not_visited.erase(t);
188 energy_lp += energies[t].LpValue(lp_values);
192 ToDouble(demand_min(t)) * helper->
Sizes()[t].LpValue(lp_values);
211 if (i2 + 1 < residual_intervals.size() &&
212 helper->
StartMin(residual_intervals[i2 + 1]) >= min_of_starts &&
213 helper->
EndMax(residual_intervals[i2 + 1]) <= max_of_ends) {
222 std::vector<int> lifted_intervals;
223 std::vector<IntegerValue> lifted_min_overlap;
224 double forced_contrib_lp = 0.0;
225 for (
const int t : intervals_not_visited) {
227 if (helper->
StartMin(t) >= min_of_starts &&
228 helper->
EndMax(t) <= max_of_ends) {
232 const IntegerValue min_overlap =
235 if (min_overlap <= 0)
continue;
237 lifted_intervals.push_back(t);
240 if (demand_is_fixed(t)) {
241 forced_contrib_lp +=
ToDouble(min_overlap * demand_min(t));
245 demands[t].LpValue(lp_values) *
ToDouble(min_overlap);
249 lp_values, encoder) *
250 ToDouble(min_overlap * demand_min(t));
255 const double relative_violation =
256 (energy_lp + forced_contrib_lp) /
257 ToDouble((max_of_ends - min_of_starts) * capacity_max);
258 if (relative_violation > max_relative_violation) {
259 end_index_of_max_violation = i2;
260 max_relative_violation = relative_violation;
261 start_of_max_violation = min_of_starts;
262 end_of_max_violation = max_of_ends;
263 lifted_intervals_of_max_violation = lifted_intervals;
267 if (end_index_of_max_violation == -1)
continue;
270 bool cut_generated =
true;
271 bool has_opt_cuts =
false;
273 bool has_quadratic_cuts =
false;
274 bool use_energy =
false;
280 for (
int i2 = 0; i2 <= end_index_of_max_violation; ++i2) {
281 const int t = residual_intervals[i2];
292 has_quadratic_cuts =
true;
299 if (!helper->
SizeIsFixed(t) || !demand_is_fixed(t)) {
300 has_quadratic_cuts =
true;
303 helper->
SizeMin(t) * demand_min(t))) {
304 cut_generated =
false;
310 for (
int i2 = 0; i2 < lifted_intervals_of_max_violation.size(); ++i2) {
311 const int t = lifted_intervals_of_max_violation[i2];
313 t, start_of_max_violation, end_of_max_violation);
317 if (demand_is_fixed(t)) {
321 cut.
AddTerm(demands[t], min_overlap);
326 min_overlap * demand_min(t))) {
327 cut_generated =
false;
334 std::string full_name = cut_name;
335 if (has_opt_cuts) full_name.append(
"_opt");
336 if (has_quadratic_cuts) full_name.append(
"_quad");
337 if (lifted) full_name.append(
"_lifted");
338 if (use_energy) full_name.append(
"_energy");
340 manager->AddCut(cut.
Build(), full_name, lp_values);
349 const std::vector<AffineExpression>& demands,
IntegerTrail* integer_trail,
352 if (!integer_trail->
IsFixed(demand_expr)) {
353 result->
vars.push_back(demand_expr.var);
362 const std::vector<IntervalVariable>& intervals,
364 const std::vector<AffineExpression>& demands,
365 const std::vector<LinearExpression>& energies,
Model*
model) {
370 model->TakeOwnership(helper);
374 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
391 const std::vector<IntervalVariable>& intervals,
Model*
model) {
396 model->TakeOwnership(helper);
398 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
401 std::vector<LinearExpression> sizes;
402 sizes.reserve(intervals.size());
403 for (
int i = 0; i < intervals.size(); ++i) {
413 "NoOverlapEnergy", helper,
420 const std::vector<IntervalVariable>& intervals,
422 const std::vector<AffineExpression>& demands,
Model*
model) {
427 model->TakeOwnership(helper);
432 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
450 std::vector<Event> events;
453 for (
int i = 0; i < helper->
NumTasks(); ++i) {
462 e1.interval_index = i;
464 e1.demand = demands[i];
470 events.push_back(e1);
471 events.push_back(e2);
477 std::sort(events.begin(), events.end(),
478 [](
const Event i,
const Event j) {
479 if (i.time == j.time) {
480 if (i.positive == j.positive) {
481 return i.interval_index < j.interval_index;
485 return i.time < j.time;
488 std::vector<Event> cut_events;
489 bool added_positive_event =
false;
490 for (
const Event& e : events) {
492 added_positive_event =
true;
493 cut_events.push_back(e);
496 if (added_positive_event && cut_events.size() > 1) {
498 bool cut_generated =
true;
502 for (
const Event& cut_event : cut_events) {
503 if (helper->
IsPresent(cut_event.interval_index)) {
504 cut.
AddTerm(cut_event.demand, IntegerValue(1));
509 if (!cut_generated)
break;
515 manager->AddCut(cut.
Build(),
"CumulativeTimeTable", lp_values);
520 for (
int i = 0; i < cut_events.size(); ++i) {
521 if (cut_events[i].interval_index == e.interval_index) {
524 cut_events[new_size] = cut_events[i];
527 cut_events.resize(new_size);
528 added_positive_event =
false;
547 const std::string& cut_name,
549 std::vector<PrecedenceEvent> events, IntegerValue capacity_max,
551 const int num_events = events.size();
552 if (num_events <= 1)
return;
554 std::sort(events.begin(), events.end(),
556 return e1.start_min < e2.start_min ||
557 (e1.start_min == e2.start_min && e1.end_max < e2.end_max);
560 const double tolerance = 1e-4;
562 for (
int i = 0; i + 1 < num_events; ++i) {
564 for (
int j = i + 1; j < num_events; ++j) {
574 if (interval_1_can_precede_2 && !interval_2_can_precede_1 &&
581 }
else if (interval_2_can_precede_1 && !interval_1_can_precede_2 &&
595 const std::vector<IntervalVariable>& intervals,
597 const std::vector<AffineExpression>& demands,
Model*
model) {
602 model->TakeOwnership(helper);
607 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
619 std::vector<PrecedenceEvent> events;
620 for (
int t = 0; t < helper->
NumTasks(); ++t) {
624 event.start_max = helper->
StartMax(t);
625 event.start = helper->
Starts()[t];
626 event.end_min = helper->
EndMin(t);
627 event.end_max = helper->
EndMax(t);
628 event.end = helper->
Ends()[t];
629 event.demand_min = integer_trail->
LowerBound(demands[t]);
630 events.push_back(event);
633 std::move(events), capacity_max,
model, manager);
640 const std::vector<IntervalVariable>& intervals,
Model*
model) {
645 model->TakeOwnership(helper);
647 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
652 [trail, helper,
model](
657 std::vector<PrecedenceEvent> events;
658 for (
int t = 0; t < helper->
NumTasks(); ++t) {
662 event.start_max = helper->
StartMax(t);
663 event.start = helper->
Starts()[t];
664 event.end_min = helper->
EndMin(t);
665 event.end_max = helper->
EndMax(t);
666 event.end = helper->
Ends()[t];
667 event.demand_min = IntegerValue(1);
668 events.push_back(event);
671 std::move(events), IntegerValue(1),
model,
709 bool use_energy =
false;
716 return absl::StrCat(
"CtEvent(x_end = ", x_end.
DebugString(),
717 ", x_start_min = ", x_start_min.value(),
718 ", x_size_min = ", x_size_min.value(),
719 ", x_lp_end = ", x_lp_end,
720 ", y_start_min = ", y_start_min.value(),
721 ", y_end_max = ", y_end_max.value(),
722 ", energy_min = ", energy_min.value(),
723 ", use_energy = ", use_energy,
", lifted = ", lifted);
740 const std::string& cut_name,
742 std::vector<CtEvent> events,
bool use_lifting,
Model*
model,
747 std::sort(events.begin(), events.end(),
749 return e1.x_start_min < e2.x_start_min;
751 for (
int start = 0; start + 1 < events.size(); ++start) {
754 events[start].x_start_min == events[start - 1].x_start_min) {
758 const IntegerValue sequence_start_min = events[start].x_start_min;
759 std::vector<CtEvent> residual_tasks(events.begin() + start, events.end());
767 for (
int before = 0; before < start; ++before) {
768 if (events[before].x_start_min + events[before].x_size_min >
769 sequence_start_min) {
771 CtEvent event = events[before];
773 const IntegerValue old_size_min =
event.x_size_min;
775 event.x_size_min +
event.x_start_min - sequence_start_min;
776 event.x_start_min = sequence_start_min;
785 event.energy_min =
event.energy_min *
event.x_size_min / old_size_min;
786 residual_tasks.push_back(event);
791 std::sort(residual_tasks.begin(), residual_tasks.end(),
793 return e1.x_lp_end < e2.x_lp_end;
797 double best_efficacy = 0.01;
798 IntegerValue best_min_contrib(0);
799 IntegerValue sum_duration(0);
800 IntegerValue sum_square_duration(0);
801 IntegerValue best_size_divisor(0);
802 double unscaled_lp_contrib = 0;
807 for (
int i = 0; i < residual_tasks.size(); ++i) {
808 const CtEvent&
event = residual_tasks[i];
809 DCHECK_GE(event.x_start_min, sequence_start_min);
810 const IntegerValue
energy =
event.energy_min;
814 current_start_min =
std::min(current_start_min, event.x_start_min);
815 y_start_min =
std::min(y_start_min, event.y_start_min);
816 y_end_max =
std::max(y_end_max, event.y_end_max);
818 const IntegerValue size_divisor = y_end_max - y_start_min;
824 const IntegerValue min_contrib =
825 (sum_duration * sum_duration + sum_square_duration) / 2 +
826 current_start_min * sum_duration * size_divisor;
827 const double efficacy = (
ToDouble(min_contrib) -
828 unscaled_lp_contrib *
ToDouble(size_divisor)) /
829 std::sqrt(
ToDouble(sum_square_duration));
831 if (efficacy > best_efficacy) {
832 best_efficacy = efficacy;
834 best_min_contrib = min_contrib;
835 best_size_divisor = size_divisor;
838 if (best_end != -1) {
840 bool is_lifted =
false;
841 bool use_energy =
false;
842 for (
int i = 0; i <= best_end; ++i) {
843 const CtEvent&
event = residual_tasks[i];
844 is_lifted |=
event.
lifted;
845 use_energy |=
event.use_energy;
846 cut.
AddTerm(event.x_end, event.energy_min * best_size_divisor);
848 std::string full_name = cut_name;
849 if (is_lifted) full_name.append(
"_lifted");
850 if (use_energy) full_name.append(
"_energy");
851 top_n_cuts.
AddCut(cut.
Build(), full_name, lp_values);
858 const std::vector<IntervalVariable>& intervals,
Model*
model) {
863 model->TakeOwnership(helper);
865 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
870 [trail, helper,
model](
875 auto generate_cuts = [&lp_values,
model, manager,
876 helper](
const std::string& cut_name) {
877 std::vector<CtEvent> events;
885 event.x_size_min = size_min;
886 event.x_end = end_expr;
887 event.x_lp_end = end_expr.
LpValue(lp_values);
888 event.y_start_min = IntegerValue(0);
889 event.y_end_max = IntegerValue(1);
890 event.energy_min = size_min;
891 events.push_back(event);
895 false,
model, manager);
898 generate_cuts(
"NoOverlapCompletionTime");
900 generate_cuts(
"NoOverlapCompletionTimeMirror");
907 const std::vector<IntervalVariable>& intervals,
909 const std::vector<AffineExpression>& demands,
910 const std::vector<LinearExpression>& energies,
Model*
model) {
915 model->TakeOwnership(helper);
920 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
926 [trail, integer_trail, helper, demands, energies,
capacity,
model](
932 auto generate_cuts = [&lp_values,
model, manager, helper, capacity_max,
933 integer_trail, &demands,
934 &energies](
const std::string& cut_name) {
935 std::vector<CtEvent> events;
937 if (!helper->IsPresent(
index))
continue;
938 if (helper->SizeMin(
index) > 0 &&
939 integer_trail->LowerBound(demands[
index]) > 0) {
941 const IntegerValue size_min = helper->SizeMin(
index);
942 const IntegerValue demand_min =
943 integer_trail->LowerBound(demands[
index]);
947 event.x_size_min = size_min;
948 event.x_end = end_expr;
949 event.x_lp_end = end_expr.
LpValue(lp_values);
950 event.y_start_min = IntegerValue(0);
951 event.y_end_max = IntegerValue(capacity_max);
952 event.energy_min = size_min * demand_min;
956 const IntegerValue linearized_energy =
959 event.energy_min = linearized_energy;
960 event.use_energy =
true;
963 events.push_back(event);
967 true,
model, manager);
969 if (!helper->SynchronizeAndSetTimeDirection(
true))
return false;
970 generate_cuts(
"CumulativeCompletionTime");
971 if (!helper->SynchronizeAndSetTimeDirection(
false))
return false;
972 generate_cuts(
"CumulativeCompletionTimeMirror");
979 const std::vector<IntervalVariable>& x_intervals,
980 const std::vector<IntervalVariable>& y_intervals,
Model*
model) {
985 model->TakeOwnership(x_helper);
989 model->TakeOwnership(y_helper);
990 AddIntegerVariableFromIntervals(x_helper,
model, &result.
vars);
991 AddIntegerVariableFromIntervals(y_helper,
model, &result.
vars);
996 [trail, x_helper, y_helper,
model](
1004 const int num_boxes = x_helper->
NumTasks();
1005 std::vector<int> active_boxes;
1006 std::vector<IntegerValue> cached_areas(num_boxes);
1007 std::vector<Rectangle> cached_rectangles(num_boxes);
1008 for (
int box = 0; box < num_boxes; ++box) {
1011 cached_areas[box] = x_helper->
SizeMin(box) * y_helper->
SizeMin(box);
1012 if (cached_areas[box] == 0)
continue;
1018 Rectangle& rectangle = cached_rectangles[box];
1024 active_boxes.push_back(box);
1027 if (active_boxes.size() <= 1)
return true;
1029 std::vector<absl::Span<int>> components =
1031 absl::MakeSpan(active_boxes));
1032 for (absl::Span<int> boxes : components) {
1033 if (boxes.size() <= 1)
continue;
1035 auto generate_cuts = [&lp_values,
model, manager, &boxes,
1037 const std::string& cut_name,
1040 std::vector<CtEvent> events;
1042 for (
const int box : boxes) {
1045 event.
x_start_min = x_helper->ShiftedStartMin(box);
1046 event.x_size_min = x_helper->SizeMin(box);
1047 event.x_end = x_end_expr;
1048 event.x_lp_end = x_end_expr.
LpValue(lp_values);
1052 x_helper->SizeMin(box) * y_helper->
SizeMin(box);
1053 events.push_back(event);
1057 true,
model, manager);
1060 if (!x_helper->SynchronizeAndSetTimeDirection(
true))
return false;
1062 generate_cuts(
"NoOverlap2dXCompletionTime", x_helper, y_helper);
1063 generate_cuts(
"NoOverlap2dYCompletionTime", y_helper, x_helper);
1064 if (!x_helper->SynchronizeAndSetTimeDirection(
false))
return false;
1066 generate_cuts(
"NoOverlap2dXCompletionTimeMirror", x_helper, y_helper);
1067 generate_cuts(
"NoOverlap2dYCompletionTimeMirror", y_helper, x_helper);
1078 const std::vector<LinearExpression>& energies, absl::Span<int> boxes,
1082 std::sort(boxes.begin(), boxes.end(), [x_helper](
int a,
int b) {
1083 return x_helper->StartMin(a) < x_helper->StartMin(b) ||
1084 (x_helper->StartMin(a) == x_helper->StartMin(b) &&
1085 x_helper->EndMax(a) < x_helper->EndMax(b));
1088 for (
int i1 = 0; i1 + 1 < boxes.size(); ++i1) {
1091 int end_index_of_max_violation = -1;
1092 double max_relative_violation = 1.01;
1093 IntegerValue x_min_of_max_violation(0);
1094 IntegerValue x_max_of_max_violation(0);
1095 IntegerValue y_min_of_max_violation(0);
1096 IntegerValue y_max_of_max_violation(0);
1099 double energy_lp = 0.0;
1107 std::vector<int> residual_intervals(boxes.begin() + i1, boxes.end());
1108 std::sort(residual_intervals.begin(), residual_intervals.end(),
1110 return x_helper->EndMax(a) < x_helper->EndMax(b);
1116 for (
int i2 = 0; i2 < residual_intervals.size(); ++i2) {
1117 const int t = residual_intervals[i2];
1120 energy_lp += energies[t].LpValue(lp_values);
1122 energy_lp += x_helper->
Sizes()[t].LpValue(lp_values) *
1124 energy_lp += y_helper->
Sizes()[t].LpValue(lp_values) *
1134 energy_lp += GetLiteralLpValue(lit, lp_values, encoder) *
1145 const double relative_violation =
1146 energy_lp /
ToDouble((x_max - x_min) * (y_max - y_min));
1147 if (relative_violation > max_relative_violation) {
1148 end_index_of_max_violation = i2;
1149 max_relative_violation = relative_violation;
1150 x_min_of_max_violation = x_min;
1151 x_max_of_max_violation = x_max;
1152 y_min_of_max_violation = y_min;
1153 y_max_of_max_violation = y_max;
1156 if (end_index_of_max_violation == -1)
return;
1159 bool has_opt_cuts =
false;
1160 bool has_quadratic_cuts =
false;
1161 bool use_energy =
false;
1165 (x_max_of_max_violation - x_min_of_max_violation) *
1166 (y_max_of_max_violation - y_min_of_max_violation));
1169 for (
int i2 = 0; i2 <= end_index_of_max_violation; ++i2) {
1170 const int t = residual_intervals[i2];
1180 has_quadratic_cuts =
true;
1191 has_opt_cuts =
true;
1193 has_quadratic_cuts =
true;
1199 std::string full_name = cut_name;
1200 if (has_opt_cuts) full_name.append(
"_opt");
1201 if (has_quadratic_cuts) full_name.append(
"_quad");
1202 if (use_energy) full_name.append(
"_energy");
1204 manager->
AddCut(cut.
Build(), full_name, lp_values);
1209 const std::vector<IntervalVariable>& x_intervals,
1210 const std::vector<IntervalVariable>& y_intervals,
Model*
model) {
1214 const int num_boxes = x_intervals.size();
1216 std::vector<LinearExpression> energies;
1217 std::vector<AffineExpression> x_sizes;
1218 std::vector<AffineExpression> y_sizes;
1219 for (
int i = 0; i < num_boxes; ++i) {
1220 x_sizes.push_back(intervals_repository->
Size(x_intervals[i]));
1221 y_sizes.push_back(intervals_repository->
Size(y_intervals[i]));
1227 model->TakeOwnership(x_helper);
1231 model->TakeOwnership(y_helper);
1232 AddIntegerVariableFromIntervals(x_helper,
model, &result.
vars);
1233 AddIntegerVariableFromIntervals(y_helper,
model, &result.
vars);
1240 [integer_trail, trail, encoder, x_helper, y_helper,
model, energies](
1248 const int num_boxes = x_helper->
NumTasks();
1249 std::vector<int> active_boxes;
1250 std::vector<Rectangle> cached_rectangles(num_boxes);
1251 for (
int box = 0; box < num_boxes; ++box) {
1265 Rectangle& rectangle = cached_rectangles[box];
1271 active_boxes.push_back(box);
1274 if (active_boxes.size() <= 1)
return true;
1276 std::vector<absl::Span<int>> components =
1278 absl::MakeSpan(active_boxes));
1283 for (absl::Span<int> boxes : components) {
1284 if (boxes.size() <= 1)
continue;
1287 lp_values,
model, integer_trail, encoder, manager, energies,
1288 boxes,
"NoOverlap2dXEnergy", x_helper, y_helper);
1290 lp_values,
model, integer_trail, encoder, manager, energies,
1291 boxes,
"NoOverlap2dYEnergy", y_helper, x_helper);
1297 for (absl::Span<int> boxes : components) {
1298 if (boxes.size() <= 1)
continue;
1301 lp_values,
model, integer_trail, encoder, manager, energies,
1302 boxes,
"NoOverlap2dXEnergyMirror", x_helper, y_helper);
1304 lp_values,
model, integer_trail, encoder, manager, energies,
1305 boxes,
"NoOverlap2dYEnergyMirror", y_helper, x_helper);
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK(condition)
bool IsFixed(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
AffineExpression Size(IntervalVariable i) const
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
void AddConstant(IntegerValue value)
void AddLinearExpression(const LinearExpression &expr)
void AddQuadraticLowerBound(AffineExpression left, AffineExpression right, IntegerTrail *integer_trail)
LinearExpression BuildExpression()
void AddTerm(IntegerVariable var, IntegerValue coeff)
bool AddCut(LinearConstraint ct, std::string type_name, const absl::StrongVector< IntegerVariable, double > &lp_solution, std::string extra_info="")
Class that owns everything related to a particular optimization model.
IntegerValue ShiftedStartMin(int t) const
IntegerValue EndMin(int t) const
const std::vector< AffineExpression > & Starts() const
bool IsPresent(int t) const
IntegerValue ShiftedEndMax(int t) const
bool SizeIsFixed(int t) const
const std::vector< AffineExpression > & Sizes() const
IntegerValue GetMinOverlap(int t, IntegerValue start, IntegerValue end) const
bool IsAbsent(int t) const
IntegerValue EndMax(int t) const
bool IsOptional(int t) const
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
IntegerValue StartMin(int t) const
Literal PresenceLiteral(int index) const
IntegerValue StartMax(int t) const
const std::vector< AffineExpression > & Ends() const
IntegerValue SizeMin(int t) const
void AddCut(LinearConstraint ct, const std::string &name, const absl::StrongVector< IntegerVariable, double > &lp_solution)
void TransferToManager(const absl::StrongVector< IntegerVariable, double > &lp_solution, LinearConstraintManager *manager)
int CurrentDecisionLevel() const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
static double ToDouble(double f)
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 CreateNoOverlap2dEnergyCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
void GeneratePrecedenceCuts(const std::string &cut_name, const absl::StrongVector< IntegerVariable, double > &lp_values, std::vector< PrecedenceEvent > events, IntegerValue capacity_max, Model *model, LinearConstraintManager *manager)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
CutGenerator CreateNoOverlapCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
std::vector< absl::Span< int > > GetOverlappingRectangleComponents(const std::vector< Rectangle > &rectangles, absl::Span< int > active_rectangles)
void LinearizeInnerProduct(const std::vector< AffineExpression > &left, const std::vector< AffineExpression > &right, Model *model, std::vector< LinearExpression > *energies)
const IntegerVariable kNoIntegerVariable(-1)
void AppendVariablesToCumulativeCut(const AffineExpression &capacity, const std::vector< AffineExpression > &demands, IntegerTrail *integer_trail, CutGenerator *result)
CutGenerator CreateCumulativeTimeTableCutGenerator(const std::vector< IntervalVariable > &intervals, const AffineExpression &capacity, const std::vector< AffineExpression > &demands, Model *model)
void GenerateCompletionTimeCuts(const std::string &cut_name, const absl::StrongVector< IntegerVariable, double > &lp_values, std::vector< CtEvent > events, bool use_lifting, Model *model, LinearConstraintManager *manager)
CutGenerator CreateNoOverlap2dCompletionTimeCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
void GenerateNoOverlap2dEnergyCut(const absl::StrongVector< IntegerVariable, double > &lp_values, Model *model, IntegerTrail *integer_trail, IntegerEncoder *encoder, LinearConstraintManager *manager, const std::vector< LinearExpression > &energies, absl::Span< int > boxes, const std::string &cut_name, SchedulingConstraintHelper *x_helper, SchedulingConstraintHelper *y_helper)
bool ProductIsLinearized(const LinearExpression &expr)
std::function< bool(const absl::StrongVector< IntegerVariable, double > &, LinearConstraintManager *)> GenerateCumulativeEnergyCuts(const std::string &cut_name, SchedulingConstraintHelper *helper, const std::vector< AffineExpression > &demands, const std::vector< LinearExpression > &energies, AffineExpression capacity, Model *model)
CutGenerator CreateCumulativeCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, const AffineExpression &capacity, const std::vector< AffineExpression > &demands, const std::vector< LinearExpression > &energies, Model *model)
CutGenerator CreateNoOverlapEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
CutGenerator CreateCumulativePrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, const AffineExpression &capacity, const std::vector< AffineExpression > &demands, Model *model)
double ToDouble(IntegerValue value)
Collection of objects used to extend the Constraint Solver library.
double LpValue(const absl::StrongVector< IntegerVariable, double > &lp_values) const
const std::string DebugString() const
std::string DebugString() const
std::vector< IntegerVariable > vars
std::function< bool(const absl::StrongVector< IntegerVariable, double > &lp_values, LinearConstraintManager *manager)> generate_cuts