OR-Tools  9.2
diffn.h
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_SAT_DIFFN_H_
15 #define OR_TOOLS_SAT_DIFFN_H_
16 
17 #include <functional>
18 #include <vector>
19 
20 #include "ortools/base/int_type.h"
22 #include "ortools/base/logging.h"
23 #include "ortools/base/macros.h"
24 #include "ortools/sat/diffn_util.h"
26 #include "ortools/sat/integer.h"
27 #include "ortools/sat/intervals.h"
28 #include "ortools/sat/model.h"
29 #include "ortools/sat/sat_base.h"
30 
31 namespace operations_research {
32 namespace sat {
33 
34 // Propagates using a box energy reasoning.
36  public:
37  // The strict parameters indicates how to place zero width or zero height
38  // boxes. If strict is true, these boxes must not 'cross' another box, and are
39  // pushed by the other boxes.
42  Model* model)
43  : x_(*x), y_(*y), random_(model->GetOrCreate<ModelRandomGenerator>()) {}
45 
46  bool Propagate() final;
47  int RegisterWith(GenericLiteralWatcher* watcher);
48 
49  private:
50  void SortBoxesIntoNeighbors(int box, absl::Span<const int> local_boxes,
51  IntegerValue total_sum_of_areas);
52  bool FailWhenEnergyIsTooLarge(int box, absl::Span<const int> local_boxes,
53  IntegerValue total_sum_of_areas);
54 
57  ModelRandomGenerator* random_;
58 
59  // When the size of the bounding box is greater than any of the corresponding
60  // rectangles, then there is no point checking for overload.
61  IntegerValue threshold_x_;
62  IntegerValue threshold_y_;
63 
64  std::vector<int> active_boxes_;
65  std::vector<IntegerValue> cached_energies_;
66  std::vector<Rectangle> cached_rectangles_;
67 
68  struct Neighbor {
69  int box;
70  IntegerValue distance_to_bounding_box;
71  bool operator<(const Neighbor& o) const {
72  return distance_to_bounding_box < o.distance_to_bounding_box;
73  }
74  };
75  std::vector<Neighbor> neighbors_;
76 
81 };
82 
83 // Non overlapping rectangles.
85  : public PropagatorInterface {
86  public:
87  // The strict parameters indicates how to place zero width or zero height
88  // boxes. If strict is true, these boxes must not 'cross' another box, and are
89  // pushed by the other boxes.
90  // The slow_propagators select which disjunctive algorithms to propagate.
94  Model* model);
96 
97  bool Propagate() final;
98  void Register(int fast_priority, int slow_priority);
99 
100  private:
101  bool PropagateTwoBoxes();
102  bool FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
103  bool fast_propagation, const SchedulingConstraintHelper& x,
105 
106  SchedulingConstraintHelper& global_x_;
107  SchedulingConstraintHelper& global_y_;
109  const bool strict_;
110 
111  GenericLiteralWatcher* watcher_;
112  int fast_id_; // Propagator id of the "fast" version.
113 
114  std::vector<IndexedInterval> indexed_intervals_;
115  std::vector<std::vector<int>> events_overlapping_boxes_;
116 
117  absl::flat_hash_set<absl::Span<int>> reduced_overlapping_boxes_;
118  std::vector<absl::Span<int>> boxes_to_propagate_;
119  std::vector<absl::Span<int>> disjoint_boxes_;
120 
121  DisjunctiveOverloadChecker overload_checker_;
122  DisjunctiveDetectablePrecedences forward_detectable_precedences_;
123  DisjunctiveDetectablePrecedences backward_detectable_precedences_;
124  DisjunctiveNotLast forward_not_last_;
125  DisjunctiveNotLast backward_not_last_;
126  DisjunctiveEdgeFinding forward_edge_finding_;
127  DisjunctiveEdgeFinding backward_edge_finding_;
128 
133 };
134 
135 // Add a cumulative relaxation. That is, on one dimension, it does not enforce
136 // the rectangle aspect, allowing vertical slices to move freely.
137 void AddCumulativeRelaxation(const std::vector<IntervalVariable>& x_intervals,
140 
141 // Enforces that the boxes with corners in (x, y), (x + dx, y), (x, y + dy)
142 // and (x + dx, y + dy) do not overlap.
143 // If strict is true, and if one box has a zero dimension, it still cannot
144 // intersect another box.
145 inline std::function<void(Model*)> NonOverlappingRectangles(
146  const std::vector<IntervalVariable>& x,
147  const std::vector<IntervalVariable>& y, bool is_strict,
148  bool add_cumulative_relaxation = true) {
149  return [=](Model* model) {
150  SchedulingConstraintHelper* x_helper =
152  SchedulingConstraintHelper* y_helper =
154  model->TakeOwnership(x_helper);
155  model->TakeOwnership(y_helper);
156 
157  NonOverlappingRectanglesEnergyPropagator* energy_constraint =
158  new NonOverlappingRectanglesEnergyPropagator(x_helper, y_helper, model);
159  GenericLiteralWatcher* const watcher =
160  model->GetOrCreate<GenericLiteralWatcher>();
161  watcher->SetPropagatorPriority(energy_constraint->RegisterWith(watcher), 3);
162  model->TakeOwnership(energy_constraint);
163 
165  new NonOverlappingRectanglesDisjunctivePropagator(is_strict, x_helper,
166  y_helper, model);
167  constraint->Register(/*fast_priority=*/3, /*slow_priority=*/4);
168  model->TakeOwnership(constraint);
169 
170  if (add_cumulative_relaxation) {
171  // We must first check if the cumulative relaxation is possible.
172  bool some_boxes_are_only_optional_on_x = false;
173  bool some_boxes_are_only_optional_on_y = false;
174  for (int i = 0; i < x.size(); ++i) {
175  if (x_helper->IsOptional(i) && y_helper->IsOptional(i) &&
176  x_helper->PresenceLiteral(i) != y_helper->PresenceLiteral(i)) {
177  // Abort as the task would be conditioned by two literals.
178  return;
179  }
180  if (x_helper->IsOptional(i) && !y_helper->IsOptional(i)) {
181  // We cannot use x_size as the demand of the cumulative based on
182  // the y_intervals.
183  some_boxes_are_only_optional_on_x = true;
184  }
185  if (y_helper->IsOptional(i) && !x_helper->IsOptional(i)) {
186  // We cannot use y_size as the demand of the cumulative based on
187  // the y_intervals.
188  some_boxes_are_only_optional_on_y = true;
189  }
190  }
191  if (!some_boxes_are_only_optional_on_y) {
192  AddCumulativeRelaxation(x, x_helper, y_helper, model);
193  }
194  if (!some_boxes_are_only_optional_on_x) {
195  AddCumulativeRelaxation(y, y_helper, x_helper, model);
196  }
197  }
198  };
199 }
200 
201 } // namespace sat
202 } // namespace operations_research
203 
204 #endif // OR_TOOLS_SAT_DIFFN_H_
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
GRBmodel * model
void AddCumulativeRelaxation(const std::vector< IntervalVariable > &x_intervals, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
Definition: sat/diffn.cc:80
Definition: cleanup.h:22
void SetPropagatorPriority(int id, int priority)
Definition: integer.cc:2018
NonOverlappingRectanglesDisjunctivePropagator(bool strict, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
Definition: sat/diffn.cc:332
Collection of objects used to extend the Constraint Solver library.
std::function< void(Model *)> NonOverlappingRectangles(const std::vector< IntervalVariable > &x, const std::vector< IntervalVariable > &y, bool is_strict, bool add_cumulative_relaxation=true)
Definition: diffn.h:145
NonOverlappingRectanglesEnergyPropagator(SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
Definition: diffn.h:40