Generated on for Gecode by doxygen 1.15.0
propagate.cpp
Go to the documentation of this file.
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Christian Schulte <schulte@gecode.dev>
5 *
6 * Contributing authors:
7 * Fabio Tardivo <ftardivo@nmsu.edu>
8 *
9 * Copyright:
10 * Fabio Tardivo, 2024
11 * Christian Schulte, 2010
12 *
13 * This file is part of Gecode, the generic constraint
14 * development environment:
15 * http://www.gecode.dev
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining
18 * a copy of this software and associated documentation files (the
19 * "Software"), to deal in the Software without restriction, including
20 * without limitation the rights to use, copy, modify, merge, publish,
21 * distribute, sublicense, and/or sell copies of the Software, and to
22 * permit persons to whom the Software is furnished to do so, subject to
23 * the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be
26 * included in all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 *
36 */
37
39
40namespace Gecode { namespace Int { namespace BinPacking {
41
42 /*
43 * Packing propagator
44 *
45 */
46
47 PropCost
48 Pack::cost(const Space&, const ModEventDelta&) const {
49 return PropCost::quadratic(PropCost::HI,bs.size());
50 }
51
52 void
54 l.reschedule(home,*this,PC_INT_BND);
55 bs.reschedule(home,*this,PC_INT_DOM);
56 }
57
58 Actor*
60 return new (home) Pack(home,*this);
61 }
62
64 class TellCache {
65 protected:
67 int* _nq;
69 int _n_nq;
71 int _eq;
72 public:
74 TellCache(Region& region, int m);
76 void nq(int j);
78 void eq(int j);
80 ExecStatus tell(Space& home, IntView x);
81 };
82
85 : _nq(region.alloc<int>(m)), _n_nq(0), _eq(-1) {}
86 forceinline void
88 _nq[_n_nq++] = j;
89 }
90 forceinline void
92 // For eq: -1 mean not yet assigned, -2 means failure, positive means value
93 if (_eq == -1)
94 _eq = j;
95 else
96 _eq = -2;
97 }
100 if (_eq == -2) {
101 return ES_FAILED;
102 } else if (_eq >= 0) {
103 GECODE_ME_CHECK(x.eq(home,_eq));
104 }
106 GECODE_ME_CHECK(x.minus_v(home, nqi));
107 _n_nq=0; _eq=-1;
108 return ES_OK;
109 }
110
111
112 /*
113 * Propagation proper
114 *
115 */
118 // Number of items
119 int n = bs.size();
120 // Number of bins
121 int m = l.size();
122
123 Region region;
124 {
125
126 // Possible sizes for bins
127 int* s = region.alloc<int>(m);
128
129 for (int j=0; j<m; j++)
130 s[j] = 0;
131
132 // Compute sizes for bins
133 if (OffsetView::me(med) == ME_INT_VAL) {
134 // Also eliminate assigned items
135 int k=0;
136 for (int i=0; i<n; i++)
137 if (bs[i].assigned()) {
138 int j = bs[i].bin().val();
139 l[j].offset(l[j].offset() - bs[i].size());
140 t -= bs[i].size();
141 } else {
142 for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
143 s[j.val()] += bs[i].size();
144 bs[k++] = bs[i];
145 }
146 n=k; bs.size(n);
147 } else {
148 for (int i=0; i<n; i++) {
149 assert(!bs[i].assigned());
150 for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
151 s[j.val()] += bs[i].size();
152 }
153 }
154
155 // Propagate bin loads and compute lower and upper bound
156 int min = t, max = t;
157 for (int j=0; j<m; j++) {
158 GECODE_ME_CHECK(l[j].gq(home,0));
159 GECODE_ME_CHECK(l[j].lq(home,s[j]));
160 min -= l[j].max(); max -= l[j].min();
161 }
162
163 // Propagate that load must be equal to total size
164 for (bool mod = true; mod; ) {
165 mod = false; ModEvent me;
166 for (int j=0; j<m; j++) {
167 int lj_min = l[j].min();
168 me = l[j].gq(home, min + l[j].max());
169 if (me_failed(me))
170 return ES_FAILED;
171 if (me_modified(me)) {
172 max += lj_min - l[j].min(); mod = true;
173 }
174 int lj_max = l[j].max();
175 me = l[j].lq(home, max + l[j].min());
176 if (me_failed(me))
177 return ES_FAILED;
178 if (me_modified(me)) {
179 min += lj_max - l[j].max(); mod = true;
180 }
181 }
182 }
183
184 if (n == 0) {
185 assert(l.assigned());
186 return home.ES_SUBSUMED(*this);
187 }
188
189
190 {
191 TellCache tc(region,m);
192
193 int k=0;
194 for (int i=0; i<n; i++) {
195 for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) {
196 if (bs[i].size() > l[j.val()].max())
197 tc.nq(j.val());
198 if (s[j.val()] - bs[i].size() < l[j.val()].min())
199 tc.eq(j.val());
200 }
201 GECODE_ES_CHECK(tc.tell(home,bs[i].bin()));
202 // Eliminate assigned bin
203 if (bs[i].assigned()) {
204 int j = bs[i].bin().val();
205 l[j].offset(l[j].offset() - bs[i].size());
206 t -= bs[i].size();
207 } else {
208 bs[k++] = bs[i];
209 }
210 }
211 n=k; bs.size(n);
212 }
213 region.free();
214 }
215
216 // Stop after basic propagation unless stronger filtering is requested.
217 if (ba(ipl) == IPL_BASIC)
218 return ES_NOFIX;
219
220 // Only if the propagator is at fixpoint here, continue with the more
221 // expensive stage for propagation.
223 return ES_NOFIX;
224
225 // Now the invariant holds that no more assigned bins exist!
226 {
227
228 // Size of items
229 SizeSetMinusOne* s = region.alloc<SizeSetMinusOne>(m);
230
231 for (int j=0; j<m; j++)
232 s[j] = SizeSetMinusOne(region,n);
233
234 // Set up size information
235 for (int i=0; i<n; i++) {
236 assert(!bs[i].assigned());
237 for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
238 s[j.val()].add(bs[i].size());
239 }
240
241 for (int j=0; j<m; j++) {
242 // Can items still be packed into bin?
243 if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].max()))
244 return ES_FAILED;
245 int ap, bp;
246 // Must there be packed more items into bin?
247 if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].min(),
248 ap, bp))
249 GECODE_ME_CHECK(l[j].gq(home,bp));
250 // Must there be packed less items into bin?
251 if (nosum(static_cast<SizeSet&>(s[j]), l[j].max(), l[j].max(),
252 ap, bp))
253 GECODE_ME_CHECK(l[j].lq(home,ap));
254 }
255
256 TellCache tc(region,m);
257
258 int k=0;
259 for (int i=0; i<n; i++) {
260 assert(!bs[i].assigned());
261 for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) {
262 // Items must be removed in decreasing size!
263 s[j.val()].minus(bs[i].size());
264 // Can item i still be packed into bin j?
265 if (nosum(s[j.val()],
266 l[j.val()].min() - bs[i].size(),
267 l[j.val()].max() - bs[i].size()))
268 tc.nq(j.val());
269 // Must item i be packed into bin j?
270 if (nosum(s[j.val()], l[j.val()].min(), l[j.val()].max()))
271 tc.eq(j.val());
272 }
273 GECODE_ES_CHECK(tc.tell(home,bs[i].bin()));
274 if (bs[i].assigned()) {
275 int j = bs[i].bin().val();
276 l[j].offset(l[j].offset() - bs[i].size());
277 t -= bs[i].size();
278 } else {
279 bs[k++] = bs[i];
280 }
281 }
282 n=k; bs.size(n);
283 region.free();
284 }
285
286 // Perform lower bound checking
287 if (n > 0) {
288
289 {
290 // Allocate auxiliary data
291 int n_bins = l.size();
292 int n_weights_reductions = n_bins + bs.size();
293 int* weights_base_reduction =
294 region.alloc<int>(n_weights_reductions);
295 int* weights_current_reduction =
296 region.alloc<int>(n_weights_reductions);
297 int* delta_reductions = region.alloc<int>(n_reductions);
298 bool full = ba(ipl) != IPL_ADVANCED;
299
300 // Initialize reductions
301 int capacity_base_reduction = 0;
302 calc_reductions(bs, l, weights_base_reduction,
303 capacity_base_reduction, delta_reductions);
304
305 for (int r_idx = 0; r_idx < n_reductions; r_idx += 1) {
306 // Calculate reduction parameters
307 int& delta = delta_reductions[r_idx];
308 long long int capacity_ll =
309 static_cast<long long int>(capacity_base_reduction) + delta;
310
311 if ((capacity_ll > 0) &&
312 (capacity_ll <= std::numeric_limits<int>::max())) {
313 int capacity = static_cast<int>(capacity_ll);
314 // Calculate reduction
315 int n_not_zero_weights = 0;
316 int max_weight = 0;
317 int* weights = weights_current_reduction;
318 for (int w_idx = 0; w_idx < n_weights_reductions; w_idx += 1) {
319 int weight =
320 weights_base_reduction[w_idx] + (w_idx < n_bins ? delta : 0);
321 n_not_zero_weights += weight != 0;
322 max_weight = std::max(max_weight, weight);
323 weights[w_idx] = weight;
324 }
325
326 // Check the small DFF portfolio used by advanced propagation.
327 int lower_bound =
329 (weights, n_weights_reductions, capacity,
330 n_not_zero_weights, max_weight);
331 if (lower_bound > n_bins)
332 return ES_FAILED;
333
334 lower_bound =
336 (weights, n_weights_reductions, capacity,
337 n_not_zero_weights, max_weight);
338 if (lower_bound > n_bins)
339 return ES_FAILED;
340
341 if (full) {
342 // Check the remaining DFFs for full propagation.
343 lower_bound =
345 (weights, n_weights_reductions, capacity,
346 n_not_zero_weights, max_weight);
347 if (lower_bound > n_bins)
348 return ES_FAILED;
349
350 lower_bound =
352 (weights, n_weights_reductions, capacity,
353 n_not_zero_weights, max_weight, true);
354 if (lower_bound > n_bins)
355 return ES_FAILED;
356
357 lower_bound =
359 (weights, n_weights_reductions, capacity,
360 n_not_zero_weights, max_weight, true);
361 if (lower_bound > n_bins)
362 return ES_FAILED;
363
364 lower_bound =
366 (weights, n_weights_reductions, capacity,
367 n_not_zero_weights, max_weight);
368 if (lower_bound > n_bins)
369 return ES_FAILED;
370 }
371 }
372 }
373 }
374 region.free();
375 }
376
377 return ES_NOFIX;
378 }
379
383 // Sort according to size
384 Support::quicksort(&bs[0], bs.size());
385 // Total size of items
386 int s = 0;
387 // Constrain bins
388 for (int i=0; i<bs.size(); i++) {
389 s += bs[i].size();
390 GECODE_ME_CHECK(bs[i].bin().gq(home,0));
391 GECODE_ME_CHECK(bs[i].bin().le(home,l.size()));
392 }
393 // Eliminate zero sized items (which are at the end as the size are sorted)
394 {
395 int n = bs.size();
396 while ((n > 0) && (bs[n-1].size() == 0))
397 n--;
398 bs.size(n);
399 }
400 if (bs.size() == 0) {
401 // No items to be packed
402 for (int i=0; i<l.size(); i++)
403 GECODE_ME_CHECK(l[i].eq(home,0));
404 return ES_OK;
405 } else if (l.size() == 0) {
406 // No bins available
407 return ES_FAILED;
408 } else {
409 // Constrain load
410 for (int j=0; j<l.size(); j++) {
411 GECODE_ME_CHECK(l[j].gq(home,0));
412 GECODE_ME_CHECK(l[j].lq(home,s));
413 }
414 (void) new (home) Pack(home,l,bs,ipl);
415 return ES_OK;
416 }
417 }
418
419 void
422 int* weights_base_reduction,
423 int& capacity_base_reduction,
424 int* delta_reductions) {
425 // Reset values
426 int n_weights_reductions = l.size() + bs.size();
427 for (int w_idx = 0; w_idx < n_weights_reductions; w_idx += 1)
428 weights_base_reduction[w_idx] = 0;
429
430 // R0
431 int n_bins = l.size();
432 int n_items = bs.size();
433 capacity_base_reduction = 0;
434 for (int b_idx = 0; b_idx < n_bins; b_idx += 1)
435 capacity_base_reduction =
436 std::max(capacity_base_reduction, l[b_idx].max());
437 for (int b_idx = 0; b_idx < n_bins; b_idx += 1)
438 weights_base_reduction[b_idx] =
439 capacity_base_reduction - l[b_idx].max();
440 for (int i_idx = 0; i_idx < n_items; i_idx += 1) {
441 bool i_assigned = bs[i_idx].bin().assigned();
442 int i_weight = bs[i_idx].size();
443 if (i_assigned) {
444 int b_idx = bs[i_idx].bin().val();
445 weights_base_reduction[b_idx] += i_weight;
446 } else {
447 weights_base_reduction[n_bins + i_idx] = i_weight;
448 }
449 }
450
451 // RMin, RMax
452 int smallest_virtual_weight = std::numeric_limits<int>::max();
453 for (int b_idx = 0; b_idx < n_bins; b_idx += 1)
454 smallest_virtual_weight =
455 std::min(smallest_virtual_weight, weights_base_reduction[b_idx]);
456 delta_reductions[0] = -smallest_virtual_weight;
457 delta_reductions[1] = 0;
458 delta_reductions[2] = capacity_base_reduction -
459 smallest_virtual_weight - smallest_virtual_weight + 1;
460 }
461
462}}}
463
464// STATISTICS: int-prop
Base-class for both propagators and branchers.
Definition core.hpp:635
static ModEvent me(const ModEventDelta &med)
Definition view.hpp:639
Home class for posting propagators
Definition core.hpp:863
ViewArray< OffsetView > l
Views for load of bins.
static int calc_dff_lower_bound(const int *weights, int n_weights, int capacity, int n_not_zero_weights, int max_weight, bool sanitize=false)
IntPropLevel ipl
Propagation level.
virtual ExecStatus propagate(Space &home, const ModEventDelta &med)
Perform propagation.
ViewArray< Item > bs
Items with bin and size.
int t
Total size of all items.
static int const n_reductions
Reductions.
virtual Actor * copy(Space &home)
Copy propagator during cloning.
Definition propagate.cpp:59
bool nosum(const SizeSet &s, int a, int b, int &ap, int &bp)
Detect non-existence of sums in a .. b.
static ExecStatus post(Home home, ViewArray< OffsetView > &l, ViewArray< Item > &bs, IntPropLevel ipl=IPL_DEF)
Post propagator for loads l and items bs.
virtual PropCost cost(const Space &home, const ModEventDelta &med) const
Cost function.
Definition propagate.cpp:48
Pack(Home home, ViewArray< OffsetView > &l, ViewArray< Item > &bs, IntPropLevel ipl)
Constructor for posting.
static void calc_reductions(const ViewArray< Item > &bs, const ViewArray< OffsetView > &l, int *weights_base_reduction, int &capacity_base_reduction, int *delta_reductions)
virtual void reschedule(Space &home)
Schedule function.
Definition propagate.cpp:53
Size sets with one element discarded.
void minus(int s)
Discard size s.
void add(int s)
Add new size s.
Record tell information.
Definition propagate.cpp:64
int * _nq
Values (sorted) to be pruned from view.
Definition propagate.cpp:67
int _n_nq
Number of values to be pruned.
Definition propagate.cpp:69
TellCache(Region &region, int m)
Initialize cache for at most m values.
Definition propagate.cpp:84
ExecStatus tell(Space &home, IntView x)
Perform tell to view x and reset cache.
Definition propagate.cpp:99
void eq(int j)
Record that view must be equal to j, return false if not possible.
Definition propagate.cpp:91
int _eq
Value to which view should be assigned.
Definition propagate.cpp:71
void nq(int j)
Record that view must be different from j.
Definition propagate.cpp:87
Integer view for integer variables.
Definition view.hpp:129
ModEvent minus_v(Space &home, I &i, bool depends=true)
Remove from domain the values described by i.
Definition int.hpp:206
ModEvent eq(Space &home, int n)
Restrict domain values to be equal to n.
Definition int.hpp:166
Value iterator for integer views.
Definition view.hpp:94
Value iterator for array of integers
static PropCost quadratic(PropCost::Mod m, unsigned int n)
Quadratic complexity for modifier m and size measure n.
Definition core.hpp:4963
@ HI
Expensive.
Definition core.hpp:521
size_t size
The size of the propagator (used during subsumption).
Definition core.hpp:1086
friend class Space
Definition core.hpp:1075
ModEventDelta modeventdelta(void) const
Return the modification event delta.
Definition core.hpp:3629
ModEventDelta med
A set of modification events (used during propagation).
Definition core.hpp:1084
Handle to region.
Definition region.hpp:55
void free(void)
Free allocate memory.
Definition region.hpp:356
T * alloc(long unsigned int n)
Allocate block of n objects of type T from region.
Definition region.hpp:386
Computation spaces.
Definition core.hpp:1775
static ModEvent me(const ModEventDelta &med)
Definition view.hpp:552
View arrays.
Definition array.hpp:255
const int capacity[n_warehouses]
Capacity of a single warehouse.
ExecStatus ES_SUBSUMED(Propagator &p)
Propagator p is subsumed
Definition core.hpp:3672
int ModEventDelta
Modification event deltas.
Definition core.hpp:94
#define GECODE_ME_CHECK(me)
Check whether modification event me is failed, and forward failure.
Definition macros.hpp:52
bool me_failed(ModEvent me)
Check whether modification event me is failed.
Definition modevent.hpp:54
#define GECODE_ES_CHECK(es)
Check whether execution status es is failed or subsumed, and forward failure or subsumption.
Definition macros.hpp:91
bool me_modified(ModEvent me)
Check whether modification event me describes variable modification.
Definition modevent.hpp:59
IntPropLevel
Propagation levels for integer propagators.
Definition int.hh:1008
@ IPL_BASIC
Use basic propagation algorithm.
Definition int.hh:1015
@ IPL_ADVANCED
Use advanced propagation algorithm.
Definition int.hh:1016
void weights(Home home, IntSharedArray elements, IntSharedArray weights, SetVar x, IntVar y)
Post propagator for .
Definition int.cpp:292
Bin-packing propagators
Finite domain integers.
Definition lastval.hh:52
const Gecode::PropCond PC_INT_BND
Propagate when minimum or maximum of a view changes.
Definition var-type.hpp:99
const Gecode::PropCond PC_INT_DOM
Propagate when domain changes.
Definition var-type.hpp:108
const Gecode::ModEvent ME_INT_VAL
Domain operation has resulted in a value (assigned variable).
Definition var-type.hpp:64
const Gecode::ModEvent ME_INT_NONE
Domain operation has not changed domain.
Definition var-type.hpp:62
void quicksort(Type *l, Type *r, Less &less)
Standard quick sort.
Definition sort.hpp:130
Gecode toplevel namespace
void mod(Home home, IntVar x0, IntVar x1, IntVar x2, IntPropLevel ipl=IPL_DEF)
Post propagator for .
IntPropLevel ba(IntPropLevel ipl)
Extract basic or advanced from propagation level.
Definition ipl.hpp:43
void min(Home home, FloatVar x0, FloatVar x1, FloatVar x2)
Post propagator for .
ExecStatus
Definition core.hpp:479
@ ES_OK
Execution is okay.
Definition core.hpp:483
@ ES_FAILED
Execution has resulted in failure.
Definition core.hpp:481
@ ES_NOFIX
Propagation has not computed fixpoint.
Definition core.hpp:482
void max(Home home, FloatVar x0, FloatVar x1, FloatVar x2)
Post propagator for .
int ModEvent
Type for modification events.
Definition core.hpp:67
#define forceinline
Definition config.hpp:141