Generated on Mon Sep 17 2012 22:20:34 for Gecode by doxygen 1.8.1.1
mult.hpp
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.org>
5  *
6  * Copyright:
7  * Christian Schulte, 2004
8  *
9  * Last modified:
10  * $Date: 2010-06-03 21:46:55 +1000 (Thu, 03 Jun 2010) $ by $Author: schulte $
11  * $Revision: 11014 $
12  *
13  * This file is part of Gecode, the generic constraint
14  * development environment:
15  * http://www.gecode.org
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 
38 #include <cmath>
39 #include <climits>
40 
42 
43 namespace Gecode { namespace Int { namespace Arithmetic {
44 
45  /*
46  * Arithmetic help functions
47  *
48  */
49 
51  template<class Val>
52  Val m(int x, int y);
53 
55  template<class Val>
56  Val m(int x, double y);
57 
58  template<>
59  forceinline double
60  m(int x, int y) {
61  return static_cast<double>(x)*static_cast<double>(y);
62  }
63 
64  template<>
65  forceinline double
66  m(int x, double y) {
67  return static_cast<double>(x)*y;
68  }
69 
70  template<>
71  forceinline int
72  m(int x, int y) {
73  return x*y;
74  }
75 
77  template<class Val>
78  int c_d_p(int x, Val y);
80  template<class Val>
81  int f_d_p(int x, Val y);
82 
83  template<>
84  forceinline int
85  c_d_p<int>(int x, int y) {
86  assert((x >= 0) && (y >= 0));
87  return (x+y-1)/y;
88  }
89  template<>
90  forceinline int
91  c_d_p<double>(int x, double y) {
92  assert((x >= 0) && (y >= 0));
93  return static_cast<int>(ceil(static_cast<double>(x) / y));
94  }
95  template<>
96  forceinline int
97  f_d_p<int>(int x, int y) {
98  assert((x >= 0) && (y >= 0));
99  return x/y;
100  }
101  template<>
102  forceinline int
103  f_d_p<double>(int x, double y) {
104  assert((x >= 0) && (y >= 0));
105  return static_cast<int>(floor(static_cast<double>(x) / y));
106  }
107 
108 
110  forceinline int
111  f_d(int x, int y) {
112  return static_cast<int>(floor(static_cast<double>(x) /
113  static_cast<double>(y)));
114  }
115 
117  forceinline int
118  c_d(int x, int y) {
119  return static_cast<int>(ceil(static_cast<double>(x) /
120  static_cast<double>(y)));
121  }
122 
124  template<class View>
125  forceinline bool
126  pos(const View& x) {
127  return x.min() > 0;
128  }
130  template<class View>
131  forceinline bool
132  neg(const View& x) {
133  return x.max() < 0;
134  }
136  template<class View>
137  forceinline bool
138  any(const View& x) {
139  return (x.min() <= 0) && (x.max() >= 0);
140  }
141 
142 
143  /*
144  * Propagator for x * y = x
145  *
146  */
147 
148  template<class View, PropCond pc>
150  MultZeroOne<View,pc>::MultZeroOne(Home home, View x0, View x1)
151  : BinaryPropagator<View,pc>(home,x0,x1) {}
152 
153  template<class View, PropCond pc>
156  if (pc == PC_INT_DOM) {
157  return rtest_eq_dom(x,n);
158  } else {
159  return rtest_eq_bnd(x,n);
160  }
161  }
162 
163  template<class View, PropCond pc>
165  MultZeroOne<View,pc>::post(Home home, View x0, View x1) {
166  switch (equal(x0,0)) {
167  case RT_FALSE:
168  GECODE_ME_CHECK(x1.eq(home,1));
169  break;
170  case RT_TRUE:
171  break;
172  case RT_MAYBE:
173  switch (equal(x1,1)) {
174  case RT_FALSE:
175  GECODE_ME_CHECK(x0.eq(home,0));
176  break;
177  case RT_TRUE:
178  break;
179  case RT_MAYBE:
180  (void) new (home) MultZeroOne<View,pc>(home,x0,x1);
181  break;
182  default: GECODE_NEVER;
183  }
184  break;
185  default: GECODE_NEVER;
186  }
187  return ES_OK;
188  }
189 
190  template<class View, PropCond pc>
194  : BinaryPropagator<View,pc>(home,share,p) {}
195 
196  template<class View, PropCond pc>
197  Actor*
198  MultZeroOne<View,pc>::copy(Space& home, bool share) {
199  return new (home) MultZeroOne<View,pc>(home,share,*this);
200  }
201 
202  template<class View, PropCond pc>
203  ExecStatus
205  switch (equal(x0,0)) {
206  case RT_FALSE:
207  GECODE_ME_CHECK(x1.eq(home,1));
208  break;
209  case RT_TRUE:
210  break;
211  case RT_MAYBE:
212  switch (equal(x1,1)) {
213  case RT_FALSE:
214  GECODE_ME_CHECK(x0.eq(home,0));
215  break;
216  case RT_TRUE:
217  break;
218  case RT_MAYBE:
219  return ES_FIX;
220  default: GECODE_NEVER;
221  }
222  break;
223  default: GECODE_NEVER;
224  }
225  return home.ES_SUBSUMED(*this);
226  }
227 
228 
229  /*
230  * Positive bounds consistent multiplication
231  *
232  */
233  template<class Val, class VA, class VB, class VC>
235  prop_mult_plus_bnd(Space& home, Propagator& p, VA x0, VB x1, VC x2) {
236  assert(pos(x0) && pos(x1) && pos(x2));
237  bool mod;
238  do {
239  mod = false;
240  {
241  ModEvent me = x2.lq(home,m<Val>(x0.max(),x1.max()));
242  if (me_failed(me)) return ES_FAILED;
243  mod |= me_modified(me);
244  }
245  {
246  ModEvent me = x2.gq(home,m<Val>(x0.min(),x1.min()));
247  if (me_failed(me)) return ES_FAILED;
248  mod |= me_modified(me);
249  }
250  {
251  ModEvent me = x0.lq(home,f_d_p<Val>(x2.max(),x1.min()));
252  if (me_failed(me)) return ES_FAILED;
253  mod |= me_modified(me);
254  }
255  {
256  ModEvent me = x0.gq(home,c_d_p<Val>(x2.min(),x1.max()));
257  if (me_failed(me)) return ES_FAILED;
258  mod |= me_modified(me);
259  }
260  {
261  ModEvent me = x1.lq(home,f_d_p<Val>(x2.max(),x0.min()));
262  if (me_failed(me)) return ES_FAILED;
263  mod |= me_modified(me);
264  }
265  {
266  ModEvent me = x1.gq(home,c_d_p<Val>(x2.min(),x0.max()));
267  if (me_failed(me)) return ES_FAILED;
268  mod |= me_modified(me);
269  }
270  } while (mod);
271  return x0.assigned() && x1.assigned() ?
272  home.ES_SUBSUMED(p) : ES_FIX;
273  }
274 
275  template<class Val, class VA, class VB, class VC>
277  MultPlusBnd<Val,VA,VB,VC>::MultPlusBnd(Home home, VA x0, VB x1, VC x2)
279  (home,x0,x1,x2) {}
280 
281  template<class Val, class VA, class VB, class VC>
286  (home,share,p) {}
287 
288  template<class Val, class VA, class VB, class VC>
289  Actor*
291  return new (home) MultPlusBnd<Val,VA,VB,VC>(home,share,*this);
292  }
293 
294  template<class Val, class VA, class VB, class VC>
295  ExecStatus
297  return prop_mult_plus_bnd<Val,VA,VB,VC>(home,*this,x0,x1,x2);
298  }
299 
300  template<class Val, class VA, class VB, class VC>
302  MultPlusBnd<Val,VA,VB,VC>::post(Home home, VA x0, VB x1, VC x2) {
303  GECODE_ME_CHECK(x0.gr(home,0));
304  GECODE_ME_CHECK(x1.gr(home,0));
305  GECODE_ME_CHECK(x2.gq(home,(static_cast<double>(x0.min()) *
306  static_cast<double>(x1.min()))));
307  double u = static_cast<double>(x0.max()) * static_cast<double>(x1.max());
308  if (u > INT_MAX) {
309  (void) new (home) MultPlusBnd<double,VA,VB,VC>(home,x0,x1,x2);
310  } else {
311  GECODE_ME_CHECK(x2.lq(home,u));
312  (void) new (home) MultPlusBnd<int,VA,VB,VC>(home,x0,x1,x2);
313  }
314  return ES_OK;
315  }
316 
317 
318  /*
319  * Bounds consistent multiplication
320  *
321  */
322  template<class View>
324  MultBnd<View>::MultBnd(Home home, View x0, View x1, View x2)
325  : TernaryPropagator<View,PC_INT_BND>(home,x0,x1,x2) {}
326 
327  template<class View>
330  : TernaryPropagator<View,PC_INT_BND>(home,share,p) {}
331 
332  template<class View>
333  Actor*
334  MultBnd<View>::copy(Space& home, bool share) {
335  return new (home) MultBnd<View>(home,share,*this);
336  }
337 
338  template<class View>
339  ExecStatus
341  if (pos(x0)) {
342  if (pos(x1) || pos(x2)) goto rewrite_ppp;
343  if (neg(x1) || neg(x2)) goto rewrite_pnn;
344  goto prop_pxx;
345  }
346  if (neg(x0)) {
347  if (neg(x1) || pos(x2)) goto rewrite_nnp;
348  if (pos(x1) || neg(x2)) goto rewrite_npn;
349  goto prop_nxx;
350  }
351  if (pos(x1)) {
352  if (pos(x2)) goto rewrite_ppp;
353  if (neg(x2)) goto rewrite_npn;
354  goto prop_xpx;
355  }
356  if (neg(x1)) {
357  if (pos(x2)) goto rewrite_nnp;
358  if (neg(x2)) goto rewrite_pnn;
359  goto prop_xnx;
360  }
361 
362  assert(any(x0) && any(x1));
363  GECODE_ME_CHECK(x2.lq(home,std::max(m<double>(x0.max(),x1.max()),
364  m<double>(x0.min(),x1.min()))));
365  GECODE_ME_CHECK(x2.gq(home,std::min(m<double>(x0.min(),x1.max()),
366  m<double>(x0.max(),x1.min()))));
367 
368  if (x0.assigned()) {
369  assert((x0.val() == 0) && (x2.val() == 0));
370  return home.ES_SUBSUMED(*this);
371  }
372 
373  if (x1.assigned()) {
374  assert((x1.val() == 0) && (x2.val() == 0));
375  return home.ES_SUBSUMED(*this);
376  }
377 
378  return ES_NOFIX;
379 
380  prop_xpx:
381  std::swap(x0,x1);
382  prop_pxx:
383  assert(pos(x0) && any(x1) && any(x2));
384 
385  GECODE_ME_CHECK(x2.lq(home,m<double>(x0.max(),x1.max())));
386  GECODE_ME_CHECK(x2.gq(home,m<double>(x0.max(),x1.min())));
387 
388  if (pos(x2)) goto rewrite_ppp;
389  if (neg(x2)) goto rewrite_pnn;
390 
391  GECODE_ME_CHECK(x1.lq(home,f_d(x2.max(),x0.min())));
392  GECODE_ME_CHECK(x1.gq(home,c_d(x2.min(),x0.min())));
393 
394  if (x0.assigned() && x1.assigned()) {
395  GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
396  return home.ES_SUBSUMED(*this);
397  }
398 
399  return ES_NOFIX;
400 
401  prop_xnx:
402  std::swap(x0,x1);
403  prop_nxx:
404  assert(neg(x0) && any(x1) && any(x2));
405 
406  GECODE_ME_CHECK(x2.lq(home,m<double>(x0.min(),x1.min())));
407  GECODE_ME_CHECK(x2.gq(home,m<double>(x0.min(),x1.max())));
408 
409  if (pos(x2)) goto rewrite_nnp;
410  if (neg(x2)) goto rewrite_npn;
411 
412  GECODE_ME_CHECK(x1.lq(home,f_d(x2.min(),x0.max())));
413  GECODE_ME_CHECK(x1.gq(home,c_d(x2.max(),x0.max())));
414 
415  if (x0.assigned() && x1.assigned()) {
416  GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
417  return home.ES_SUBSUMED(*this);
418  }
419 
420  return ES_NOFIX;
421 
422  rewrite_ppp:
424  ::post(home(*this),x0,x1,x2)));
425  rewrite_nnp:
427  ::post(home(*this),MinusView(x0),MinusView(x1),x2)));
428  rewrite_pnn:
429  std::swap(x0,x1);
430  rewrite_npn:
432  ::post(home(*this),MinusView(x0),x1,MinusView(x2))));
433  }
434 
435  template<class View>
436  ExecStatus
437  MultBnd<View>::post(Home home, View x0, View x1, View x2) {
438  if (same(x0,x1))
439  return SqrBnd<View>::post(home,x0,x2);
440  if (same(x0,x2))
441  return MultZeroOne<View,PC_INT_BND>::post(home,x0,x1);
442  if (same(x1,x2))
443  return MultZeroOne<View,PC_INT_BND>::post(home,x1,x0);
444  if (pos(x0)) {
445  if (pos(x1) || pos(x2)) goto post_ppp;
446  if (neg(x1) || neg(x2)) goto post_pnn;
447  } else if (neg(x0)) {
448  if (neg(x1) || pos(x2)) goto post_nnp;
449  if (pos(x1) || neg(x2)) goto post_npn;
450  } else if (pos(x1)) {
451  if (pos(x2)) goto post_ppp;
452  if (neg(x2)) goto post_npn;
453  } else if (neg(x1)) {
454  if (pos(x2)) goto post_nnp;
455  if (neg(x2)) goto post_pnn;
456  }
457  {
458  double a =
459  static_cast<double>(x0.min()) * static_cast<double>(x1.min());
460  double b =
461  static_cast<double>(x0.min()) * static_cast<double>(x1.max());
462  double c =
463  static_cast<double>(x0.max()) * static_cast<double>(x1.min());
464  double d =
465  static_cast<double>(x0.max()) * static_cast<double>(x1.max());
466  GECODE_ME_CHECK(x2.gq(home,std::min(std::min(a,b),std::min(c,d))));
467  GECODE_ME_CHECK(x2.lq(home,std::max(std::max(a,b),std::max(c,d))));
468  (void) new (home) MultBnd<View>(home,x0,x1,x2);
469  }
470  return ES_OK;
471 
472  post_ppp:
474  post_nnp:
476  MinusView(x0),MinusView(x1),x2);
477  post_pnn:
478  std::swap(x0,x1);
479  post_npn:
481  MinusView(x0),x1,MinusView(x2));
482  }
483 
484 
485  /*
486  * Positive domain consistent multiplication
487  *
488  */
489  template<class Val, class View>
491  prop_mult_dom(Space& home, Propagator& p, View x0, View x1, View x2) {
492  Region r(home);
493  SupportValues<View,Region> s0(r,x0), s1(r,x1), s2(r,x2);
494  while (s0()) {
495  while (s1()) {
496  if (s2.support(m<Val>(s0.val(),s1.val()))) {
497  s0.support(); s1.support();
498  }
499  ++s1;
500  }
501  s1.reset(); ++s0;
502  }
503  GECODE_ME_CHECK(s0.tell(home));
504  GECODE_ME_CHECK(s1.tell(home));
505  GECODE_ME_CHECK(s2.tell(home));
506  return x0.assigned() && x1.assigned() ? home.ES_SUBSUMED(p) : ES_FIX;
507  }
508 
509  template<class Val, class VA, class VB, class VC>
511  MultPlusDom<Val,VA,VB,VC>::MultPlusDom(Home home, VA x0, VB x1, VC x2)
513  (home,x0,x1,x2) {}
514 
515  template<class Val, class VA, class VB, class VC>
520  (home,share,p) {}
521 
522  template<class Val, class VA, class VB, class VC>
523  Actor*
525  return new (home) MultPlusDom<Val,VA,VB,VC>(home,share,*this);
526  }
527 
528  template<class Val, class VA, class VB, class VC>
529  PropCost
531  const ModEventDelta& med) const {
532  if (VA::me(med) == ME_INT_DOM)
534  else
536  }
537 
538  template<class Val, class VA, class VB, class VC>
539  ExecStatus
541  if (VA::me(med) != ME_INT_DOM) {
542  GECODE_ES_CHECK((prop_mult_plus_bnd<Val,VA,VB,VC>(home,*this,x0,x1,x2)));
543  return home.ES_FIX_PARTIAL(*this,VA::med(ME_INT_DOM));
544  }
545  IntView y0(x0.varimp()), y1(x1.varimp()), y2(x2.varimp());
546  return prop_mult_dom<Val,IntView>(home,*this,y0,y1,y2);
547  }
548 
549  template<class Val, class VA, class VB, class VC>
551  MultPlusDom<Val,VA,VB,VC>::post(Home home, VA x0, VB x1, VC x2) {
552  GECODE_ME_CHECK(x0.gr(home,0));
553  GECODE_ME_CHECK(x1.gr(home,0));
554  GECODE_ME_CHECK(x2.gq(home,(static_cast<double>(x0.min()) *
555  static_cast<double>(x1.min()))));
556  double u = static_cast<double>(x0.max()) * static_cast<double>(x1.max());
557  if (u > INT_MAX) {
558  (void) new (home) MultPlusDom<double,VA,VB,VC>(home,x0,x1,x2);
559  } else {
560  GECODE_ME_CHECK(x2.lq(home,u));
561  (void) new (home) MultPlusDom<int,VA,VB,VC>(home,x0,x1,x2);
562  }
563  return ES_OK;
564  }
565 
566 
567  /*
568  * Bounds consistent multiplication
569  *
570  */
571  template<class View>
573  MultDom<View>::MultDom(Home home, View x0, View x1, View x2)
574  : TernaryPropagator<View,PC_INT_DOM>(home,x0,x1,x2) {}
575 
576  template<class View>
579  : TernaryPropagator<View,PC_INT_DOM>(home,share,p) {}
580 
581  template<class View>
582  Actor*
583  MultDom<View>::copy(Space& home, bool share) {
584  return new (home) MultDom<View>(home,share,*this);
585  }
586 
587  template<class View>
588  PropCost
589  MultDom<View>::cost(const Space&, const ModEventDelta& med) const {
590  if (View::me(med) == ME_INT_DOM)
592  else
594  }
595 
596  template<class View>
597  ExecStatus
599  if (View::me(med) != ME_INT_DOM) {
600  if (pos(x0)) {
601  if (pos(x1) || pos(x2)) goto rewrite_ppp;
602  if (neg(x1) || neg(x2)) goto rewrite_pnn;
603  goto prop_pxx;
604  }
605  if (neg(x0)) {
606  if (neg(x1) || pos(x2)) goto rewrite_nnp;
607  if (pos(x1) || neg(x2)) goto rewrite_npn;
608  goto prop_nxx;
609  }
610  if (pos(x1)) {
611  if (pos(x2)) goto rewrite_ppp;
612  if (neg(x2)) goto rewrite_npn;
613  goto prop_xpx;
614  }
615  if (neg(x1)) {
616  if (pos(x2)) goto rewrite_nnp;
617  if (neg(x2)) goto rewrite_pnn;
618  goto prop_xnx;
619  }
620 
621  assert(any(x0) && any(x1));
622  GECODE_ME_CHECK(x2.lq(home,std::max(m<double>(x0.max(),x1.max()),
623  m<double>(x0.min(),x1.min()))));
624  GECODE_ME_CHECK(x2.gq(home,std::min(m<double>(x0.min(),x1.max()),
625  m<double>(x0.max(),x1.min()))));
626 
627  if (x0.assigned()) {
628  assert((x0.val() == 0) && (x2.val() == 0));
629  return home.ES_SUBSUMED(*this);
630  }
631 
632  if (x1.assigned()) {
633  assert((x1.val() == 0) && (x2.val() == 0));
634  return home.ES_SUBSUMED(*this);
635  }
636 
637  return home.ES_NOFIX_PARTIAL(*this,View::med(ME_INT_DOM));
638 
639  prop_xpx:
640  std::swap(x0,x1);
641  prop_pxx:
642  assert(pos(x0) && any(x1) && any(x2));
643 
644  GECODE_ME_CHECK(x2.lq(home,m<double>(x0.max(),x1.max())));
645  GECODE_ME_CHECK(x2.gq(home,m<double>(x0.max(),x1.min())));
646 
647  if (pos(x2)) goto rewrite_ppp;
648  if (neg(x2)) goto rewrite_pnn;
649 
650  GECODE_ME_CHECK(x1.lq(home,f_d(x2.max(),x0.min())));
651  GECODE_ME_CHECK(x1.gq(home,c_d(x2.min(),x0.min())));
652 
653  if (x0.assigned() && x1.assigned()) {
654  GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
655  return home.ES_SUBSUMED(*this);
656  }
657 
658  return home.ES_NOFIX_PARTIAL(*this,View::med(ME_INT_DOM));
659 
660  prop_xnx:
661  std::swap(x0,x1);
662  prop_nxx:
663  assert(neg(x0) && any(x1) && any(x2));
664 
665  GECODE_ME_CHECK(x2.lq(home,m<double>(x0.min(),x1.min())));
666  GECODE_ME_CHECK(x2.gq(home,m<double>(x0.min(),x1.max())));
667 
668  if (pos(x2)) goto rewrite_nnp;
669  if (neg(x2)) goto rewrite_npn;
670 
671  GECODE_ME_CHECK(x1.lq(home,f_d(x2.min(),x0.max())));
672  GECODE_ME_CHECK(x1.gq(home,c_d(x2.max(),x0.max())));
673 
674  if (x0.assigned() && x1.assigned()) {
675  GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
676  return home.ES_SUBSUMED(*this);
677  }
678 
679  return home.ES_NOFIX_PARTIAL(*this,View::med(ME_INT_DOM));
680 
681  rewrite_ppp:
683  ::post(home(*this),x0,x1,x2)));
684  rewrite_nnp:
686  ::post(home(*this),
687  MinusView(x0),MinusView(x1),x2)));
688  rewrite_pnn:
689  std::swap(x0,x1);
690  rewrite_npn:
692  ::post(home(*this),
693  MinusView(x0),x1,MinusView(x2))));
694  }
695  return prop_mult_dom<double,View>(home,*this,x0,x1,x2);
696  }
697 
698  template<class View>
699  ExecStatus
700  MultDom<View>::post(Home home, View x0, View x1, View x2) {
701  if (same(x0,x1))
702  return SqrDom<View>::post(home,x0,x2);
703  if (same(x0,x2))
704  return MultZeroOne<View,PC_INT_DOM>::post(home,x0,x1);
705  if (same(x1,x2))
706  return MultZeroOne<View,PC_INT_DOM>::post(home,x1,x0);
707  if (pos(x0)) {
708  if (pos(x1) || pos(x2)) goto post_ppp;
709  if (neg(x1) || neg(x2)) goto post_pnn;
710  } else if (neg(x0)) {
711  if (neg(x1) || pos(x2)) goto post_nnp;
712  if (pos(x1) || neg(x2)) goto post_npn;
713  } else if (pos(x1)) {
714  if (pos(x2)) goto post_ppp;
715  if (neg(x2)) goto post_npn;
716  } else if (neg(x1)) {
717  if (pos(x2)) goto post_nnp;
718  if (neg(x2)) goto post_pnn;
719  }
720  {
721  double a =
722  static_cast<double>(x0.min()) * static_cast<double>(x1.min());
723  double b =
724  static_cast<double>(x0.min()) * static_cast<double>(x1.max());
725  double c =
726  static_cast<double>(x0.max()) * static_cast<double>(x1.min());
727  double d =
728  static_cast<double>(x0.max()) * static_cast<double>(x1.max());
729  GECODE_ME_CHECK(x2.gq(home,std::min(std::min(a,b),std::min(c,d))));
730  GECODE_ME_CHECK(x2.lq(home,std::max(std::max(a,b),std::max(c,d))));
731  (void) new (home) MultDom<View>(home,x0,x1,x2);
732  }
733  return ES_OK;
734 
735  post_ppp:
737  post_nnp:
739  MinusView(x0),MinusView(x1),x2);
740  post_pnn:
741  std::swap(x0,x1);
742  post_npn:
744  MinusView(x0),x1,MinusView(x2));
745  }
746 
747 }}}
748 
749 // STATISTICS: int-prop
750