22 #include "absl/container/flat_hash_set.h"
23 #include "absl/types/span.h"
34 #include "ortools/sat/sat_parameters.pb.h"
47 void AddIsEqualToMinOf(IntegerVariable min_var,
48 const std::vector<AffineExpression>& exprs,
50 std::vector<LinearExpression> converted;
51 for (
const AffineExpression& affine : exprs) {
53 e.offset = affine.constant;
55 e.vars.push_back(affine.var);
56 e.coeffs.push_back(affine.coeff);
58 converted.push_back(e);
60 LinearExpression target;
61 target.vars.push_back(min_var);
62 target.coeffs.push_back(IntegerValue(1));
66 void AddIsEqualToMaxOf(IntegerVariable max_var,
67 const std::vector<AffineExpression>& exprs,
69 std::vector<LinearExpression> converted;
70 for (
const AffineExpression& affine : exprs) {
72 e.offset = affine.constant;
74 e.vars.push_back(affine.var);
75 e.coeffs.push_back(affine.coeff);
79 LinearExpression target;
81 target.coeffs.push_back(IntegerValue(1));
92 std::vector<AffineExpression> sizes;
93 for (
int box = 0; box < y->
NumTasks(); ++box) {
96 sizes.push_back(y->
Sizes()[box]);
99 const IntegerVariable min_start_var =
101 AddIsEqualToMinOf(min_start_var, y->
Starts(),
model);
103 const IntegerVariable max_end_var =
105 AddIsEqualToMaxOf(max_end_var, y->
Ends(),
model);
110 const std::vector<int64_t> coeffs = {-
capacity.coeff.value(), -1, 1};
113 coeffs,
capacity.constant.value()));
117 const SatParameters* params =
model->GetOrCreate<SatParameters>();
118 const bool add_timetabling_relaxation =
119 params->use_timetabling_in_no_overlap_2d();
120 bool add_energetic_relaxation =
121 params->use_energetic_reasoning_in_no_overlap_2d();
125 if (add_timetabling_relaxation || add_energetic_relaxation) {
132 if (add_timetabling_relaxation) {
133 DCHECK(demands !=
nullptr);
137 model->TakeOwnership(time_tabling);
142 if (add_energetic_relaxation) {
143 DCHECK(demands !=
nullptr);
154 IntegerValue FindCanonicalValue(IntegerValue lb, IntegerValue ub) {
155 if (lb == ub)
return lb;
156 if (lb <= 0 && ub > 0)
return IntegerValue(0);
157 if (lb < 0 && ub <= 0) {
158 return -FindCanonicalValue(-ub, -lb);
162 IntegerValue candidate = ub;
163 for (
int o = 0; o < 62; ++o) {
165 const IntegerValue masked_ub(ub.value() & ~mask);
166 if (masked_ub >= lb) {
167 candidate = masked_ub;
175 void SplitDisjointBoxes(
const SchedulingConstraintHelper& x,
176 absl::Span<int> boxes,
177 std::vector<absl::Span<int>>* result) {
179 std::sort(boxes.begin(), boxes.end(), [&x](
int a,
int b) {
180 return x.ShiftedStartMin(a) < x.ShiftedStartMin(b);
182 int current_start = 0;
183 std::size_t current_length = 1;
184 IntegerValue current_max_end = x.EndMax(boxes[0]);
186 for (
int b = 1;
b < boxes.size(); ++
b) {
187 const int box = boxes[
b];
188 if (x.ShiftedStartMin(box) < current_max_end) {
191 current_max_end =
std::max(current_max_end, x.EndMax(box));
193 if (current_length > 1) {
194 result->emplace_back(&boxes[current_start], current_length);
198 current_max_end = x.EndMax(box);
203 if (current_length > 1) {
204 result->emplace_back(&boxes[current_start], current_length);
219 x_(x->NumTasks(),
model),
222 overload_checker_(&x_),
223 forward_detectable_precedences_(true, &x_),
224 backward_detectable_precedences_(false, &x_),
225 forward_not_last_(true, &x_),
226 backward_not_last_(false, &x_),
227 forward_edge_finding_(true, &x_),
228 backward_edge_finding_(false, &x_) {}
234 int fast_priority,
int slow_priority) {
235 fast_id_ = watcher_->
Register(
this);
244 const int slow_id = watcher_->
Register(
this);
250 #define RETURN_IF_FALSE(f) \
251 if (!(f)) return false;
253 bool NonOverlappingRectanglesDisjunctivePropagator::
254 FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
255 bool fast_propagation,
const SchedulingConstraintHelper& x,
256 SchedulingConstraintHelper* y) {
259 if (!y->SynchronizeAndSetTimeDirection(
true))
return false;
263 indexed_intervals_.clear();
264 const std::vector<TaskTime>& temp = y->TaskByDecreasingStartMax();
265 for (
int i = temp.size(); --i >= 0;) {
266 const int box = temp[i].task_index;
267 if (!strict_ && (x.SizeMin(box) == 0 || y->SizeMin(box) == 0))
continue;
270 if (x.IsAbsent(box) || y->IsAbsent(box))
continue;
274 if (x.IsPresent(box) && !y->IsPresent(box))
continue;
275 if (!x.IsPresent(box) && !y->IsPresent(box) &&
276 x.PresenceLiteral(box) != y->PresenceLiteral(box)) {
280 const IntegerValue
start_max = temp[i].time;
281 const IntegerValue
end_min = y->EndMin(box);
288 if (indexed_intervals_.size() < 2)
return true;
290 &events_overlapping_boxes_);
293 boxes_to_propagate_.clear();
294 reduced_overlapping_boxes_.clear();
295 for (
int i = 0; i < events_overlapping_boxes_.size(); ++i) {
296 SplitDisjointBoxes(x, absl::MakeSpan(events_overlapping_boxes_[i]),
298 for (absl::Span<int> sub_boxes : disjoint_boxes_) {
302 const auto& insertion = reduced_overlapping_boxes_.insert(sub_boxes);
303 if (insertion.second) boxes_to_propagate_.push_back(sub_boxes);
310 for (
const absl::Span<const int> boxes : boxes_to_propagate_) {
313 if (!fast_propagation && boxes.size() <= 2)
continue;
321 for (
const int b : boxes) {
335 const IntegerValue line_to_use_for_reason = FindCanonicalValue(lb, ub);
340 if (fast_propagation) {
370 const bool fast_propagation = watcher_->
GetCurrentId() == fast_id_;
372 fast_propagation, global_x_, &global_y_));
376 fast_propagation, global_y_, &global_x_));
386 const int num_boxes = global_x_.
NumTasks();
387 for (
int box1 = 0; box1 < num_boxes; ++box1) {
388 if (!global_x_.
IsPresent(box1))
continue;
389 for (
int box2 = box1 + 1; box2 < num_boxes; ++box2) {
390 if (!global_x_.
IsPresent(box2))
continue;
418 bool NonOverlappingRectanglesDisjunctivePropagator::PropagateTwoBoxes() {
425 const auto left_box_before_right_box = [
this](
int left,
int right) {
427 const IntegerValue left_end_min = x_.
EndMin(left);
428 if (left_end_min > x_.
StartMin(right)) {
438 const IntegerValue right_start_max = x_.
StartMax(right);
439 if (right_start_max < x_.
EndMax(left)) {
461 return left_box_before_right_box(0, 1);
464 return left_box_before_right_box(1, 0);
472 #undef RETURN_IF_FALSE
void SetPropagatorPriority(int id, int priority)
int Register(PropagatorInterface *propagator)
void NotifyThatPropagatorMayNotReachFixedPointInOnePass(int id)
Class that owns everything related to a particular optimization model.
void Register(int fast_priority, int slow_priority)
~NonOverlappingRectanglesDisjunctivePropagator() override
NonOverlappingRectanglesDisjunctivePropagator(bool strict, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
IntegerValue EndMin(int t) const
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue value)
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue value)
void WatchAllTasks(int id, GenericLiteralWatcher *watcher, bool watch_start_max=true, bool watch_end_max=true) const
void AddPresenceReason(int t)
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
bool IsPresent(int t) const
void AddEndMinReason(int t, IntegerValue lower_bound)
IntegerValue EndMax(int t) const
ABSL_MUST_USE_RESULT bool ReportConflict()
const std::vector< AffineExpression > & Starts() const
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
void SetOtherHelper(SchedulingConstraintHelper *other_helper, absl::Span< const int > map_to_other_helper, IntegerValue event)
IntegerValue StartMin(int t) const
IntegerValue StartMax(int t) const
void AddReasonForBeingBefore(int before, int after)
const std::vector< AffineExpression > & Sizes() const
void AddStartMaxReason(int t, IntegerValue upper_bound)
void SetTimeDirection(bool is_forward)
const std::vector< AffineExpression > & Ends() const
void RegisterWith(GenericLiteralWatcher *watcher)
void AddCumulativeOverloadChecker(AffineExpression capacity, SchedulingConstraintHelper *helper, SchedulingDemandHelper *demands, Model *model)
const IntegerVariable kNoIntegerVariable(-1)
void ConstructOverlappingSets(bool already_sorted, std::vector< IndexedInterval > *intervals, std::vector< std::vector< int >> *result)
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
void AddDiffnCumulativeRelationOnX(SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Collection of objects used to extend the Constraint Solver library.
int64_t CapSub(int64_t x, int64_t y)
#define RETURN_IF_FALSE(f)