45 const double kMinCutViolation = 1e-4;
48 double 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];
61 void 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<IntegerVariable>& demands,
101 const std::vector<LinearExpression>& energies,
107 return [
capacity, demands, energies, trail, integer_trail, helper,
model,
111 if (trail->CurrentDecisionLevel() > 0)
return true;
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];
145 DCHECK(!helper->IsAbsent(start_index));
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);
186 if (helper->IsPresent(t)) {
187 if (demand_is_fixed(t)) {
188 if (helper->SizeIsFixed(t)) {
189 energy_lp +=
ToDouble(helper->SizeMin(t) * demand_min(t));
191 energy_lp +=
ToDouble(demand_min(t)) *
192 helper->Sizes()[t].LpValue(lp_values);
194 }
else if (helper->SizeIsFixed(t)) {
196 energy_lp += lp_values[demands[t]] *
ToDouble(helper->SizeMin(t));
197 }
else if (!energies.empty()) {
198 energy_lp += energies[t].LpValue(lp_values);
202 ToDouble(demand_min(t)) * helper->Sizes()[t].LpValue(lp_values);
203 energy_lp += lp_values[demands[t]] *
ToDouble(helper->SizeMin(t));
204 energy_lp -=
ToDouble(demand_min(t) * helper->SizeMin(t));
209 energy_lp += GetLiteralLpValue(helper->PresenceLiteral(t), lp_values,
211 ToDouble(helper->SizeMin(t) * demand_min(t));
214 min_of_starts =
std::min(min_of_starts, helper->StartMin(t));
215 max_of_ends =
std::max(max_of_ends, helper->EndMax(t));
220 if (i2 + 1 < residual_intervals.size() &&
221 helper->StartMin(residual_intervals[i2 + 1]) >= min_of_starts &&
222 helper->EndMax(residual_intervals[i2 + 1]) <= max_of_ends) {
231 std::vector<int> lifted_intervals;
232 std::vector<IntegerValue> lifted_min_overlap;
233 double forced_contrib_lp = 0.0;
234 for (
const int t : intervals_not_visited) {
236 if (helper->StartMin(t) >= min_of_starts &&
237 helper->EndMax(t) <= max_of_ends) {
241 const IntegerValue min_overlap =
242 helper->GetMinOverlap(t, min_of_starts, max_of_ends);
244 if (min_overlap <= 0)
continue;
246 lifted_intervals.push_back(t);
248 if (helper->IsPresent(t)) {
249 if (demand_is_fixed(t)) {
250 forced_contrib_lp +=
ToDouble(min_overlap * demand_min(t));
254 lp_values[demands[t]] *
ToDouble(min_overlap);
257 forced_contrib_lp += GetLiteralLpValue(helper->PresenceLiteral(t),
258 lp_values, encoder) *
259 ToDouble(min_overlap * demand_min(t));
264 const double relative_violation =
265 (energy_lp + forced_contrib_lp) /
266 ToDouble((max_of_ends - min_of_starts) * capacity_max);
267 if (relative_violation > max_relative_violation) {
268 end_index_of_max_violation = i2;
269 max_relative_violation = relative_violation;
270 start_of_max_violation = min_of_starts;
271 end_of_max_violation = max_of_ends;
272 lifted_intervals_of_max_violation = lifted_intervals;
276 if (end_index_of_max_violation == -1)
continue;
279 bool cut_generated =
true;
280 bool has_opt_cuts =
false;
282 bool has_quadratic_cuts =
false;
283 bool use_energy =
false;
289 for (
int i2 = 0; i2 <= end_index_of_max_violation; ++i2) {
290 const int t = residual_intervals[i2];
291 if (helper->IsPresent(t)) {
292 if (demand_is_fixed(t)) {
293 cut.
AddTerm(helper->Sizes()[t], demand_min(t));
294 }
else if (!helper->SizeIsFixed(t) && !energies.empty()) {
302 if (!helper->SizeIsFixed(t)) {
303 has_quadratic_cuts =
true;
310 if (!helper->SizeIsFixed(t) || !demand_is_fixed(t)) {
311 has_quadratic_cuts =
true;
314 helper->SizeMin(t) * demand_min(t))) {
315 cut_generated =
false;
321 for (
int i2 = 0; i2 < lifted_intervals_of_max_violation.size(); ++i2) {
322 const int t = lifted_intervals_of_max_violation[i2];
323 const IntegerValue min_overlap = helper->GetMinOverlap(
324 t, start_of_max_violation, end_of_max_violation);
327 if (helper->IsPresent(t)) {
328 if (demand_is_fixed(t)) {
332 cut.
AddTerm(demands[t], min_overlap);
337 min_overlap * demand_min(t))) {
338 cut_generated =
false;
345 std::string full_name = cut_name;
346 if (has_opt_cuts) full_name.append(
"_opt");
347 if (has_quadratic_cuts) full_name.append(
"_quad");
348 if (lifted) full_name.append(
"_lifted");
349 if (use_energy) full_name.append(
"_energy");
351 manager->AddCut(cut.
Build(), full_name, lp_values);
359 const std::vector<IntervalVariable>& intervals,
360 const IntegerVariable
capacity,
const std::vector<IntegerVariable>& demands,
361 const std::vector<LinearExpression>& energies,
Model*
model) {
366 model->TakeOwnership(helper);
368 result.
vars = demands;
370 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
387 const std::vector<IntervalVariable>& intervals,
Model*
model) {
392 model->TakeOwnership(helper);
394 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
400 "NoOverlapEnergy", helper,
407 const std::vector<IntervalVariable>& intervals,
408 const IntegerVariable
capacity,
const std::vector<IntegerVariable>& demands,
414 model->TakeOwnership(helper);
416 result.
vars = demands;
418 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
434 if (trail->CurrentDecisionLevel() > 0)
return true;
436 std::vector<Event> events;
439 for (
int i = 0; i < helper->
NumTasks(); ++i) {
448 e1.interval_index = i;
450 e1.demand = demands[i];
456 events.push_back(e1);
457 events.push_back(e2);
463 std::sort(events.begin(), events.end(),
464 [](
const Event i,
const Event j) {
465 if (i.time == j.time) {
466 if (i.positive == j.positive) {
467 return i.interval_index < j.interval_index;
471 return i.time < j.time;
474 std::vector<Event> cut_events;
475 bool added_positive_event =
false;
476 for (
const Event& e : events) {
478 added_positive_event =
true;
479 cut_events.push_back(e);
482 if (added_positive_event && cut_events.size() > 1) {
484 bool cut_generated =
true;
488 for (
const Event& cut_event : cut_events) {
489 if (helper->
IsPresent(cut_event.interval_index)) {
490 cut.
AddTerm(cut_event.demand, IntegerValue(1));
494 integer_trail->LowerBound(cut_event.demand));
495 if (!cut_generated)
break;
501 manager->AddCut(cut.
Build(),
"CumulativeTimeTable", lp_values);
506 for (
int i = 0; i < cut_events.size(); ++i) {
507 if (cut_events[i].interval_index == e.interval_index) {
510 cut_events[new_size] = cut_events[i];
513 cut_events.resize(new_size);
514 added_positive_event =
false;
533 const std::string& cut_name,
535 std::vector<PrecedenceEvent> events, IntegerValue capacity_max,
537 const int num_events = events.size();
538 if (num_events <= 1)
return;
540 std::sort(events.begin(), events.end(),
546 const double tolerance = 1e-4;
548 for (
int i = 0; i + 1 < num_events; ++i) {
550 for (
int j = i + 1; j < num_events; ++j) {
560 if (interval_1_can_precede_2 && !interval_2_can_precede_1 &&
567 }
else if (interval_2_can_precede_1 && !interval_1_can_precede_2 &&
581 const std::vector<IntervalVariable>& intervals, IntegerVariable
capacity,
582 const std::vector<IntegerVariable>& demands,
Model*
model) {
587 model->TakeOwnership(helper);
589 result.
vars = demands;
591 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
602 const IntegerValue capacity_max = integer_trail->UpperBound(
capacity);
603 std::vector<PrecedenceEvent> events;
604 for (
int t = 0; t < helper->NumTasks(); ++t) {
605 if (!helper->IsPresent(t))
continue;
608 event.start_max = helper->StartMax(t);
609 event.start = helper->Starts()[t];
610 event.end_min = helper->EndMin(t);
611 event.end_max = helper->EndMax(t);
612 event.end = helper->Ends()[t];
613 event.demand_min = integer_trail->LowerBound(demands[t]);
614 events.push_back(event);
617 std::move(events), capacity_max,
model, manager);
624 const std::vector<IntervalVariable>& intervals,
Model*
model) {
629 model->TakeOwnership(helper);
631 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
636 [trail, helper,
model](
641 std::vector<PrecedenceEvent> events;
642 for (
int t = 0; t < helper->NumTasks(); ++t) {
643 if (!helper->IsPresent(t))
continue;
646 event.start_max = helper->StartMax(t);
647 event.start = helper->Starts()[t];
648 event.end_min = helper->EndMin(t);
649 event.end_max = helper->EndMax(t);
650 event.end = helper->Ends()[t];
651 event.demand_min = IntegerValue(1);
652 events.push_back(event);
655 std::move(events), IntegerValue(1),
model,
724 const std::string& cut_name,
726 std::vector<CtEvent> events,
bool use_lifting,
Model*
model,
731 std::sort(events.begin(), events.end(),
735 for (
int start = 0; start + 1 < events.size(); ++start) {
738 events[start].x_start_min == events[start - 1].x_start_min) {
742 const IntegerValue sequence_start_min = events[start].x_start_min;
743 std::vector<CtEvent> residual_tasks(events.begin() + start, events.end());
751 for (
int before = 0; before < start; ++before) {
752 if (events[before].x_start_min + events[before].x_size_min >
753 sequence_start_min) {
754 CtEvent event = events[before];
756 const IntegerValue old_size_min =
event.x_size_min;
758 event.x_size_min +
event.x_start_min - sequence_start_min;
759 event.x_start_min = sequence_start_min;
768 event.energy_min =
event.energy_min *
event.x_size_min / old_size_min;
769 residual_tasks.push_back(event);
774 std::sort(residual_tasks.begin(), residual_tasks.end(),
780 double best_efficacy = 0.01;
781 IntegerValue best_min_contrib(0);
782 IntegerValue sum_duration(0);
783 IntegerValue sum_square_duration(0);
784 IntegerValue best_size_divisor(0);
785 double unscaled_lp_contrib = 0;
790 for (
int i = 0; i < residual_tasks.size(); ++i) {
791 const CtEvent&
event = residual_tasks[i];
792 DCHECK_GE(event.x_start_min, sequence_start_min);
793 const IntegerValue
energy =
event.energy_min;
797 current_start_min =
std::min(current_start_min, event.x_start_min);
798 y_start_min =
std::min(y_start_min, event.y_start_min);
799 y_end_max =
std::max(y_end_max, event.y_end_max);
801 const IntegerValue size_divisor = y_end_max - y_start_min;
807 const IntegerValue min_contrib =
808 (sum_duration * sum_duration + sum_square_duration) / 2 +
809 current_start_min * sum_duration * size_divisor;
810 const double efficacy = (
ToDouble(min_contrib) -
811 unscaled_lp_contrib *
ToDouble(size_divisor)) /
812 std::sqrt(
ToDouble(sum_square_duration));
814 if (efficacy > best_efficacy) {
815 best_efficacy = efficacy;
817 best_min_contrib = min_contrib;
818 best_size_divisor = size_divisor;
821 if (best_end != -1) {
823 bool is_lifted =
false;
824 bool use_energy =
false;
825 for (
int i = 0; i <= best_end; ++i) {
826 const CtEvent&
event = residual_tasks[i];
827 is_lifted |=
event.
lifted;
828 use_energy |=
event.use_energy;
829 cut.
AddTerm(event.x_end, event.energy_min * best_size_divisor);
831 std::string full_name = cut_name;
832 if (is_lifted) full_name.append(
"_lifted");
833 if (use_energy) full_name.append(
"_energy");
834 top_n_cuts.
AddCut(cut.
Build(), full_name, lp_values);
841 const std::vector<IntervalVariable>& intervals,
Model*
model) {
846 model->TakeOwnership(helper);
848 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
853 [trail, helper,
model](
858 auto generate_cuts = [&lp_values,
model, manager,
859 helper](
const std::string& cut_name) {
860 std::vector<CtEvent> events;
862 if (!helper->IsPresent(
index))
continue;
863 const IntegerValue size_min = helper->SizeMin(
index);
868 event.x_size_min = size_min;
869 event.x_end = end_expr;
870 event.x_lp_end = end_expr.
LpValue(lp_values);
871 event.y_start_min = IntegerValue(0);
872 event.y_end_max = IntegerValue(1);
873 event.energy_min = size_min;
874 events.push_back(event);
878 false,
model, manager);
880 if (!helper->SynchronizeAndSetTimeDirection(
true))
return false;
881 generate_cuts(
"NoOverlapCompletionTime");
882 if (!helper->SynchronizeAndSetTimeDirection(
false))
return false;
883 generate_cuts(
"NoOverlapCompletionTimeMirror");
890 const std::vector<IntervalVariable>& intervals,
891 const IntegerVariable
capacity,
const std::vector<IntegerVariable>& demands,
892 const std::vector<LinearExpression>& energies,
Model*
model) {
897 model->TakeOwnership(helper);
899 result.
vars = demands;
901 AddIntegerVariableFromIntervals(helper,
model, &result.
vars);
907 [trail, integer_trail, helper, demands, energies,
capacity,
model](
912 const IntegerValue capacity_max = integer_trail->UpperBound(
capacity);
913 auto generate_cuts = [&lp_values,
model, manager, helper, capacity_max,
914 integer_trail, &demands,
915 &energies](
const std::string& cut_name) {
916 std::vector<CtEvent> events;
918 if (!helper->IsPresent(
index))
continue;
919 if (helper->SizeMin(
index) > 0 &&
920 integer_trail->LowerBound(demands[
index]) > 0) {
922 IntegerValue energy_min =
927 const IntegerValue size_min = helper->SizeMin(
index);
928 const IntegerValue demand_min =
929 integer_trail->LowerBound(demands[
index]);
932 event.x_size_min = size_min;
933 event.x_end = end_expr;
934 event.x_lp_end = end_expr.
LpValue(lp_values);
935 event.y_start_min = IntegerValue(0);
936 event.y_end_max = IntegerValue(capacity_max);
937 if (energy_min > size_min * demand_min) {
938 event.energy_min = energy_min;
939 event.use_energy =
true;
941 event.energy_min = size_min * demand_min;
943 events.push_back(event);
947 true,
model, manager);
949 if (!helper->SynchronizeAndSetTimeDirection(
true))
return false;
950 generate_cuts(
"CumulativeCompletionTime");
951 if (!helper->SynchronizeAndSetTimeDirection(
false))
return false;
952 generate_cuts(
"CumulativeCompletionTimeMirror");
959 const std::vector<IntervalVariable>& x_intervals,
960 const std::vector<IntervalVariable>& y_intervals,
Model*
model) {
965 model->TakeOwnership(x_helper);
969 model->TakeOwnership(y_helper);
970 AddIntegerVariableFromIntervals(x_helper,
model, &result.
vars);
971 AddIntegerVariableFromIntervals(y_helper,
model, &result.
vars);
976 [trail, x_helper, y_helper,
model](
981 if (!x_helper->SynchronizeAndSetTimeDirection(
true))
return false;
982 if (!y_helper->SynchronizeAndSetTimeDirection(
true))
return false;
984 const int num_boxes = x_helper->NumTasks();
985 std::vector<int> active_boxes;
986 std::vector<IntegerValue> cached_areas(num_boxes);
987 std::vector<Rectangle> cached_rectangles(num_boxes);
988 for (
int box = 0; box < num_boxes; ++box) {
989 cached_areas[box] = x_helper->SizeMin(box) * y_helper->SizeMin(box);
990 if (cached_areas[box] == 0)
continue;
991 if (!y_helper->IsPresent(box) || !y_helper->IsPresent(box))
continue;
997 Rectangle& rectangle = cached_rectangles[box];
998 rectangle.
x_min = x_helper->StartMin(box);
999 rectangle.
x_max = x_helper->EndMax(box);
1000 rectangle.
y_min = y_helper->StartMin(box);
1001 rectangle.
y_max = y_helper->EndMax(box);
1003 active_boxes.push_back(box);
1006 if (active_boxes.size() <= 1)
return true;
1008 std::vector<absl::Span<int>> components =
1010 absl::MakeSpan(active_boxes));
1011 for (absl::Span<int> boxes : components) {
1012 if (boxes.size() <= 1)
continue;
1014 auto generate_cuts = [&lp_values,
model, manager, &boxes,
1016 const std::string& cut_name,
1019 std::vector<CtEvent> events;
1021 for (
const int box : boxes) {
1024 event.
x_start_min = x_helper->ShiftedStartMin(box);
1025 event.x_size_min = x_helper->SizeMin(box);
1026 event.x_end = x_end_expr;
1027 event.x_lp_end = x_end_expr.
LpValue(lp_values);
1028 event.y_start_min = y_helper->ShiftedStartMin(box);
1029 event.y_end_max = y_helper->ShiftedEndMax(box);
1031 x_helper->SizeMin(box) * y_helper->SizeMin(box);
1032 events.push_back(event);
1036 true,
model, manager);
1039 if (!x_helper->SynchronizeAndSetTimeDirection(
true))
return false;
1040 if (!y_helper->SynchronizeAndSetTimeDirection(
true))
return false;
1041 generate_cuts(
"NoOverlap2dXCompletionTime", x_helper, y_helper);
1042 generate_cuts(
"NoOverlap2dYCompletionTime", y_helper, x_helper);
1043 if (!x_helper->SynchronizeAndSetTimeDirection(
false))
return false;
1044 if (!y_helper->SynchronizeAndSetTimeDirection(
false))
return false;
1045 generate_cuts(
"NoOverlap2dXCompletionTimeMirror", x_helper, y_helper);
1046 generate_cuts(
"NoOverlap2dYCompletionTimeMirror", y_helper, x_helper);
CutGenerator CreateNoOverlapEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
IntegerValue StartMax(int t) const
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
bool IsAbsent(int t) const
CutGenerator CreateCumulativeTimeTableCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, Model *model)
Class that owns everything related to a particular optimization model.
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
std::vector< IntegerVariable > vars
CutGenerator CreateCumulativePrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, IntegerVariable capacity, const std::vector< IntegerVariable > &demands, Model *model)
void AddLinearExpression(const LinearExpression &expr)
bool IsPresent(int t) const
void AddTerm(IntegerVariable var, IntegerValue coeff)
double LpValue(const absl::StrongVector< IntegerVariable, double > &lp_values) const
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
double ToDouble(IntegerValue value)
const std::string DebugString() const
#define DCHECK_NE(val1, val2)
std::function< bool(const absl::StrongVector< IntegerVariable, double > &, LinearConstraintManager *)> GenerateCumulativeEnergyCuts(const std::string &cut_name, SchedulingConstraintHelper *helper, const std::vector< IntegerVariable > &demands, const std::vector< LinearExpression > &energies, AffineExpression capacity, Model *model)
void TransferToManager(const absl::StrongVector< IntegerVariable, double > &lp_solution, LinearConstraintManager *manager)
std::string DebugString() const
#define DCHECK_GE(val1, val2)
CutGenerator CreateNoOverlapPrecedenceCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
std::vector< absl::Span< int > > GetOverlappingRectangleComponents(const std::vector< Rectangle > &rectangles, absl::Span< int > active_rectangles)
IntegerValue EndMin(int t) const
#define DCHECK(condition)
void AddConstant(IntegerValue value)
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)
void AddCut(LinearConstraint ct, const std::string &name, const absl::StrongVector< IntegerVariable, double > &lp_solution)
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)
Collection of objects used to extend the Constraint Solver library.
CutGenerator CreateNoOverlap2dCompletionTimeCutGenerator(const std::vector< IntervalVariable > &x_intervals, const std::vector< IntervalVariable > &y_intervals, Model *model)
const IntegerVariable kNoIntegerVariable(-1)
CutGenerator CreateCumulativeCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, const std::vector< LinearExpression > &energies, Model *model)
bool AddCut(LinearConstraint ct, std::string type_name, const absl::StrongVector< IntegerVariable, double > &lp_solution, std::string extra_info="")
std::function< bool(const absl::StrongVector< IntegerVariable, double > &lp_values, LinearConstraintManager *manager)> generate_cuts
CutGenerator CreateNoOverlapCompletionTimeCutGenerator(const std::vector< IntervalVariable > &intervals, Model *model)
Literal PresenceLiteral(int index) const
int CurrentDecisionLevel() const
void AddQuadraticLowerBound(AffineExpression left, AffineExpression right, IntegerTrail *integer_trail)
CutGenerator CreateCumulativeEnergyCutGenerator(const std::vector< IntervalVariable > &intervals, const IntegerVariable capacity, const std::vector< IntegerVariable > &demands, const std::vector< LinearExpression > &energies, Model *model)