14#ifndef OR_TOOLS_SAT_DIFFN_UTIL_H_
15#define OR_TOOLS_SAT_DIFFN_UTIL_H_
27#include "absl/container/flat_hash_set.h"
28#include "absl/container/inlined_vector.h"
29#include "absl/log/check.h"
30#include "absl/random/bit_gen_ref.h"
31#include "absl/strings/str_format.h"
32#include "absl/types/span.h"
47 x_min = std::min(x_min, other.x_min);
48 y_min = std::min(y_min, other.y_min);
49 x_max = std::max(x_max, other.x_max);
50 y_max = std::max(y_max, other.y_max);
55 IntegerValue
SizeX()
const {
return x_max - x_min; }
56 IntegerValue
SizeY()
const {
return y_max - y_min; }
58 bool IsDisjoint(
const Rectangle& other)
const;
61 Rectangle Intersect(
const Rectangle& other)
const;
62 IntegerValue IntersectArea(
const Rectangle& other)
const;
66 absl::InlinedVector<Rectangle, 4> SetDifference(
const Rectangle& other)
const;
68 template <
typename Sink>
70 absl::Format(&sink,
"rectangle(x(%i..%i), y(%i..%i))", r.x_min.value(),
71 r.x_max.value(), r.y_min.value(), r.y_max.value());
75 return std::tie(x_min, x_max, y_min, y_max) ==
76 std::tie(other.x_min, other.x_max, other.y_min, other.y_max);
80 return Rectangle{.x_min = IntegerValue(0),
81 .x_max = IntegerValue(0),
82 .y_min = IntegerValue(0),
83 .y_max = IntegerValue(0)};
87inline Rectangle Rectangle::Intersect(
const Rectangle& other)
const {
88 const IntegerValue ret_x_min = std::max(x_min, other.x_min);
89 const IntegerValue ret_y_min = std::max(y_min, other.y_min);
90 const IntegerValue ret_x_max = std::min(x_max, other.x_max);
91 const IntegerValue ret_y_max = std::min(y_max, other.y_max);
93 if (ret_x_min >= ret_x_max || ret_y_min >= ret_y_max) {
96 return Rectangle{.x_min = ret_x_min,
103inline IntegerValue Rectangle::IntersectArea(
const Rectangle& other)
const {
104 const IntegerValue ret_x_min = std::max(x_min, other.x_min);
105 const IntegerValue ret_y_min = std::max(y_min, other.y_min);
106 const IntegerValue ret_x_max = std::min(x_max, other.x_max);
107 const IntegerValue ret_y_max = std::min(y_max, other.y_max);
109 if (ret_x_min >= ret_x_max || ret_y_min >= ret_y_max) {
112 return (ret_x_max - ret_x_min) * (ret_y_max - ret_y_min);
122 absl::Span<const Rectangle> rectangles, absl::Span<int> active_rectangles);
127 const std::vector<IntegerValue>& energies,
128 absl::Span<const int> boxes,
129 Rectangle* conflict =
nullptr);
150 absl::Span<const Rectangle> rectangles,
151 absl::Span<const IntegerValue> rectangle_energies,
152 IntegerValue* x_threshold, IntegerValue* y_threshold,
153 Rectangle* conflict =
nullptr);
159 absl::Span<const Rectangle> cached_rectangles, absl::Span<int> boxes,
160 IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random);
167 absl::Span<const Rectangle> cached_rectangles,
168 absl::Span<const IntegerValue> energies, absl::Span<int> boxes);
184 return std::tie(
a.start,
a.end,
a.index) <
185 std::tie(
b.start,
b.end,
b.index);
190 return a.start <
b.start;
204 std::vector<IndexedInterval>* intervals,
205 std::vector<std::vector<int>>* result);
212 std::vector<IndexedInterval>* intervals,
213 std::vector<std::vector<int>>* components);
220 std::vector<IndexedInterval>* intervals);
239 FIRST_LEFT_OF_SECOND,
240 FIRST_RIGHT_OF_SECOND,
256 absl::Span<const ItemForPairwiseRestriction> items,
257 std::vector<PairwiseRestriction>* result);
262 absl::Span<const ItemForPairwiseRestriction> items,
263 absl::Span<const ItemForPairwiseRestriction> other_items,
264 std::vector<PairwiseRestriction>* result);
283 IntegerValue
start = IntegerValue(0);
290 void AddRectangle(IntegerValue x_min, IntegerValue x_max, IntegerValue y_min,
295 void AddMandatoryConsumption(IntegerValue x_min, IntegerValue x_max,
296 IntegerValue y_height);
308 void BuildResidualCapacityProfile(std::vector<Rectangle>* result);
313 IntegerValue GetBoundingArea();
317 enum EventType { START_RECTANGLE, END_RECTANGLE, CHANGE_MANDATORY_PROFILE };
327 bool operator<(
const Event& other)
const {
return time < other.time; }
331 struct QueueElement {
332 int Index()
const {
return index; }
333 bool operator<(
const QueueElement& o)
const {
return value < o.value; }
339 static Event StartRectangleEvent(
int index, IntegerValue x_min,
340 IntegerValue y_min, IntegerValue y_max) {
341 return {x_min, y_min, y_max, START_RECTANGLE,
index};
344 static Event EndRectangleEvent(
int index, IntegerValue x_max) {
348 static Event ChangeMandatoryProfileEvent(IntegerValue
x, IntegerValue
delta) {
350 CHANGE_MANDATORY_PROFILE, -1};
353 std::vector<Event> events_;
354 int num_rectangles_added_ = 0;
361 IntegerValue range_max, IntegerValue
size,
362 IntegerValue interval_min,
363 IntegerValue interval_max);
384 case Corner::BOTTOM_LEFT:
385 return Rectangle{.x_min = bounding_area.x_min,
386 .x_max = bounding_area.x_min + x_size,
387 .y_min = bounding_area.y_min,
388 .y_max = bounding_area.y_min + y_size};
389 case Corner::TOP_LEFT:
390 return Rectangle{.x_min = bounding_area.x_min,
391 .x_max = bounding_area.x_min + x_size,
392 .y_min = bounding_area.y_max - y_size,
393 .y_max = bounding_area.y_max};
394 case Corner::BOTTOM_RIGHT:
395 return Rectangle{.x_min = bounding_area.x_max - x_size,
396 .x_max = bounding_area.x_max,
397 .y_min = bounding_area.y_min,
398 .y_max = bounding_area.y_min + y_size};
399 case Corner::TOP_RIGHT:
400 return Rectangle{.x_min = bounding_area.x_max - x_size,
401 .x_max = bounding_area.x_max,
402 .y_min = bounding_area.y_max - y_size,
403 .y_max = bounding_area.y_max};
411 IntegerValue smallest_area = std::numeric_limits<IntegerValue>::max();
412 Rectangle best_intersection;
413 for (
int corner_idx = 0; corner_idx < 4; ++corner_idx) {
415 Rectangle intersection = containing_area.Intersect(GetAtCorner(p));
416 const IntegerValue intersection_area = intersection.Area();
417 if (intersection_area == 0) {
418 return Rectangle::GetEmpty();
420 if (intersection_area < smallest_area) {
421 smallest_area = intersection_area;
422 best_intersection = std::move(intersection);
425 return best_intersection;
429 const Rectangle& containing_area)
const {
431 x_size, containing_area.x_min,
432 containing_area.x_max) *
434 y_size, containing_area.y_min,
435 containing_area.y_max);
440 const IntegerValue& min_intersect_x,
441 const IntegerValue& min_intersect_y) {
442 const IntegerValue x_size = original.
x_size;
443 const IntegerValue y_size = original.
y_size;
451 DCHECK_GE(x_size, min_intersect_x);
452 DCHECK_GE(y_size, min_intersect_y);
455 const IntegerValue x_headroom = x_size - min_intersect_x;
456 const IntegerValue y_headroom = y_size - min_intersect_y;
458 result.
bounding_area.x_min = containing_area.x_min - x_headroom;
459 result.
bounding_area.x_max = containing_area.x_max + x_headroom;
460 result.
bounding_area.y_min = containing_area.y_min - y_headroom;
461 result.
bounding_area.y_max = containing_area.y_max + y_headroom;
466 template <
typename Sink>
468 absl::Format(&sink,
"item(size=%vx%v, BB=%v)", r.
x_size, r.
y_size,
494 enum Edge { TOP = 0, LEFT = 1, BOTTOM = 2, RIGHT = 3 };
503 void Shrink(Edge
edge);
505 bool CanShrink(Edge
edge)
const;
510 return !(CanShrink(Edge::BOTTOM) || CanShrink(Edge::LEFT));
515 void ValidateInvariants()
const;
519 return cached_delta_energy_[
edge];
523 IntegerValue GetShrinkDeltaArea(Edge
edge)
const;
525 Rectangle GetCurrentRectangle()
const;
533 const std::vector<RectangleInRange>&
Intervals()
const {
return intervals_; }
541 void CacheShrinkDeltaEnergy(
int dimension);
546 struct IntervalPoint {
551 std::vector<IntervalPoint> interval_points_sorted_by_x_;
552 std::vector<IntervalPoint> interval_points_sorted_by_y_;
556 struct PointsForCoordinate {
557 IntegerValue coordinate;
558 absl::Span<IntervalPoint> items_touching_coordinate;
560 std::vector<PointsForCoordinate> grouped_intervals_sorted_by_x_;
561 std::vector<PointsForCoordinate> grouped_intervals_sorted_by_y_;
563 const std::vector<RectangleInRange>& intervals_;
565 IntegerValue full_energy_;
566 IntegerValue minimum_energy_;
567 IntegerValue probe_area_;
569 int next_indexes_[4];
571 absl::flat_hash_set<int> ranges_touching_both_boundaries_[2];
572 IntegerValue corner_count_[4] = {0, 0, 0, 0};
573 IntegerValue intersect_length_[4] = {0, 0, 0, 0};
574 IntegerValue cached_delta_energy_[4];
596 const std::vector<RectangleInRange>& intervals, absl::BitGenRef random,
597 double temperature,
double candidate_energy_usage_factor);
601std::string
RenderDot(std::optional<Rectangle> bb,
602 absl::Span<const Rectangle>
solution);
608 const Rectangle& bounding_box, std::vector<Rectangle> ocupied_rectangles);
IntegerValue GetShrinkDeltaEnergy(Edge edge) const
How much of GetMinimumEnergy() will change if Shrink() is called.
IntegerValue GetCurrentRectangleArea() const
IntegerValue GetMinimumEnergy() const
const std::vector< RectangleInRange > & Intervals() const
void AppendPairwiseRestrictions(absl::Span< const ItemForPairwiseRestriction > items, std::vector< PairwiseRestriction > *result)
bool BoxesAreInEnergyConflict(const std::vector< Rectangle > &rectangles, const std::vector< IntegerValue > &energies, absl::Span< const int > boxes, Rectangle *conflict)
absl::Span< int > FilterBoxesAndRandomize(absl::Span< const Rectangle > cached_rectangles, absl::Span< int > boxes, IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random)
bool AnalyzeIntervals(bool transpose, absl::Span< const int > local_boxes, absl::Span< const Rectangle > rectangles, absl::Span< const IntegerValue > rectangle_energies, IntegerValue *x_threshold, IntegerValue *y_threshold, Rectangle *conflict)
void ConstructOverlappingSets(bool already_sorted, std::vector< IndexedInterval > *intervals, std::vector< std::vector< int > > *result)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
std::vector< Rectangle > FindEmptySpaces(const Rectangle &bounding_box, std::vector< Rectangle > ocupied_rectangles)
absl::Span< int > FilterBoxesThatAreTooLarge(absl::Span< const Rectangle > cached_rectangles, absl::Span< const IntegerValue > energies, absl::Span< int > boxes)
std::vector< int > GetIntervalArticulationPoints(std::vector< IndexedInterval > *intervals)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
std::string RenderDot(std::optional< Rectangle > bb, absl::Span< const Rectangle > solution)
bool ReportEnergyConflict(Rectangle bounding_box, absl::Span< const int > boxes, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y)
std::vector< absl::Span< int > > GetOverlappingRectangleComponents(absl::Span< const Rectangle > rectangles, absl::Span< int > active_rectangles)
FindRectanglesResult FindRectanglesWithEnergyConflictMC(const std::vector< RectangleInRange > &intervals, absl::BitGenRef random, double temperature, double candidate_energy_usage_factor)
IntegerValue Smallest1DIntersection(IntegerValue range_min, IntegerValue range_max, IntegerValue size, IntegerValue interval_min, IntegerValue interval_max)
void GetOverlappingIntervalComponents(std::vector< IndexedInterval > *intervals, std::vector< std::vector< int > > *components)
In SWIG mode, we don't want anything besides these top-level includes.
std::optional< int64_t > end
bool operator==(const Rectangle &other) const
bool operator<(const Rectangle &other) const
Rectangle(IntegerValue start, IntegerValue height)
std::vector< Rectangle > conflicts
std::vector< Rectangle > candidates
bool operator()(const IndexedInterval &a, const IndexedInterval &b) const
bool operator()(const IndexedInterval &a, const IndexedInterval &b) const
bool operator==(const IndexedInterval &rhs) const
PairwiseRestrictionType type
bool operator==(const PairwiseRestriction &rhs) const
Rectangle GetMinimumIntersection(const Rectangle &containing_area) const
Returns an empty rectangle if it is possible for no intersection to happen.
Rectangle GetBoudingBox() const
IntegerValue GetMinimumIntersectionArea(const Rectangle &containing_area) const
friend void AbslStringify(Sink &sink, const RectangleInRange &r)
static RectangleInRange BiggestWithMinIntersection(const Rectangle &containing_area, const RectangleInRange &original, const IntegerValue &min_intersect_x, const IntegerValue &min_intersect_y)
Rectangle GetAtCorner(Corner p) const
static Rectangle GetEmpty()
bool operator==(const Rectangle &other) const
void GrowToInclude(const Rectangle &other)
IntegerValue Area() const
IntegerValue SizeY() const
IntegerValue SizeX() const
friend void AbslStringify(Sink &sink, const Rectangle &r)