26#include "absl/strings/str_cat.h"
27#include "absl/types/span.h"
49const double kMinCutViolation = 1e-4;
52double GetLiteralLpValue(
55 const IntegerEncoder* encoder) {
56 const IntegerVariable direct_view = encoder->GetLiteralView(lit);
58 return lp_values[direct_view];
60 const IntegerVariable opposite_view = encoder->GetLiteralView(lit.Negated());
62 return 1.0 - lp_values[opposite_view];
65void AddIntegerVariableFromIntervals(SchedulingConstraintHelper* helper,
67 std::vector<IntegerVariable>* vars) {
68 IntegerEncoder* encoder =
model->GetOrCreate<IntegerEncoder>();
69 for (
int t = 0; t < helper->NumTasks(); ++t) {
71 vars->push_back(helper->Starts()[t].var);
74 vars->push_back(helper->Sizes()[t].var);
77 vars->push_back(helper->Ends()[t].var);
79 if (helper->IsOptional(t) && !helper->IsAbsent(t) &&
80 !helper->IsPresent(t)) {
81 const Literal l = helper->PresenceLiteral(t);
86 const IntegerVariable direct_view = encoder->GetLiteralView(l);
88 vars->push_back(direct_view);
90 vars->push_back(encoder->GetLiteralView(l.Negated()));
105 IntegerValue
y_min = IntegerValue(0);
106 IntegerValue
y_max = IntegerValue(0);
145 ", energy = ",
energy ?
energy.value().DebugString() :
"{}",
155 const std::string& cut_name,
162 std::sort(events.begin(), events.end(),
164 return std::tie(a.x_start_min, a.y_spread, a.x_end_max) <
165 std::tie(b.x_start_min, b.y_spread, b.x_end_max);
168 const double capacity_lp =
capacity.LpValue(lp_values);
171 double sum_of_all_energies = 0.0;
172 for (
const auto& e : events) {
173 sum_of_all_energies += e.energy_lp;
178 for (
int i1 = 0; i1 + 1 < events.size(); ++i1) {
185 if (!events_are_2d) {
186 if (events[i1].x_start_min == processed_start) {
189 processed_start = events[i1].x_start_min;
195 int max_violation_end_index = -1;
196 double max_relative_violation = 1.0 + kMinCutViolation;
197 IntegerValue max_violation_window_start(0);
198 IntegerValue max_violation_window_end(0);
199 IntegerValue max_violation_y_min(0);
200 IntegerValue max_violation_y_max(0);
201 IntegerValue max_violation_precise_area(0);
202 bool max_violation_use_precise_area =
false;
203 std::vector<EnergyEvent> max_violation_lifted_events;
206 double energy_lp = 0.0;
211 capacity_profile.
Clear();
215 std::vector<EnergyEvent> residual_events(events.begin() + i1, events.end());
216 std::sort(residual_events.begin(), residual_events.end(),
218 return std::tie(a.x_end_max, a.y_spread) <
219 std::tie(b.x_end_max, b.y_spread);
223 for (
int i2 = 0; i2 < residual_events.size(); ++i2) {
238 if (i2 + 1 < residual_events.size() &&
239 residual_events[i2 + 1].x_start_min >= window_min &&
240 residual_events[i2 + 1].x_end_max <= window_max &&
241 residual_events[i2 + 1].y_min >= y_min &&
242 residual_events[i2 + 1].y_max <= y_max) {
247 DCHECK(capacity_lp == 0.0 || y_max == y_min);
256 bool use_precise_area =
false;
257 IntegerValue precise_area(0);
258 double area_lp = 0.0;
260 const IntegerValue bbox_area =
261 (window_max - window_min) * (y_max - y_min);
263 use_precise_area = precise_area < bbox_area;
266 area_lp = capacity_lp *
ToDouble(window_max - window_min);
269 if (area_lp >= sum_of_all_energies) {
282 std::vector<EnergyEvent> lifted_events;
283 double lifted_contrib_lp = 0.0;
288 if (!events_are_2d) {
289 const auto check_lifted_cuts = [&lifted_events, window_min, window_max,
290 y_min, y_max, &lifted_contrib_lp,
298 if (e.
y_min < y_min || e.
y_max > y_max)
return;
306 const IntegerValue min_overlap =
309 if (min_overlap <= 0)
return;
311 lifted_events.push_back(e);
312 double contrib_lp = 0.0;
320 lifted_contrib_lp +=
std::max(contrib_lp, 0.0);
323 for (
int i3 = 0; i3 < i1; ++i3) {
324 check_lifted_cuts(events[i3]);
326 for (
int i3 = i2 + 1; i3 < residual_events.size(); ++i3) {
327 check_lifted_cuts(residual_events[i3]);
332 const double relative_violation =
333 (energy_lp + lifted_contrib_lp) / area_lp;
334 if (relative_violation > max_relative_violation) {
335 max_violation_end_index = i2;
336 max_relative_violation = relative_violation;
337 max_violation_window_start = window_min;
338 max_violation_window_end = window_max;
339 std::swap(max_violation_lifted_events, lifted_events);
340 max_violation_y_min = y_min;
341 max_violation_y_max = y_max;
342 max_violation_precise_area = precise_area;
343 max_violation_use_precise_area = use_precise_area;
347 if (max_violation_end_index == -1)
continue;
350 bool cut_generated =
true;
351 bool has_opt_cuts =
false;
352 bool use_lifted_events =
false;
353 bool has_quadratic_cuts =
false;
354 bool use_energy =
false;
356 DCHECK(capacity_lp == 0.0 || max_violation_y_max == max_violation_y_min);
360 events_are_2d ? max_violation_precise_area : IntegerValue(0));
363 if (!events_are_2d) {
365 max_violation_window_start - max_violation_window_end);
368 for (
int i2 = 0; i2 <= max_violation_end_index; ++i2) {
377 has_quadratic_cuts =
true;
381 const IntegerValue min_energy =
390 cut_generated =
false;
396 for (
const EnergyEvent& e : max_violation_lifted_events) {
397 const IntegerValue min_overlap =
398 e.GetMinOverlap(max_violation_window_start, max_violation_window_end);
400 use_lifted_events =
true;
403 cut.
AddTerm(e.y_size, min_overlap);
407 min_overlap * e.y_size_min)) {
408 cut_generated =
false;
415 std::string full_name = cut_name;
416 if (has_opt_cuts) full_name.append(
"_opt");
417 if (has_quadratic_cuts) full_name.append(
"_quad");
418 if (use_lifted_events) full_name.append(
"_lifted");
419 if (use_energy) full_name.append(
"_energy");
420 if (max_violation_use_precise_area) full_name.append(
"_precise");
421 top_n_cuts.AddCut(cut.
Build(), full_name, lp_values);
424 top_n_cuts.TransferToManager(lp_values, manager);
429 const std::vector<AffineExpression>& demands,
IntegerTrail* integer_trail,
432 if (!integer_trail->
IsFixed(demand_expr)) {
433 result->
vars.push_back(demand_expr.var);
447 return e.
energy.value().LpValue(lp_values);
455 const IntegerValue min_energy =
464 const std::vector<IntervalVariable>& intervals,
466 const std::vector<AffineExpression>& demands,
467 const std::vector<LinearExpression>& energies,
Model*
model) {
472 model->TakeOwnership(helper);
478 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
486 [
capacity, demands, energies, trail, integer_trail, helper,
model,
491 std::vector<EnergyEvent> events;
492 for (
int i = 0; i < helper->
NumTasks(); ++i) {
494 if (integer_trail->LevelZeroUpperBound(demands[i]) == 0 ||
510 e.
y_size_min = integer_trail->LevelZeroLowerBound(demands[i]);
521 false,
model, manager);
529 const std::vector<IntervalVariable>& intervals,
Model*
model) {
536 model->TakeOwnership(helper);
538 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
542 std::vector<LinearExpression> sizes;
543 sizes.reserve(intervals.size());
544 for (
int i = 0; i < intervals.size(); ++i) {
546 builder.
AddTerm(helper->Sizes()[i], IntegerValue(1));
551 [sizes, trail, helper,
model, encoder](
556 std::vector<EnergyEvent> events;
557 for (
int i = 0; i < helper->NumTasks(); ++i) {
558 if (helper->IsAbsent(i))
continue;
559 if (helper->SizeMin(i) == 0) {
568 e.
x_size = helper->Sizes()[i];
569 e.
y_size = IntegerValue(1);
573 if (helper->IsPresent(i)) {
585 IntegerValue(1),
false,
model,
593 const std::vector<LinearExpression>& energies, absl::Span<int> rectangles,
594 const std::string& cut_name,
599 std::vector<EnergyEvent> events;
600 for (
const int rect : rectangles) {
601 if (y_helper->
SizeMax(rect) == 0 || x_helper->
SizeMax(rect) == 0) {
615 e.
energy = energies[rect];
633 if (events.empty())
return;
636 double average_d = 0.0;
637 for (
const auto& e : events) {
638 average_d +=
ToDouble(e.y_min + e.y_max);
640 const double average = average_d / 2.0 /
static_cast<double>(events.size());
641 for (
auto& e : events) {
646 true,
model, manager);
650 const std::vector<IntervalVariable>& x_intervals,
651 const std::vector<IntervalVariable>& y_intervals,
Model*
model) {
655 const int num_rectangles = x_intervals.size();
657 std::vector<LinearExpression> energies;
658 std::vector<AffineExpression> x_sizes;
659 std::vector<AffineExpression> y_sizes;
660 for (
int i = 0; i < num_rectangles; ++i) {
661 x_sizes.push_back(intervals_repository->
Size(x_intervals[i]));
662 y_sizes.push_back(intervals_repository->
Size(y_intervals[i]));
668 model->TakeOwnership(x_helper);
672 model->TakeOwnership(y_helper);
674 AddIntegerVariableFromIntervals(x_helper,
model, &result.
vars);
675 AddIntegerVariableFromIntervals(y_helper,
model, &result.
vars);
683 [integer_trail, trail, encoder, x_helper, y_helper,
model, energies](
691 const int num_rectangles = x_helper->
NumTasks();
692 std::vector<int> active_rectangles;
693 std::vector<Rectangle> cached_rectangles(num_rectangles);
694 for (
int rect = 0; rect < num_rectangles; ++rect) {
708 Rectangle& rectangle = cached_rectangles[rect];
714 active_rectangles.push_back(rect);
717 if (active_rectangles.size() <= 1)
return true;
719 std::vector<absl::Span<int>> components =
721 cached_rectangles, absl::MakeSpan(active_rectangles));
724 for (absl::Span<int> rectangles : components) {
725 if (rectangles.size() <= 1)
continue;
728 energies, rectangles,
"NoOverlap2dXEnergy", lp_values,
model,
729 integer_trail, encoder, manager, x_helper, y_helper);
731 energies, rectangles,
"NoOverlap2dYEnergy", lp_values,
model,
732 integer_trail, encoder, manager, y_helper, x_helper);
741 const std::vector<IntervalVariable>& intervals,
743 const std::vector<AffineExpression>& demands,
Model*
model) {
748 model->TakeOwnership(helper);
753 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
756 struct TimeTableEvent {
771 std::vector<TimeTableEvent> events;
774 for (
int i = 0; i < helper->
NumTasks(); ++i) {
783 e1.interval_index = i;
785 e1.demand = demands[i];
788 TimeTableEvent e2 = e1;
791 events.push_back(e1);
792 events.push_back(e2);
798 std::sort(events.begin(), events.end(),
799 [](
const TimeTableEvent& i,
const TimeTableEvent& j) {
800 if (i.time == j.time) {
801 if (i.positive == j.positive) {
802 return i.interval_index < j.interval_index;
806 return i.time < j.time;
809 std::vector<TimeTableEvent> cut_events;
810 bool added_positive_event =
false;
811 for (
const TimeTableEvent& e : events) {
813 added_positive_event =
true;
814 cut_events.push_back(e);
817 if (added_positive_event && cut_events.size() > 1) {
819 bool cut_generated =
true;
823 for (
const TimeTableEvent& cut_event : cut_events) {
824 if (helper->
IsPresent(cut_event.interval_index)) {
825 cut.
AddTerm(cut_event.demand, IntegerValue(1));
830 if (!cut_generated)
break;
836 manager->AddCut(cut.
Build(),
"CumulativeTimeTable", lp_values);
841 for (
int i = 0; i < cut_events.size(); ++i) {
842 if (cut_events[i].interval_index == e.interval_index) {
845 cut_events[new_size] = cut_events[i];
848 cut_events.resize(new_size);
849 added_positive_event =
false;
868 const std::string& cut_name,
870 std::vector<PrecedenceEvent> events, IntegerValue capacity_max,
872 const int num_events = events.size();
873 if (num_events <= 1)
return;
875 std::sort(events.begin(), events.end(),
877 return e1.start_min < e2.start_min ||
878 (e1.start_min == e2.start_min && e1.end_max < e2.end_max);
881 const double tolerance = 1e-4;
883 for (
int i = 0; i + 1 < num_events; ++i) {
885 for (
int j = i + 1; j < num_events; ++j) {
895 if (interval_1_can_precede_2 && !interval_2_can_precede_1 &&
902 }
else if (interval_2_can_precede_1 && !interval_1_can_precede_2 &&
916 const std::vector<IntervalVariable>& intervals,
918 const std::vector<AffineExpression>& demands,
Model*
model) {
923 model->TakeOwnership(helper);
928 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
940 std::vector<PrecedenceEvent> events;
941 for (
int t = 0; t < helper->
NumTasks(); ++t) {
945 event.start_max = helper->
StartMax(t);
946 event.start = helper->
Starts()[t];
947 event.end_min = helper->
EndMin(t);
948 event.end_max = helper->
EndMax(t);
949 event.end = helper->
Ends()[t];
950 event.demand_min = integer_trail->
LowerBound(demands[t]);
951 events.push_back(event);
954 std::move(events), capacity_max,
model, manager);
961 const std::vector<IntervalVariable>& intervals,
Model*
model) {
966 model->TakeOwnership(helper);
968 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
974 [trail, helper,
model](
979 std::vector<PrecedenceEvent> events;
980 for (
int t = 0; t < helper->
NumTasks(); ++t) {
984 event.start_max = helper->
StartMax(t);
985 event.start = helper->
Starts()[t];
986 event.end_min = helper->
EndMin(t);
987 event.end_max = helper->
EndMax(t);
988 event.end = helper->
Ends()[t];
989 event.demand_min = IntegerValue(1);
990 events.push_back(event);
993 std::move(events), IntegerValue(1),
model,
1031 bool use_energy =
false;
1035 bool lifted =
false;
1038 return absl::StrCat(
"CtEvent(x_end = ", x_end.
DebugString(),
1039 ", x_start_min = ", x_start_min.value(),
1040 ", x_size_min = ", x_size_min.value(),
1041 ", x_lp_end = ", x_lp_end,
1042 ", y_start_min = ", y_start_min.value(),
1043 ", y_end_max = ", y_end_max.value(),
1044 ", energy_min = ", energy_min.value(),
1045 ", use_energy = ", use_energy,
", lifted = ", lifted);
1062 const std::string& cut_name,
1064 std::vector<CtEvent> events,
bool use_lifting,
Model*
model,
1069 std::sort(events.begin(), events.end(),
1071 return e1.x_start_min < e2.x_start_min;
1076 events[
start].x_start_min == events[
start - 1].x_start_min) {
1080 const IntegerValue sequence_start_min = events[
start].x_start_min;
1081 std::vector<CtEvent> residual_tasks(events.begin() +
start, events.end());
1089 for (
int before = 0; before <
start; ++before) {
1090 if (events[before].x_start_min + events[before].x_size_min >
1091 sequence_start_min) {
1093 CtEvent event = events[before];
1095 const IntegerValue old_size_min =
event.x_size_min;
1097 event.x_size_min +
event.x_start_min - sequence_start_min;
1098 event.x_start_min = sequence_start_min;
1109 event.energy_min =
event.energy_min *
event.x_size_min / old_size_min;
1110 residual_tasks.push_back(event);
1115 std::sort(residual_tasks.begin(), residual_tasks.end(),
1117 return e1.x_lp_end < e2.x_lp_end;
1121 double best_efficacy = 0.01;
1122 IntegerValue best_min_contrib(0);
1123 IntegerValue sum_duration(0);
1124 IntegerValue sum_square_duration(0);
1125 IntegerValue best_size_divisor(0);
1126 double unscaled_lp_contrib = 0;
1131 for (
int i = 0; i < residual_tasks.size(); ++i) {
1132 const CtEvent&
event = residual_tasks[i];
1133 DCHECK_GE(event.x_start_min, sequence_start_min);
1134 const IntegerValue
energy =
event.energy_min;
1138 current_start_min =
std::min(current_start_min, event.x_start_min);
1139 y_start_min =
std::min(y_start_min, event.y_start_min);
1140 y_end_max =
std::max(y_end_max, event.y_end_max);
1142 const IntegerValue size_divisor = y_end_max - y_start_min;
1148 const IntegerValue min_contrib =
1149 (sum_duration * sum_duration + sum_square_duration) / 2 +
1150 current_start_min * sum_duration * size_divisor;
1151 const double efficacy = (
ToDouble(min_contrib) -
1152 unscaled_lp_contrib *
ToDouble(size_divisor)) /
1153 std::sqrt(
ToDouble(sum_square_duration));
1155 if (efficacy > best_efficacy) {
1156 best_efficacy = efficacy;
1158 best_min_contrib = min_contrib;
1159 best_size_divisor = size_divisor;
1162 if (best_end != -1) {
1164 bool is_lifted =
false;
1165 bool use_energy =
false;
1166 for (
int i = 0; i <= best_end; ++i) {
1167 const CtEvent&
event = residual_tasks[i];
1168 is_lifted |=
event.
lifted;
1169 use_energy |=
event.use_energy;
1170 cut.
AddTerm(event.x_end, event.energy_min * best_size_divisor);
1172 std::string full_name = cut_name;
1173 if (is_lifted) full_name.append(
"_lifted");
1174 if (use_energy) full_name.append(
"_energy");
1175 top_n_cuts.
AddCut(cut.
Build(), full_name, lp_values);
1182 const std::vector<IntervalVariable>& intervals,
Model*
model) {
1187 model->TakeOwnership(helper);
1189 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
1195 [trail, helper,
model](
1200 auto generate_cuts = [&lp_values,
model, manager,
1201 helper](
const std::string& cut_name) {
1202 std::vector<CtEvent> events;
1210 event.x_size_min = size_min;
1211 event.x_end = end_expr;
1212 event.x_lp_end = end_expr.
LpValue(lp_values);
1213 event.y_start_min = IntegerValue(0);
1214 event.y_end_max = IntegerValue(1);
1215 event.energy_min = size_min;
1216 events.push_back(event);
1220 false,
model, manager);
1223 generate_cuts(
"NoOverlapCompletionTime");
1225 generate_cuts(
"NoOverlapCompletionTimeMirror");
1232 const std::vector<IntervalVariable>& intervals,
1234 const std::vector<AffineExpression>& demands,
1235 const std::vector<LinearExpression>& energies,
Model*
model) {
1240 model->TakeOwnership(helper);
1245 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
1251 [trail, integer_trail, helper, demands, energies,
capacity,
model](
1257 auto generate_cuts = [&lp_values,
model, manager, helper, capacity_max,
1258 integer_trail, &demands,
1259 &energies](
const std::string& cut_name) {
1260 std::vector<CtEvent> events;
1262 if (!helper->IsPresent(
index))
continue;
1263 if (helper->SizeMin(
index) > 0 &&
1264 integer_trail->LowerBound(demands[
index]) > 0) {
1266 const IntegerValue size_min = helper->SizeMin(
index);
1267 const IntegerValue demand_min =
1268 integer_trail->LowerBound(demands[
index]);
1272 event.x_size_min = size_min;
1273 event.x_end = end_expr;
1274 event.x_lp_end = end_expr.
LpValue(lp_values);
1275 event.y_start_min = IntegerValue(0);
1276 event.y_end_max = IntegerValue(capacity_max);
1277 event.energy_min = size_min * demand_min;
1281 const IntegerValue linearized_energy =
1284 event.energy_min = linearized_energy;
1285 event.use_energy =
true;
1288 events.push_back(event);
1292 true,
model, manager);
1294 if (!helper->SynchronizeAndSetTimeDirection(
true))
return false;
1295 generate_cuts(
"CumulativeCompletionTime");
1296 if (!helper->SynchronizeAndSetTimeDirection(
false))
return false;
1297 generate_cuts(
"CumulativeCompletionTimeMirror");
1304 const std::vector<IntervalVariable>& x_intervals,
1305 const std::vector<IntervalVariable>& y_intervals,
Model*
model) {
1310 model->TakeOwnership(x_helper);
1314 model->TakeOwnership(y_helper);
1316 AddIntegerVariableFromIntervals(x_helper,
model, &result.
vars);
1317 AddIntegerVariableFromIntervals(y_helper,
model, &result.
vars);
1323 [trail, x_helper, y_helper,
model](
1331 const int num_rectangles = x_helper->
NumTasks();
1332 std::vector<int> active_rectangles;
1333 std::vector<IntegerValue> cached_areas(num_rectangles);
1334 std::vector<Rectangle> cached_rectangles(num_rectangles);
1335 for (
int rect = 0; rect < num_rectangles; ++rect) {
1339 cached_areas[rect] =
1341 if (cached_areas[rect] == 0)
continue;
1347 Rectangle& rectangle = cached_rectangles[rect];
1353 active_rectangles.push_back(rect);
1356 if (active_rectangles.size() <= 1)
return true;
1358 std::vector<absl::Span<int>> components =
1360 cached_rectangles, absl::MakeSpan(active_rectangles));
1361 for (absl::Span<int> rectangles : components) {
1362 if (rectangles.size() <= 1)
continue;
1364 auto generate_cuts = [&lp_values,
model, manager, &rectangles,
1366 const std::string& cut_name,
1369 std::vector<CtEvent> events;
1371 for (
const int rect : rectangles) {
1374 event.
x_start_min = x_helper->ShiftedStartMin(rect);
1375 event.x_size_min = x_helper->SizeMin(rect);
1376 event.x_end = x_end_expr;
1377 event.x_lp_end = x_end_expr.
LpValue(lp_values);
1381 x_helper->SizeMin(rect) * y_helper->
SizeMin(rect);
1382 events.push_back(event);
1386 true,
model, manager);
1389 if (!x_helper->SynchronizeAndSetTimeDirection(
true))
return false;
1391 generate_cuts(
"NoOverlap2dXCompletionTime", x_helper, y_helper);
1392 generate_cuts(
"NoOverlap2dYCompletionTime", y_helper, x_helper);
1393 if (!x_helper->SynchronizeAndSetTimeDirection(
false))
return false;
1395 generate_cuts(
"NoOverlap2dXCompletionTimeMirror", x_helper, y_helper);
1396 generate_cuts(
"NoOverlap2dYCompletionTimeMirror", y_helper, x_helper);
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK(condition)
void AddRectangle(IntegerValue x_min, IntegerValue x_max, IntegerValue y_min, IntegerValue y_max)
IntegerValue GetBoundingArea()
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 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="")
LiteralIndex Index() const
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
const std::vector< AffineExpression > & Sizes() const
bool IsAbsent(int t) const
IntegerValue EndMax(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 SizeMax(int t) 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)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
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)
const LiteralIndex kNoLiteralIndex(-1)
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)
void GenerateNoOverlap2dEnergyCut(const std::vector< LinearExpression > &energies, absl::Span< int > rectangles, const std::string &cut_name, const absl::StrongVector< IntegerVariable, double > &lp_values, Model *model, IntegerTrail *integer_trail, IntegerEncoder *encoder, LinearConstraintManager *manager, SchedulingConstraintHelper *x_helper, SchedulingConstraintHelper *y_helper)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
void AppendVariablesToCumulativeCut(const AffineExpression &capacity, const std::vector< AffineExpression > &demands, IntegerTrail *integer_trail, CutGenerator *result)
double ComputeEnergyLp(const EnergyEvent &e, const absl::StrongVector< IntegerVariable, double > &lp_values, IntegerTrail *integer_trail)
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)
bool ProductIsLinearized(const LinearExpression &expr)
void GenerateEnergeticCuts(const std::string &cut_name, const absl::StrongVector< IntegerVariable, double > &lp_values, std::vector< EnergyEvent > events, const AffineExpression capacity, bool events_are_2d, Model *model, LinearConstraintManager *manager)
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.
std::optional< int64_t > end
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
LiteralIndex presence_literal_index
std::optional< LinearExpression > energy
std::string DebugString() const
IntegerValue GetMinOverlap(IntegerValue start, IntegerValue end) const