this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Christian Schulte <schulte@gecode.org>
5 *
6 * Copyright:
7 * Christian Schulte, 2012
8 *
9 * This file is part of Gecode, the generic constraint
10 * development environment:
11 * http://www.gecode.org
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sublicense, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 *
32 */
33
34#include <gecode/int/rel.hh>
35
36#include <climits>
37#include <algorithm>
38
39namespace Gecode { namespace Int { namespace Arithmetic {
40
41 /*
42 * Positive bounds consistent nth root
43 *
44 */
45
46 template<class Ops, bool minus>
47 forceinline ExecStatus
48 prop_nroot_plus_bnd(Space& home, IntView x0, IntView x1, const Ops& ops) {
49 if (minus) {
50 bool mod;
51 do {
52 mod = false;
53 {
54 ModEvent me = x1.gq(home,-ops.cnroot(-x0.min()));
55 if (me_failed(me)) return ES_FAILED;
56 mod |= me_modified(me);
57 }
58 {
59 ModEvent me = x1.lq(home,-ops.cnroot(-x0.max()));
60 if (me_failed(me)) return ES_FAILED;
61 mod |= me_modified(me);
62 }
63 {
64 ModEvent me = x0.gq(home,-ops.tpow(-x1.min()));
65 if (me_failed(me)) return ES_FAILED;
66 mod |= me_modified(me);
67 }
68 {
69 ModEvent me = x0.lq(home,-(ops.tpow(-x1.max()-1)+1));
70 if (me_failed(me)) return ES_FAILED;
71 mod |= me_modified(me);
72 }
73 } while (mod);
74 } else {
75 bool mod;
76 do {
77 mod = false;
78 {
79 ModEvent me = x1.lq(home,ops.fnroot(x0.max()));
80 if (me_failed(me)) return ES_FAILED;
81 mod |= me_modified(me);
82 }
83 {
84 ModEvent me = x1.gq(home,ops.fnroot(x0.min()));
85 if (me_failed(me)) return ES_FAILED;
86 mod |= me_modified(me);
87 }
88 {
89 ModEvent me = x0.le(home,ops.tpow(x1.max()+1));
90 if (me_failed(me)) return ES_FAILED;
91 mod |= me_modified(me);
92 }
93 {
94 ModEvent me = x0.gq(home,ops.tpow(x1.min()));
95 if (me_failed(me)) return ES_FAILED;
96 mod |= me_modified(me);
97 }
98 } while (mod);
99 }
100 return ES_OK;
101 }
102
103 template<class Ops, bool minus>
104 forceinline
105 NrootPlusBnd<Ops,minus>::NrootPlusBnd(Home home, IntView x0, IntView x1,
106 const Ops& o)
107 : BinaryPropagator<IntView,PC_INT_BND>(home,x0,x1),
108 ops(o) {}
109
110 template<class Ops, bool minus>
111 forceinline ExecStatus
112 NrootPlusBnd<Ops,minus>::post(Home home, IntView x0, IntView x1, Ops ops) {
113 if (minus) {
114 GECODE_ME_CHECK(x0.lq(home,0));
115 GECODE_ME_CHECK(x1.lq(home,0));
116 } else {
117 GECODE_ME_CHECK(x0.gq(home,0));
118 GECODE_ME_CHECK(x1.gq(home,0));
119 }
120 (void) new (home) NrootPlusBnd<Ops,minus>(home,x0,x1,ops);
121 return ES_OK;
122 }
123
124 template<class Ops, bool minus>
125 forceinline
126 NrootPlusBnd<Ops,minus>::NrootPlusBnd(Space& home,
127 NrootPlusBnd<Ops,minus>& p)
128 : BinaryPropagator<IntView,PC_INT_BND>(home,p),
129 ops(p.ops) {}
130
131 template<class Ops, bool minus>
132 Actor*
133 NrootPlusBnd<Ops,minus>::copy(Space& home) {
134 return new (home) NrootPlusBnd<Ops,minus>(home,*this);
135 }
136
137 template<class Ops, bool minus>
138 ExecStatus
139 NrootPlusBnd<Ops,minus>::propagate(Space& home, const ModEventDelta&) {
140 GECODE_ES_CHECK((prop_nroot_plus_bnd<Ops,minus>(home,x0,x1,ops)));
141 return x1.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX;
142 }
143
144
145 /*
146 * Bounds consistent nth root
147 *
148 */
149
150 template<class Ops>
151 forceinline ExecStatus
152 prop_nroot_bnd(Space& home, IntView x0, IntView x1, const Ops& ops) {
153 assert((x0.min() < 0) && (x0.max() > 0));
154 assert((x1.min() < 0) && (x1.max() > 0));
155
156 GECODE_ME_CHECK(x1.lq(home,ops.fnroot(x0.max())));
157 GECODE_ME_CHECK(x1.gq(home,-ops.cnroot(-x0.min())));
158 GECODE_ME_CHECK(x0.le(home,ops.tpow(x1.max()+1)));
159 GECODE_ME_CHECK(x0.gq(home,ops.tpow(x1.min()-1)+1));
160
161 return ES_OK;
162 }
163
164 template<class Ops>
165 forceinline
166 NrootBnd<Ops>::NrootBnd(Home home, IntView x0, IntView x1, const Ops& o)
167 : BinaryPropagator<IntView,PC_INT_BND>(home,x0,x1),
168 ops(o) {}
169
170 template<class Ops>
171 forceinline ExecStatus
172 NrootBnd<Ops>::post(Home home, IntView x0, IntView x1, Ops ops) {
173 if (static_cast<unsigned int>(ops.exp()) >= sizeof(int) * CHAR_BIT) {
174 // The integer limits allow only -2, -1, 0, 1 for x1
175 GECODE_ME_CHECK(x1.lq(home,1));
176 GECODE_ME_CHECK(x1.gq(home,-2));
177 // Just rewrite to values that can be handeled without overflow
178 ops.exp(ops.even() ? 30 : 31);
179 }
180
181 if (ops.exp() == 0) {
182 GECODE_ME_CHECK(x1.eq(home,1));
183 return ES_OK;
184 } else if (ops.exp() == 1) {
185 return Rel::EqBnd<IntView,IntView>::post(home,x0,x1);
186 }
187
188 if (x0 == x1) {
189 assert(ops.exp() > 1);
190 GECODE_ME_CHECK(x0.lq(home,1));
191 GECODE_ME_CHECK(x0.gq(home,ops.even() ? 0 : -2));
192 return ES_OK;
193 }
194
195 // Limits values such that no overflow can occur
196 GECODE_ME_CHECK(x1.lq(home,ops.fnroot(Limits::max)));
197 GECODE_ME_CHECK(x1.gq(home,-ops.cnroot(-Limits::min)));
198
199 if (ops.even()) {
200 GECODE_ME_CHECK(x0.gq(home,0));
201 GECODE_ME_CHECK(x1.gq(home,0));
202 }
203
204 if ((x0.min() >= 0) || (x1.min() >= 0))
205 return NrootPlusBnd<Ops,false>::post(home,x0,x1,ops);
206
207 if ((x0.max() <= 0) || (x1.max() <= 0))
208 return NrootPlusBnd<Ops,true>::post(home,x0,x1,ops);
209
210 assert((x0.min() < 0) && (x0.max() > 0));
211 assert((x1.min() < 0) && (x1.max() > 0));
212 GECODE_ES_CHECK(prop_nroot_bnd<Ops>(home,x0,x1,ops));
213 (void) new (home) NrootBnd(home,x0,x1,ops);
214 return ES_OK;
215 }
216
217 template<class Ops>
218 forceinline
219 NrootBnd<Ops>::NrootBnd(Space& home, NrootBnd<Ops>& p)
220 : BinaryPropagator<IntView,PC_INT_BND>(home,p),
221 ops(p.ops) {}
222
223 template<class Ops>
224 Actor*
225 NrootBnd<Ops>::copy(Space& home) {
226 return new (home) NrootBnd<Ops>(home,*this);
227 }
228
229 template<class Ops>
230 ExecStatus
231 NrootBnd<Ops>::propagate(Space& home, const ModEventDelta&) {
232 assert(!ops.even());
233 if ((x0.min() >= 0) || (x1.min() >= 0))
234 GECODE_REWRITE(*this,(NrootPlusBnd<Ops,false>::post(home(*this),x0,x1,ops)));
235
236 if ((x0.max() <= 0) || (x1.max() <= 0))
237 GECODE_REWRITE(*this,(NrootPlusBnd<Ops,true>::post(home(*this),x0,x1,ops)));
238
239 GECODE_ES_CHECK(prop_nroot_bnd(home,x0,x1,ops));
240
241 return x0.assigned() && x1.assigned() ? home.ES_SUBSUMED(*this) : ES_NOFIX;
242 }
243
244
245 /*
246 * Domain consistent nth root
247 *
248 */
249 /// Mapping ranges to powers
250 template<class Ops>
251 class RangesMapPow {
252 protected:
253 /// Power operations
254 Ops ops;
255 public:
256 /// Initialize with operations \a o
257 forceinline RangesMapPow(const Ops& o) : ops(o) {}
258 /// Perform mapping of minimum
259 forceinline int min(int x) const {
260 return ops.tpow(x);
261 }
262 /// Perform mapping of maximum
263 forceinline int max(int x) const {
264 return ops.tpow(x+1)-1;
265 }
266 };
267
268 /// Mapping integer to n-th root
269 template<class Ops>
270 class RangesMapNroot {
271 protected:
272 /// Power operations
273 Ops ops;
274 public:
275 /// Initialize with operations \a o
276 forceinline RangesMapNroot(const Ops& o) : ops(o) {}
277 /// Perform mapping of minimum
278 forceinline int min(int x) const {
279 return (x < 0) ? -ops.cnroot(-x) : ops.fnroot(x);
280 }
281 /// Perform mapping of maximum
282 forceinline int max(int x) const {
283 return (x < 0) ? -ops.cnroot(-x) : ops.fnroot(x);
284 }
285 };
286
287 template<class Ops, bool minus>
288 forceinline
289 NrootPlusDom<Ops,minus>::NrootPlusDom(Home home, IntView x0, IntView x1,
290 const Ops& o)
291 : BinaryPropagator<IntView,PC_INT_DOM>(home,x0,x1),
292 ops(o) {}
293
294 template<class Ops, bool minus>
295 forceinline ExecStatus
296 NrootPlusDom<Ops,minus>::post(Home home, IntView x0, IntView x1, Ops ops) {
297 if (minus) {
298 GECODE_ME_CHECK(x0.lq(home,0));
299 GECODE_ME_CHECK(x1.lq(home,0));
300 } else {
301 GECODE_ME_CHECK(x0.gq(home,0));
302 GECODE_ME_CHECK(x1.gq(home,0));
303 }
304 GECODE_ES_CHECK((prop_nroot_plus_bnd<Ops,minus>(home,x0,x1,ops)));
305 (void) new (home) NrootPlusDom<Ops,minus>(home,x0,x1,ops);
306 return ES_OK;
307 }
308
309 template<class Ops, bool minus>
310 forceinline
311 NrootPlusDom<Ops,minus>::NrootPlusDom(Space& home,
312 NrootPlusDom<Ops,minus>& p)
313 : BinaryPropagator<IntView,PC_INT_DOM>(home,p),
314 ops(p.ops) {}
315
316 template<class Ops, bool minus>
317 Actor*
318 NrootPlusDom<Ops,minus>::copy(Space& home) {
319 return new (home) NrootPlusDom<Ops,minus>(home,*this);
320 }
321
322 template<class Ops, bool minus>
323 PropCost
324 NrootPlusDom<Ops,minus>::cost(const Space&, const ModEventDelta& med) const {
325 if (IntView::me(med) == ME_INT_VAL)
326 return PropCost::unary(PropCost::LO);
327 else if (IntView::me(med) == ME_INT_DOM)
328 return PropCost::binary(PropCost::HI);
329 else
330 return PropCost::binary(PropCost::LO);
331 }
332
333 template<class Ops, bool minus>
334 ExecStatus
335 NrootPlusDom<Ops,minus>::propagate(Space& home, const ModEventDelta& med) {
336 if (IntView::me(med) != ME_INT_DOM) {
337 GECODE_ES_CHECK((prop_nroot_plus_bnd<Ops,minus>(home,x0,x1,ops)));
338 return x1.assigned() ? home.ES_SUBSUMED(*this)
339 : home.ES_NOFIX_PARTIAL(*this,IntView::med(ME_INT_DOM));
340 }
341
342 {
343 ViewRanges<IntView> r(x0);
344 RangesMapNroot<Ops> rmn(ops);
345 Iter::Ranges::Map<ViewRanges<IntView>,RangesMapNroot<Ops>,false>
346 m(r,rmn);
347 GECODE_ME_CHECK(x1.inter_r(home,m,false));
348 }
349
350 {
351 ViewRanges<IntView> r(x1);
352 RangesMapPow<Ops> rmp(ops);
353 Iter::Ranges::Map<ViewRanges<IntView>,RangesMapPow<Ops>,true>
354 m(r,rmp);
355 GECODE_ME_CHECK(x0.inter_r(home,m,false));
356 }
357
358 return x1.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX;
359 }
360
361
362
363 template<class Ops>
364 forceinline
365 NrootDom<Ops>::NrootDom(Home home, IntView x0, IntView x1, const Ops& o)
366 : BinaryPropagator<IntView,PC_INT_DOM>(home,x0,x1),
367 ops(o) {}
368
369 template<class Ops>
370 forceinline ExecStatus
371 NrootDom<Ops>::post(Home home, IntView x0, IntView x1, Ops ops) {
372 if (static_cast<unsigned int>(ops.exp()) >= sizeof(int) * CHAR_BIT) {
373 // The integer limits allow only -2, -1, 0, 1 for x1
374 GECODE_ME_CHECK(x1.lq(home,1));
375 GECODE_ME_CHECK(x1.gq(home,-2));
376 // Just rewrite to values that can be handeled without overflow
377 ops.exp(ops.even() ? 30 : 31);
378 }
379
380 if (ops.exp() == 0) {
381 GECODE_ME_CHECK(x1.eq(home,1));
382 return ES_OK;
383 } else if (ops.exp() == 1) {
384 return Rel::EqDom<IntView,IntView>::post(home,x0,x1);
385 }
386
387 if (x0 == x1) {
388 assert(ops.exp() > 1);
389 GECODE_ME_CHECK(x0.lq(home,1));
390 GECODE_ME_CHECK(x0.gq(home,ops.even() ? 0 : -2));
391 return ES_OK;
392 }
393
394 // Limits values such that no overflow can occur
395 GECODE_ME_CHECK(x1.lq(home,ops.fnroot(Limits::max)));
396 GECODE_ME_CHECK(x1.gq(home,-ops.cnroot(-Limits::min)));
397
398 if (ops.even()) {
399 GECODE_ME_CHECK(x0.gq(home,0));
400 GECODE_ME_CHECK(x1.gq(home,0));
401 }
402
403 if ((x0.min() >= 0) || (x1.min() >= 0))
404 return NrootPlusDom<Ops,false>::post(home,x0,x1,ops);
405
406 if ((x0.max() <= 0) || (x1.max() <= 0))
407 return NrootPlusDom<Ops,true>::post(home,x0,x1,ops);
408
409 assert((x0.min() < 0) && (x0.max() > 0));
410 assert((x1.min() < 0) && (x1.max() > 0));
411 GECODE_ES_CHECK(prop_nroot_bnd<Ops>(home,x0,x1,ops));
412 (void) new (home) NrootDom(home,x0,x1,ops);
413 return ES_OK;
414 }
415
416 template<class Ops>
417 forceinline
418 NrootDom<Ops>::NrootDom(Space& home, NrootDom<Ops>& p)
419 : BinaryPropagator<IntView,PC_INT_DOM>(home,p),
420 ops(p.ops) {}
421
422 template<class Ops>
423 Actor*
424 NrootDom<Ops>::copy(Space& home) {
425 return new (home) NrootDom<Ops>(home,*this);
426 }
427
428 template<class Ops>
429 PropCost
430 NrootDom<Ops>::cost(const Space&, const ModEventDelta& med) const {
431 if (IntView::me(med) == ME_INT_VAL)
432 return PropCost::unary(PropCost::LO);
433 else if (IntView::me(med) == ME_INT_DOM)
434 return PropCost::binary(PropCost::HI);
435 else
436 return PropCost::binary(PropCost::LO);
437 }
438
439 template<class Ops>
440 ExecStatus
441 NrootDom<Ops>::propagate(Space& home, const ModEventDelta& med) {
442 assert(!ops.even());
443 if ((x0.min() >= 0) || (x1.min() >= 0))
444 GECODE_REWRITE(*this,(NrootPlusDom<Ops,false>::post(home(*this),x0,x1,ops)));
445
446 if ((x0.max() <= 0) || (x1.max() <= 0))
447 GECODE_REWRITE(*this,(NrootPlusDom<Ops,true>::post(home(*this),x0,x1,ops)));
448
449 if (IntView::me(med) != ME_INT_DOM) {
450 GECODE_ES_CHECK(prop_nroot_bnd<Ops>(home,x0,x1,ops));
451 return x0.assigned() && x1.assigned() ? home.ES_SUBSUMED(*this)
452 : home.ES_NOFIX_PARTIAL(*this,IntView::med(ME_INT_DOM));
453 }
454
455 {
456 ViewRanges<IntView> r(x0);
457 RangesMapNroot<Ops> rmn(ops);
458 Iter::Ranges::Map<ViewRanges<IntView>,RangesMapNroot<Ops>,false>
459 m(r,rmn);
460 GECODE_ME_CHECK(x1.inter_r(home,m,false));
461 }
462
463 {
464 ViewRanges<IntView> r(x1);
465 RangesMapPow<Ops> rmp(ops);
466 Iter::Ranges::Map<ViewRanges<IntView>,RangesMapPow<Ops>,true>
467 m(r,rmp);
468 GECODE_ME_CHECK(x0.inter_r(home,m,false));
469 }
470
471 return x0.assigned() && x1.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX;
472 }
473
474
475}}}
476
477// STATISTICS: int-prop
478