20#include "absl/strings/str_format.h"
21#include "absl/types/span.h"
34class Diffn :
public Constraint {
36 Diffn(Solver*
const solver,
const std::vector<IntVar*>& x_vars,
37 const std::vector<IntVar*>& y_vars,
const std::vector<IntVar*>& x_size,
38 const std::vector<IntVar*>& y_size,
bool strict)
47 CHECK_EQ(x_vars.size(), y_vars.size());
48 CHECK_EQ(x_vars.size(), x_size.size());
49 CHECK_EQ(x_vars.size(), y_size.size());
54 void Post()
override {
55 Solver*
const s = solver();
56 for (
int i = 0;
i < size_; ++
i) {
58 s,
this, &Diffn::OnBoxRangeChange,
"OnBoxRangeChange", i);
59 x_[
i]->WhenRange(demon);
60 y_[
i]->WhenRange(demon);
61 dx_[
i]->WhenRange(demon);
62 dy_[
i]->WhenRange(demon);
66 if (solver()->
parameters().diffn_use_cumulative() &&
69 Constraint* ct1 =
nullptr;
70 Constraint* ct2 =
nullptr;
84 std::vector<int64_t> size_x;
86 ct1 = MakeCumulativeConstraint(x_, size_x, dy_,
87 max_size_y + max_y - min_y);
90 std::vector<int64_t> size_y;
92 ct2 = MakeCumulativeConstraint(y_, size_y, dx_,
93 max_size_x + max_x - min_x);
97 s->AddConstraint(ct1);
100 s->AddConstraint(ct2);
105 void InitialPropagate()
override {
107 for (
int i = 0;
i < size_; ++
i) {
113 to_propagate_.clear();
114 for (
int i = 0;
i < size_;
i++) {
115 to_propagate_.insert(i);
120 std::string DebugString()
const override {
121 return absl::StrFormat(
122 "Diffn(x = [%s], y = [%s], dx = [%s], dy = [%s]))",
127 void Accept(ModelVisitor*
const visitor)
const override {
141 void PropagateAll() {
142 for (
const int box : to_propagate_) {
144 FailWhenEnergyIsTooLarge(box);
145 PushOverlappingBoxes(box);
147 to_propagate_.clear();
148 fail_stamp_ = solver()->fail_stamp();
151 void OnBoxRangeChange(
int box) {
152 if (solver()->fail_stamp() > fail_stamp_ && !to_propagate_.empty()) {
155 fail_stamp_ = solver()->fail_stamp();
156 to_propagate_.clear();
158 to_propagate_.insert(box);
159 EnqueueDelayedDemon(delayed_demon_);
162 bool CanBoxedOverlap(
int i,
int j)
const {
163 if (AreBoxedDisjoingHorizontallyForSure(i, j) ||
164 AreBoxedDisjoingVerticallyForSure(i, j)) {
170 bool AreBoxedDisjoingHorizontallyForSure(
int i,
int j)
const {
171 return (x_[i]->Min() >= x_[j]->Max() + dx_[j]->Max()) ||
172 (x_[j]->Min() >= x_[i]->Max() + dx_[i]->Max()) ||
173 (!strict_ && (dx_[
i]->Min() == 0 || dx_[j]->Min() == 0));
176 bool AreBoxedDisjoingVerticallyForSure(
int i,
int j)
const {
177 return (y_[i]->Min() >= y_[j]->Max() + dy_[j]->Max()) ||
178 (y_[j]->Min() >= y_[i]->Max() + dy_[i]->Max()) ||
179 (!strict_ && (dy_[
i]->Min() == 0 || dy_[j]->Min() == 0));
183 void FillNeighbors(
int box) {
187 for (
int other = 0; other < size_; ++other) {
188 if (other != box && CanBoxedOverlap(other, box)) {
189 neighbors_.push_back(other);
197 void FailWhenEnergyIsTooLarge(
int box) {
198 int64_t area_min_x = x_[box]->Min();
199 int64_t area_max_x = x_[box]->Max() + dx_[box]->Max();
200 int64_t area_min_y = y_[box]->Min();
201 int64_t area_max_y = y_[box]->Max() + dy_[box]->Max();
202 int64_t sum_of_areas = dx_[box]->Min() * dy_[box]->Min();
205 for (
int i = 0;
i < neighbors_.size(); ++
i) {
206 const int other = neighbors_[
i];
208 area_min_x = std::min(area_min_x, x_[other]->Min());
209 area_max_x = std::max(area_max_x, x_[other]->Max() + dx_[other]->Max());
210 area_min_y = std::min(area_min_y, y_[other]->Min());
211 area_max_y = std::max(area_max_y, y_[other]->Max() + dy_[other]->Max());
213 sum_of_areas += dx_[other]->Min() * dy_[other]->Min();
214 const int64_t bounding_area =
215 (area_max_x - area_min_x) * (area_max_y - area_min_y);
216 if (sum_of_areas > bounding_area) {
225 void PushOverlappingBoxes(
int box) {
226 for (
int i = 0;
i < neighbors_.size(); ++
i) {
227 PushOneBox(box, neighbors_[i]);
234 void PushOneBox(
int box,
int other) {
236 (x_[box]->Min() + dx_[box]->Min() <= x_[other]->Max()) +
237 2 * (x_[other]->Min() + dx_[other]->Min() <= x_[box]->Max()) +
238 4 * (y_[box]->Min() + dy_[box]->Min() <= y_[other]->Max()) +
239 8 * (y_[other]->Min() + dy_[other]->Min() <= y_[box]->Max());
248 x_[other]->SetMin(x_[box]->Min() + dx_[box]->Min());
249 x_[box]->SetMax(x_[other]->Max() - dx_[box]->Min());
250 dx_[box]->SetMax(x_[other]->Max() - x_[box]->Min());
254 x_[box]->SetMin(x_[other]->Min() + dx_[other]->Min());
255 x_[other]->SetMax(x_[box]->Max() - dx_[other]->Min());
256 dx_[other]->SetMax(x_[box]->Max() - x_[other]->Min());
260 y_[other]->SetMin(y_[box]->Min() + dy_[box]->Min());
261 y_[box]->SetMax(y_[other]->Max() - dy_[box]->Min());
262 dy_[box]->SetMax(y_[other]->Max() - y_[box]->Min());
266 y_[box]->SetMin(y_[other]->Min() + dy_[other]->Min());
267 y_[other]->SetMax(y_[box]->Max() - dy_[other]->Min());
268 dy_[other]->SetMax(y_[box]->Max() - y_[other]->Min());
277 Constraint* MakeCumulativeConstraint(
const std::vector<IntVar*>& positions,
278 const std::vector<int64_t>& sizes,
279 const std::vector<IntVar*>& demands,
281 std::vector<IntervalVar*> intervals;
282 solver()->MakeFixedDurationIntervalVarArray(positions, sizes,
"interval",
284 return solver()->MakeCumulative(intervals, demands, capacity,
"cumul");
287 std::vector<IntVar*> x_;
288 std::vector<IntVar*> y_;
289 std::vector<IntVar*> dx_;
290 std::vector<IntVar*> dy_;
293 Demon* delayed_demon_;
294 absl::flat_hash_set<int> to_propagate_;
295 std::vector<int> neighbors_;
296 uint64_t fail_stamp_;
301 const std::vector<IntVar*>& x_vars,
const std::vector<IntVar*>& y_vars,
302 const std::vector<IntVar*>& x_size,
const std::vector<IntVar*>& y_size) {
303 return RevAlloc(
new Diffn(
this, x_vars, y_vars, x_size, y_size,
true));
307 const std::vector<IntVar*>& x_vars,
const std::vector<IntVar*>& y_vars,
308 absl::Span<const int64_t> x_size, absl::Span<const int64_t> y_size) {
309 std::vector<IntVar*> dx(x_size.size());
310 std::vector<IntVar*> dy(y_size.size());
311 for (
int i = 0; i < x_size.size(); ++i) {
315 return RevAlloc(
new Diffn(
this, x_vars, y_vars, dx, dy,
true));
319 const std::vector<IntVar*>& x_vars,
const std::vector<IntVar*>& y_vars,
320 absl::Span<const int> x_size, absl::Span<const int> y_size) {
321 std::vector<IntVar*> dx(x_size.size());
322 std::vector<IntVar*> dy(y_size.size());
323 for (
int i = 0; i < x_size.size(); ++i) {
327 return RevAlloc(
new Diffn(
this, x_vars, y_vars, dx, dy,
true));
331 const std::vector<IntVar*>& x_vars,
const std::vector<IntVar*>& y_vars,
332 const std::vector<IntVar*>& x_size,
const std::vector<IntVar*>& y_size) {
333 return RevAlloc(
new Diffn(
this, x_vars, y_vars, x_size, y_size,
false));
337 const std::vector<IntVar*>& x_vars,
const std::vector<IntVar*>& y_vars,
338 absl::Span<const int64_t> x_size, absl::Span<const int64_t> y_size) {
339 std::vector<IntVar*> dx(x_size.size());
340 std::vector<IntVar*> dy(y_size.size());
341 for (
int i = 0; i < x_size.size(); ++i) {
345 return RevAlloc(
new Diffn(
this, x_vars, y_vars, dx, dy,
false));
349 const std::vector<IntVar*>& x_vars,
const std::vector<IntVar*>& y_vars,
350 absl::Span<const int> x_size, absl::Span<const int> y_size) {
351 std::vector<IntVar*> dx(x_size.size());
352 std::vector<IntVar*> dy(y_size.size());
353 for (
int i = 0; i < x_size.size(); ++i) {
357 return RevAlloc(
new Diffn(
this, x_vars, y_vars, dx, dy,
false));
static const char kPositionXArgument[]
static const char kSizeYArgument[]
static const char kPositionYArgument[]
static const char kDisjunctive[]
static const char kSizeXArgument[]
Constraint * MakeNonOverlappingNonStrictBoxesConstraint(const std::vector< IntVar * > &x_vars, const std::vector< IntVar * > &y_vars, const std::vector< IntVar * > &x_size, const std::vector< IntVar * > &y_size)
Constraint * MakeNonOverlappingBoxesConstraint(const std::vector< IntVar * > &x_vars, const std::vector< IntVar * > &y_vars, const std::vector< IntVar * > &x_size, const std::vector< IntVar * > &y_size)
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
#define DEFINE_INT_TYPE(int_type_name, value_type)
In SWIG mode, we don't want anything besides these top-level includes.
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
int64_t MaxVarArray(const std::vector< IntVar * > &vars)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
void FillValues(const std::vector< IntVar * > &vars, std::vector< int64_t > *const values)
int64_t MinVarArray(const std::vector< IntVar * > &vars)
bool IsArrayInRange(const std::vector< IntVar * > &vars, T range_min, T range_max)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
bool AreAllBound(const std::vector< IntVar * > &vars)