OR-Tools  9.6
diffn_util.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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_UTIL_H_
15 #define OR_TOOLS_SAT_DIFFN_UTIL_H_
16 
17 #include <algorithm>
18 #include <cstdint>
19 #include <iosfwd>
20 #include <ostream>
21 #include <string>
22 #include <tuple>
23 #include <vector>
24 
25 #include "absl/container/flat_hash_set.h"
26 #include "absl/random/bit_gen_ref.h"
27 #include "absl/strings/str_format.h"
28 #include "absl/types/span.h"
30 #include "ortools/sat/integer.h"
31 #include "ortools/sat/intervals.h"
33 
34 namespace operations_research {
35 namespace sat {
36 
37 struct Rectangle {
38  IntegerValue x_min;
39  IntegerValue x_max;
40  IntegerValue y_min;
41  IntegerValue y_max;
42 
43  void TakeUnionWith(const Rectangle& other) {
44  x_min = std::min(x_min, other.x_min);
45  y_min = std::min(y_min, other.y_min);
46  x_max = std::max(x_max, other.x_max);
47  y_max = std::max(y_max, other.y_max);
48  }
49 
50  IntegerValue Area() const { return (x_max - x_min) * (y_max - y_min); }
51 
52  bool IsDisjoint(const Rectangle& other) const;
53 
54  std::string DebugString() const {
55  return absl::StrFormat("rectangle(x(%i..%i), y(%i..%i))", x_min.value(),
56  x_max.value(), y_min.value(), y_max.value());
57  }
58 };
59 
60 // Creates a graph when two nodes are connected iff their rectangles overlap.
61 // Then partition into connected components.
62 //
63 // This method removes all singleton components. It will modify the
64 // active_rectangle span in place.
65 std::vector<absl::Span<int>> GetOverlappingRectangleComponents(
66  const std::vector<Rectangle>& rectangles,
67  absl::Span<int> active_rectangles);
68 
69 // Visible for testing. The algo is in O(n^4) so shouldn't be used directly.
70 // Returns true if there exist a bounding box with too much energy.
71 bool BoxesAreInEnergyConflict(const std::vector<Rectangle>& rectangles,
72  const std::vector<IntegerValue>& energies,
73  absl::Span<const int> boxes,
74  Rectangle* conflict = nullptr);
75 
76 // Checks that there is indeed a conflict for the given bounding_box and
77 // report it. This returns false for convenience as we usually want to return
78 // false on a conflict.
79 //
80 // TODO(user): relax the bounding box dimension to have a relaxed explanation.
81 // We can also minimize the number of required intervals.
82 bool ReportEnergyConflict(Rectangle bounding_box, absl::Span<const int> boxes,
83  SchedulingConstraintHelper* x,
84  SchedulingConstraintHelper* y);
85 
86 // A O(n^2) algorithm to analyze all the relevant X intervals and infer a
87 // threshold of the y size of a bounding box after which there is no point
88 // checking for energy overload.
89 //
90 // Returns false on conflict, and fill the bounding box that caused the
91 // conflict.
92 //
93 // If transpose is true, we analyze the relevant Y intervals instead.
94 bool AnalyzeIntervals(bool transpose, absl::Span<const int> boxes,
95  const std::vector<Rectangle>& rectangles,
96  const std::vector<IntegerValue>& rectangle_energies,
97  IntegerValue* x_threshold, IntegerValue* y_threshold,
98  Rectangle* conflict = nullptr);
99 
100 // Removes boxes with a size above the thresholds. Also randomize the order.
101 // Because we rely on various heuristic, this allow to change the order from
102 // one call to the next.
103 absl::Span<int> FilterBoxesAndRandomize(
104  const std::vector<Rectangle>& cached_rectangles, absl::Span<int> boxes,
105  IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random);
106 
107 // Given the total energy of all rectangles (sum of energies[box]) we know that
108 // any box with an area greater than that cannot participate in any "bounding
109 // box" conflict. As we remove this box, the total energy decrease, so we might
110 // remove more. This works in O(n log n).
111 absl::Span<int> FilterBoxesThatAreTooLarge(
112  const std::vector<Rectangle>& cached_rectangles,
113  const std::vector<IntegerValue>& energies, absl::Span<int> boxes);
114 
116  int index;
117  IntegerValue start;
118  IntegerValue end;
119 
120  bool operator==(const IndexedInterval& rhs) const {
121  return std::tie(start, end, index) ==
122  std::tie(rhs.start, rhs.end, rhs.index);
123  }
124 
125  // NOTE(user): We would like to use TUPLE_DEFINE_STRUCT, but sadly it doesn't
126  // support //buildenv/target:non_prod.
128  bool operator()(const IndexedInterval& a, const IndexedInterval& b) const {
129  return std::tie(a.start, a.end, a.index) <
130  std::tie(b.start, b.end, b.index);
131  }
132  };
134  bool operator()(const IndexedInterval& a, const IndexedInterval& b) const {
135  return a.start < b.start;
136  }
137  };
138 };
139 std::ostream& operator<<(std::ostream& out, const IndexedInterval& interval);
140 
141 // Given n fixed intervals, returns the subsets of intervals that overlap during
142 // at least one time unit. Note that we only return "maximal" subset and filter
143 // subset strictly included in another.
144 //
145 // All Intervals must have a positive size.
146 //
147 // The algo is in O(n log n) + O(result_size) which is usually O(n^2).
148 void ConstructOverlappingSets(bool already_sorted,
149  std::vector<IndexedInterval>* intervals,
150  std::vector<std::vector<int>>* result);
151 
152 // Given n intervals, returns the set of connected components (using the overlap
153 // relation between 2 intervals). Components are sorted by their start, and
154 // inside a component, the intervals are also sorted by start.
155 // `intervals` is only sorted (by start), and not modified otherwise.
157  std::vector<IndexedInterval>* intervals,
158  std::vector<std::vector<int>>* components);
159 
160 // Similar to GetOverlappingIntervalComponents(), but returns the indices of
161 // all intervals whose removal would create one more connected component in the
162 // interval graph. Those are sorted by start. See:
163 // https://en.wikipedia.org/wiki/Glossary_of_graph_theory#articulation_point.
164 std::vector<int> GetIntervalArticulationPoints(
165  std::vector<IndexedInterval>* intervals);
166 
167 // This class is used by the no_overlap_2d constraint to maintain the envelope
168 // of a set of rectangles. This envelope is not the convex hull, but the exact
169 // polyline (aligned with the x and y axis) that contains all the rectangles
170 // passed with the AddRectangle() call.
172  public:
173  // Simple start of a rectangle. This is used to represent the residual
174  // capacity profile.
175  struct Rectangle {
176  Rectangle(IntegerValue start, IntegerValue height)
177  : start(start), height(height) {}
178 
179  bool operator<(const Rectangle& other) const { return start < other.start; }
180  bool operator==(const Rectangle& other) const {
181  return start == other.start && height == other.height;
182  }
183 
184  IntegerValue start = IntegerValue(0);
185  IntegerValue height = IntegerValue(0);
186  };
187 
188  void Clear();
189 
190  // Adds a rectangle to the current shape.
191  void AddRectangle(IntegerValue x_min, IntegerValue x_max, IntegerValue y_min,
192  IntegerValue y_max);
193 
194  // Adds a mandatory profile consumption. All mandatory usages will be
195  // subtracted from the y_max-y_min profile to build the residual capacity.
196  void AddMandatoryConsumption(IntegerValue x_min, IntegerValue x_max,
197  IntegerValue y_height);
198 
199  // Returns the profile of the function:
200  // capacity(x) = max(y_max of rectangles overlapping x) - min(y_min of
201  // rectangle overlapping x) - sum(y_height of mandatory rectangles
202  // overlapping x) where a rectangle overlaps x if x_min <= x < x_max.
203  //
204  // Note the profile can contain negative heights in case the mandatory part
205  // exceeds the range on the y axis.
206  //
207  // Note that it adds a sentinel (kMinIntegerValue, 0) at the start. It is
208  // useful when we reverse the direction on the x axis.
209  void BuildResidualCapacityProfile(std::vector<Rectangle>* result);
210 
211  // Returns the exact area of the bounding polyline of all rectangles added.
212  //
213  // Note that this will redo the computation each time.
214  IntegerValue GetBoundingArea();
215 
216  private:
217  // Type for the capacity events.
218  enum EventType { START_RECTANGLE, END_RECTANGLE, CHANGE_MANDATORY_PROFILE };
219 
220  // Individual events.
221  struct Event {
222  IntegerValue time;
223  IntegerValue y_min;
224  IntegerValue y_max;
225  EventType type;
226  int index;
227 
228  const bool operator<(const Event& other) const { return time < other.time; }
229  };
230 
231  // Element of the integer_pq heap.
232  struct QueueElement {
233  int Index() const { return index; }
234  const bool operator<(const QueueElement& o) const {
235  return value < o.value;
236  }
237 
238  int index;
239  IntegerValue value;
240  };
241 
242  static Event StartRectangleEvent(int index, IntegerValue x_min,
243  IntegerValue y_min, IntegerValue y_max) {
244  return {x_min, y_min, y_max, START_RECTANGLE, index};
245  }
246 
247  static Event EndRectangleEvent(int index, IntegerValue x_max) {
248  return {x_max, kMinIntegerValue, kMinIntegerValue, END_RECTANGLE, index};
249  }
250 
251  static Event ChangeMandatoryProfileEvent(IntegerValue x, IntegerValue delta) {
252  return {x, /*y_min=*/delta, /*y_max=*/kMinIntegerValue,
253  CHANGE_MANDATORY_PROFILE, /*index=*/-1};
254  }
255 
256  std::vector<Event> events_;
257  int num_rectangles_added_ = 0;
258 };
259 
260 } // namespace sat
261 } // namespace operations_research
262 
263 #endif // OR_TOOLS_SAT_DIFFN_UTIL_H_
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
void AddMandatoryConsumption(IntegerValue x_min, IntegerValue x_max, IntegerValue y_height)
Definition: diffn_util.cc:507
void AddRectangle(IntegerValue x_min, IntegerValue x_max, IntegerValue y_min, IntegerValue y_max)
Definition: diffn_util.cc:496
void BuildResidualCapacityProfile(std::vector< Rectangle > *result)
Definition: diffn_util.cc:517
int64_t b
int64_t a
int64_t value
int index
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Definition: cp_model.cc:88
std::vector< int > GetIntervalArticulationPoints(std::vector< IndexedInterval > *intervals)
Definition: diffn_util.cc:443
void GetOverlappingIntervalComponents(std::vector< IndexedInterval > *intervals, std::vector< std::vector< int >> *components)
Definition: diffn_util.cc:410
std::vector< absl::Span< int > > GetOverlappingRectangleComponents(const std::vector< Rectangle > &rectangles, absl::Span< int > active_rectangles)
Definition: diffn_util.cc:41
absl::Span< int > FilterBoxesAndRandomize(const std::vector< Rectangle > &cached_rectangles, absl::Span< int > boxes, IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random)
Definition: diffn_util.cc:318
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
void ConstructOverlappingSets(bool already_sorted, std::vector< IndexedInterval > *intervals, std::vector< std::vector< int >> *result)
Definition: diffn_util.cc:361
bool AnalyzeIntervals(bool transpose, absl::Span< const int > local_boxes, const std::vector< Rectangle > &rectangles, const std::vector< IntegerValue > &rectangle_energies, IntegerValue *x_threshold, IntegerValue *y_threshold, Rectangle *conflict)
Definition: diffn_util.cc:166
bool ReportEnergyConflict(Rectangle bounding_box, absl::Span< const int > boxes, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y)
Definition: diffn_util.cc:67
bool BoxesAreInEnergyConflict(const std::vector< Rectangle > &rectangles, const std::vector< IntegerValue > &energies, absl::Span< const int > boxes, Rectangle *conflict)
Definition: diffn_util.cc:99
absl::Span< int > FilterBoxesThatAreTooLarge(const std::vector< Rectangle > &cached_rectangles, const std::vector< IntegerValue > &energies, absl::Span< int > boxes)
Definition: diffn_util.cc:334
Collection of objects used to extend the Constraint Solver library.
int64_t time
Definition: resource.cc:1694
int64_t delta
Definition: resource.cc:1695
IntervalVar * interval
Definition: resource.cc:101
bool operator<(const Rectangle &other) const
Definition: diffn_util.h:179
bool operator==(const Rectangle &other) const
Definition: diffn_util.h:180
Rectangle(IntegerValue start, IntegerValue height)
Definition: diffn_util.h:176
bool operator()(const IndexedInterval &a, const IndexedInterval &b) const
Definition: diffn_util.h:134
bool operator()(const IndexedInterval &a, const IndexedInterval &b) const
Definition: diffn_util.h:128
bool operator==(const IndexedInterval &rhs) const
Definition: diffn_util.h:120
std::string DebugString() const
Definition: diffn_util.h:54
void TakeUnionWith(const Rectangle &other)
Definition: diffn_util.h:43