00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef PPL_Interval_defs_hh
00025 #define PPL_Interval_defs_hh 1
00026
00027 #include "globals.defs.hh"
00028 #include "meta_programming.hh"
00029 #include "assign_or_swap.hh"
00030 #include "intervals.defs.hh"
00031 #include "Interval.types.hh"
00032 #include "Interval_Info.defs.hh"
00033 #include <iosfwd>
00034
00035
00036 #include <iostream>
00037
00038 namespace Parma_Polyhedra_Library {
00039
00040 enum Ternary { T_YES, T_NO, T_MAYBE };
00041
00042 inline I_Result
00043 combine(Result l, Result u) {
00044 return static_cast<I_Result>(l | (u << 6));
00045 }
00046
00047 struct Interval_Base {
00048 };
00049
00050 using namespace Boundary_NS;
00051 using namespace Interval_NS;
00052
00053 template <typename T, typename Enable = void>
00054 struct Is_Singleton : public Is_Native_Or_Checked<T> {};
00055
00056 template <typename T>
00057 struct Is_Interval : public Is_Same_Or_Derived<Interval_Base, T> {};
00058
00059
00060 template <typename From>
00061 typename Enable_If<Is_Interval<From>::value, I_Result>::type
00062 neg_assign(From& x);
00063
00065
00089 template <typename Boundary, typename Info>
00090 class Interval : public Interval_Base, private Info {
00091 private:
00092 PPL_COMPILE_TIME_CHECK(!Info::store_special
00093 || !std::numeric_limits<Boundary>::has_infinity,
00094 "store_special is meaningless"
00095 " when boundary type may contains infinity");
00096 Info& w_info() const {
00097 return const_cast<Interval&>(*this);
00098 }
00099 Result lower_normalize() const {
00100 Result r;
00101 if (info().get_boundary_property(LOWER, NORMALIZED)
00102 || info().get_boundary_property(LOWER, SPECIAL))
00103 r = V_EQ;
00104 else {
00105 Boundary& l = const_cast<Boundary&>(lower());
00106 if (info().get_boundary_property(LOWER, OPEN)) {
00107 r = info().restrict(round_dir_check(LOWER, true), l, V_GT);
00108 if (r != V_GT)
00109 w_info().set_boundary_property(LOWER, OPEN, false);
00110 }
00111 else {
00112 r = info().restrict(round_dir_check(LOWER, true), l, V_GE);
00113 if (r == V_GT)
00114 w_info().set_boundary_property(LOWER, OPEN);
00115 }
00116 w_info().set_boundary_property(LOWER, NORMALIZED);
00117 }
00118 return r;
00119 }
00120 Result upper_normalize() const {
00121 Result r;
00122 if (info().get_boundary_property(UPPER, NORMALIZED)
00123 || info().get_boundary_property(UPPER, SPECIAL))
00124 r = V_EQ;
00125 else {
00126 Boundary& u = const_cast<Boundary&>(upper());
00127 if (info().get_boundary_property(UPPER, OPEN)) {
00128 r = info().restrict(round_dir_check(UPPER, true), u, V_LT);
00129 if (r != V_LT)
00130 w_info().set_boundary_property(UPPER, OPEN, false);
00131 }
00132 else {
00133 r = info().restrict(round_dir_check(UPPER, true), u, V_LE);
00134 if (r == V_LT)
00135 w_info().set_boundary_property(UPPER, OPEN);
00136 }
00137 w_info().set_boundary_property(UPPER, NORMALIZED);
00138 }
00139 return r;
00140 }
00141
00142
00143 public:
00144 typedef Boundary boundary_type;
00145 typedef Info info_type;
00146
00147 typedef Interval_NS::Property Property;
00148
00149 template <typename T>
00150 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
00151 operator=(const T& x) {
00152 assign(x);
00153 return *this;
00154 }
00155
00156 template <typename T>
00157 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
00158 operator+=(const T& x) {
00159 add_assign(*this, x);
00160 return *this;
00161 }
00162 template <typename T>
00163 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
00164 operator-=(const T& x) {
00165 sub_assign(*this, x);
00166 return *this;
00167 }
00168 template <typename T>
00169 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
00170 operator*=(const T& x) {
00171 mul_assign(*this, x);
00172 return *this;
00173 }
00174 template <typename T>
00175 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
00176 operator/=(const T& x) {
00177 div_assign(*this, x);
00178 return *this;
00179 }
00180
00182 void swap(Interval& y);
00183
00184 Info& info() {
00185 return *this;
00186 }
00187
00188 const Info& info() const {
00189 return *this;
00190 }
00191
00192 Boundary& lower() {
00193 return lower_;
00194 }
00195
00196 const Boundary& lower() const {
00197 return lower_;
00198 }
00199
00200 Boundary& upper() {
00201 return upper_;
00202 }
00203
00204 const Boundary& upper() const {
00205 return upper_;
00206 }
00207
00208 I_Constraint<boundary_type> lower_constraint() const {
00209 PPL_ASSERT(!is_empty());
00210 if (info().get_boundary_property(LOWER, SPECIAL))
00211 return I_Constraint<boundary_type>();
00212 return i_constraint(lower_is_open() ? GREATER_THAN : GREATER_OR_EQUAL, lower(), true);
00213 }
00214 I_Constraint<boundary_type> upper_constraint() const {
00215 PPL_ASSERT(!is_empty());
00216 if (info().get_boundary_property(UPPER, SPECIAL))
00217 return I_Constraint<boundary_type>();
00218 return i_constraint(upper_is_open() ? LESS_THAN : LESS_OR_EQUAL, upper(), true);
00219 }
00220
00221 bool has_restriction() const {
00222 return info().has_restriction();
00223 }
00224
00225 I_Result normalize() const {
00226 PPL_ASSERT(OK());
00227 if (has_restriction()) {
00228 Result rl = lower_normalize();
00229 Result ru = upper_normalize();
00230 info().normalize();
00231 PPL_ASSERT(OK());
00232 return combine(rl, ru);
00233 }
00234 else
00235 return combine(V_EQ, V_EQ);
00236 }
00237
00238 bool is_empty() const {
00239 return lt(UPPER, upper(), info(), LOWER, lower(), info());
00240 }
00241
00242 bool check_empty(I_Result r) const {
00243 return (r & I_ANY) == I_EMPTY
00244 || ((r & I_ANY) != I_NOT_EMPTY && is_empty());
00245 }
00246
00247 bool is_singleton() const {
00248 return eq(LOWER, lower(), info(), UPPER, upper(), info());
00249 }
00250
00251 bool lower_is_open() const {
00252 PPL_ASSERT(OK());
00253 return is_open(LOWER, lower(), info());
00254 }
00255
00256 bool upper_is_open() const {
00257 PPL_ASSERT(OK());
00258 return is_open(UPPER, upper(), info());
00259 }
00260
00261 bool lower_is_boundary_infinity() const {
00262 PPL_ASSERT(OK());
00263 return Boundary_NS::is_boundary_infinity(LOWER, lower(), info());
00264 }
00265
00266 bool upper_is_boundary_infinity() const {
00267 PPL_ASSERT(OK());
00268 return Boundary_NS::is_boundary_infinity(UPPER, upper(), info());
00269 }
00270
00271 bool lower_is_domain_inf() const {
00272 PPL_ASSERT(OK());
00273 return Boundary_NS::is_domain_inf(LOWER, lower(), info());
00274 }
00275
00276 bool upper_is_domain_sup() const {
00277 PPL_ASSERT(OK());
00278 return Boundary_NS::is_domain_sup(UPPER, upper(), info());
00279 }
00280
00281 bool is_bounded() const {
00282 PPL_ASSERT(OK());
00283 return !lower_is_boundary_infinity() && !upper_is_boundary_infinity();
00284 }
00285
00286 bool is_universe() const {
00287 PPL_ASSERT(OK());
00288 return lower_is_domain_inf() && upper_is_domain_sup()
00289 && !has_restriction();
00290 }
00291
00292 I_Result lower_extend() {
00293 info().clear_boundary_properties(LOWER);
00294 set_unbounded(LOWER, lower(), info());
00295 return I_ANY;
00296 }
00297
00298 template <typename C>
00299 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type
00300 lower_extend(const C& c);
00301
00302 I_Result upper_extend() {
00303 info().clear_boundary_properties(UPPER);
00304 set_unbounded(UPPER, upper(), info());
00305 return I_ANY;
00306 }
00307
00308 template <typename C>
00309 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type
00310 upper_extend(const C& c);
00311
00312 I_Result build() {
00313 return assign(UNIVERSE);
00314 }
00315
00316 template <typename C>
00317 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type
00318 build(const C& c) {
00319 Relation_Symbol rs;
00320 switch (c.rel()) {
00321 case V_LGE:
00322 case V_GT_MINUS_INFINITY:
00323 case V_LT_PLUS_INFINITY:
00324 return assign(UNIVERSE);
00325 default:
00326 return assign(EMPTY);
00327 case V_LT:
00328 case V_LE:
00329 case V_GT:
00330 case V_GE:
00331 case V_EQ:
00332 case V_NE:
00333 assign(UNIVERSE);
00334 rs = (Relation_Symbol) c.rel();
00335 return refine_existential(rs, c.value());
00336 }
00337 }
00338
00339 template <typename C1, typename C2>
00340 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C1>::value
00341 &&
00342 Is_Same_Or_Derived<I_Constraint_Base, C2>::value,
00343 I_Result>::type
00344 build(const C1& c1, const C2& c2) {
00345 switch (c1.rel()) {
00346 case V_LGE:
00347 return build(c2);
00348 case V_NAN:
00349 return assign(EMPTY);
00350 default:
00351 break;
00352 }
00353 switch (c2.rel()) {
00354 case V_LGE:
00355 return build(c1);
00356 case V_NAN:
00357 return assign(EMPTY);
00358 default:
00359 break;
00360 }
00361 build(c1);
00362 I_Result r = add_constraint(c2);
00363 return r - (I_CHANGED | I_UNCHANGED);
00364 }
00365
00366 template <typename C>
00367 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type
00368 add_constraint(const C& c) {
00369 Interval x;
00370 x.build(c);
00371 return intersect_assign(x);
00372 }
00373
00374 I_Result assign(Degenerate_Element e) {
00375 I_Result r;
00376 info().clear();
00377 switch (e) {
00378 default:
00379 PPL_ASSERT(0);
00380
00381 case EMPTY:
00382 lower_ = 1;
00383 upper_ = 0;
00384 r = I_EMPTY | I_EXACT;
00385 break;
00386 case UNIVERSE:
00387 set_unbounded(LOWER, lower(), info());
00388 set_unbounded(UPPER, upper(), info());
00389 r = I_UNIVERSE | I_EXACT;
00390 break;
00391 }
00392 PPL_ASSERT(OK());
00393 return r;
00394 }
00395
00396 template <typename From>
00397 typename Enable_If<Is_Special<From>::value, I_Result>::type
00398 assign(const From&) {
00399 info().clear();
00400 Result rl, ru;
00401 switch (From::vclass) {
00402 case VC_MINUS_INFINITY:
00403 rl = Boundary_NS::set_minus_infinity(LOWER, lower(), info());
00404 ru = Boundary_NS::set_minus_infinity(UPPER, upper(), info());
00405 break;
00406 case VC_PLUS_INFINITY:
00407 rl = Boundary_NS::set_plus_infinity(LOWER, lower(), info());
00408 ru = Boundary_NS::set_plus_infinity(UPPER, upper(), info());
00409 break;
00410 default:
00411 PPL_ASSERT(0);
00412 rl = V_NAN;
00413 ru = V_NAN;
00414 }
00415 PPL_ASSERT(OK());
00416 return combine(rl, ru);
00417 }
00418
00419 I_Result set_infinities() {
00420 info().clear();
00421
00422 Result rl = Boundary_NS::set_minus_infinity(LOWER, lower(), info());
00423 Result ru = Boundary_NS::set_plus_infinity(UPPER, upper(), info());
00424 PPL_ASSERT(OK());
00425 return combine(rl, ru);
00426 }
00427
00428 static bool is_always_topologically_closed() {
00429 return !Info::store_open;
00430 }
00431
00432 bool is_topologically_closed() const {
00433 PPL_ASSERT(OK());
00434 return is_always_topologically_closed()
00435 || is_empty()
00436 || ((lower_is_boundary_infinity() || !lower_is_open())
00437 && (upper_is_boundary_infinity() || !upper_is_open()));
00438 }
00439
00441 void topological_closure_assign() {
00442 if (!Info::store_open || is_empty())
00443 return;
00444 if (lower_is_open() && !lower_is_boundary_infinity())
00445 info().set_boundary_property(LOWER, OPEN, false);
00446 if (upper_is_open() && !upper_is_boundary_infinity())
00447 info().set_boundary_property(UPPER, OPEN, false);
00448 }
00449
00450 void remove_inf() {
00451 PPL_ASSERT(!is_empty());
00452 if (!Info::store_open)
00453 return;
00454 info().set_boundary_property(LOWER, OPEN, true);
00455 }
00456
00457 void remove_sup() {
00458 PPL_ASSERT(!is_empty());
00459 if (!Info::store_open)
00460 return;
00461 info().set_boundary_property(UPPER, OPEN, true);
00462 }
00463
00464 bool is_infinity() const {
00465 PPL_ASSERT(OK());
00466 if (is_reverse_infinity(LOWER, lower(), info()))
00467 return 1;
00468 else if (is_reverse_infinity(UPPER, upper(), info()))
00469 return -1;
00470 else
00471 return 0;
00472 }
00473
00474 bool contains_integer_point() const {
00475 PPL_ASSERT(OK());
00476 if (is_empty())
00477 return false;
00478 if (!is_bounded())
00479 return true;
00480 Boundary l;
00481 if (lower_is_open()) {
00482 add_assign_r(l, lower(), Boundary(1), ROUND_DOWN);
00483 floor_assign_r(l, l, ROUND_DOWN);
00484 }
00485 else
00486 ceil_assign_r(l, lower(), ROUND_DOWN);
00487 Boundary u;
00488 if (upper_is_open()) {
00489 sub_assign_r(u, upper(), Boundary(1), ROUND_UP);
00490 ceil_assign_r(u, u, ROUND_UP);
00491 }
00492 else
00493 floor_assign_r(u, upper(), ROUND_UP);
00494 return u >= l;
00495 }
00496
00497 void drop_some_non_integer_points() {
00498 if (is_empty())
00499 return;
00500 if (lower_is_open() && !lower_is_boundary_infinity()) {
00501 add_assign_r(lower(), lower(), Boundary(1), ROUND_DOWN);
00502 floor_assign_r(lower(), lower(), ROUND_DOWN);
00503 info().set_boundary_property(LOWER, OPEN, false);
00504 }
00505 else
00506 ceil_assign_r(lower(), lower(), ROUND_DOWN);
00507 if (upper_is_open() && !upper_is_boundary_infinity()) {
00508 sub_assign_r(upper(), upper(), Boundary(1), ROUND_UP);
00509 ceil_assign_r(upper(), upper(), ROUND_UP);
00510 info().set_boundary_property(UPPER, OPEN, false);
00511 }
00512 else
00513 floor_assign_r(upper(), upper(), ROUND_UP);
00514 }
00515
00516 template <typename From>
00517 typename Enable_If<Is_Singleton<From>::value || Is_Interval<From>::value, I_Result>::type
00518 wrap_assign(Bounded_Integer_Type_Width w,
00519 Bounded_Integer_Type_Representation r,
00520 const From& refinement) {
00521 if (is_empty())
00522 return I_EMPTY;
00523 if (lower_is_boundary_infinity() || upper_is_boundary_infinity())
00524 return assign(refinement);
00525 PPL_DIRTY_TEMP(Boundary, u);
00526 Result result = sub_2exp_assign_r(u, upper(), w, ROUND_UP);
00527 if (!result_overflow(result) && u > lower())
00528 return assign(refinement);
00529 info().clear();
00530 switch (r) {
00531 case UNSIGNED:
00532 umod_2exp_assign(LOWER, lower(), info(),
00533 LOWER, lower(), info(), w);
00534 umod_2exp_assign(UPPER, upper(), info(),
00535 UPPER, upper(), info(), w);
00536 break;
00537 case SIGNED_2_COMPLEMENT:
00538 smod_2exp_assign(LOWER, lower(), info(),
00539 LOWER, lower(), info(), w);
00540 smod_2exp_assign(UPPER, upper(), info(),
00541 UPPER, upper(), info(), w);
00542 break;
00543 default:
00544 PPL_ASSERT(false);
00545 break;
00546 }
00547 if (le(LOWER, lower(), info(), UPPER, upper(), info()))
00548 return intersect_assign(refinement);
00549 PPL_DIRTY_TEMP(Interval, tmp);
00550 tmp.info().clear();
00551 Boundary_NS::assign(LOWER, tmp.lower(), tmp.info(),
00552 LOWER, lower(), info());
00553 set_unbounded(UPPER, tmp.upper(), tmp.info());
00554 tmp.intersect_assign(refinement);
00555 lower_extend();
00556 intersect_assign(refinement);
00557 return join_assign(tmp);
00558 }
00559
00561 memory_size_type total_memory_in_bytes() const;
00562
00564 memory_size_type external_memory_in_bytes() const;
00565
00566 void ascii_dump(std::ostream& s) const;
00567 bool ascii_load(std::istream& s);
00568
00569 bool OK() const {
00570 #if 0
00571 if (!Info::may_be_empty && is_empty()) {
00572 #ifndef NDEBUG
00573 std::cerr << "The interval is unexpectedly empty.\n";
00574 #endif
00575 return false;
00576 }
00577 #endif
00578
00579 if (is_open(LOWER, lower(), info())) {
00580 if (is_plus_infinity(LOWER, lower(), info())) {
00581 #ifndef NDEBUG
00582 std::cerr << "The lower boundary is +inf open.\n";
00583 #endif
00584 }
00585 }
00586 else if (!Info::may_contain_infinity
00587 && (is_minus_infinity(LOWER, lower(), info())
00588 || is_plus_infinity(LOWER, lower(), info()))) {
00589 #ifndef NDEBUG
00590 std::cerr << "The lower boundary is unexpectedly infinity.\n";
00591 #endif
00592 return false;
00593 }
00594 if (!info().get_boundary_property(LOWER, SPECIAL)) {
00595 if (is_not_a_number(lower())) {
00596 #ifndef NDEBUG
00597 std::cerr << "The lower boundary is not a number.\n";
00598 #endif
00599 return false;
00600 }
00601 #if 0
00602 if (info().get_boundary_property(LOWER, NORMALIZED)
00603 && !info().is_restricted(lower())) {
00604 #ifndef NDEBUG
00605 std::cerr << "The lower boundary is marked to be normalized, "
00606 << "but it is not.\n";
00607 #endif
00608 return false;
00609 }
00610 #endif
00611 }
00612
00613 if (is_open(UPPER, upper(), info())) {
00614 if (is_minus_infinity(UPPER, upper(), info())) {
00615 #ifndef NDEBUG
00616 std::cerr << "The upper boundary is -inf open.\n";
00617 #endif
00618 }
00619 }
00620 else if (!Info::may_contain_infinity
00621 && (is_minus_infinity(UPPER, upper(), info())
00622 || is_plus_infinity(UPPER, upper(), info()))) {
00623 #ifndef NDEBUG
00624 std::cerr << "The upper boundary is unexpectedly infinity."
00625 << std::endl;
00626 #endif
00627 return false;
00628 }
00629 if (!info().get_boundary_property(UPPER, SPECIAL)) {
00630 if (is_not_a_number(upper())) {
00631 #ifndef NDEBUG
00632 std::cerr << "The upper boundary is not a number.\n";
00633 #endif
00634 return false;
00635 }
00636 #if 0
00637 if (info().get_boundary_property(UPPER, NORMALIZED)
00638 && !info().is_restricted(upper())) {
00639 #ifndef NDEBUG
00640 std::cerr << "The upper boundary is marked to be normalized, "
00641 << "but it is not.\n";
00642 #endif
00643 return false;
00644 }
00645 #endif
00646 }
00647
00648
00649 return true;
00650 }
00651
00652 Interval() {
00653 }
00654
00655 template <typename T>
00656 explicit Interval(const T& x) {
00657 assign(x);
00658 }
00659
00664 explicit Interval(const char* s);
00665
00666 template <typename T>
00667 typename Enable_If<Is_Singleton<T>::value
00668 || Is_Interval<T>::value, bool>::type
00669 contains(const T& y) const;
00670
00671 template <typename T>
00672 typename Enable_If<Is_Singleton<T>::value
00673 || Is_Interval<T>::value, bool>::type
00674 strictly_contains(const T& y) const;
00675
00676 template <typename T>
00677 typename Enable_If<Is_Singleton<T>::value
00678 || Is_Interval<T>::value, bool>::type
00679 is_disjoint_from(const T& y) const;
00680
00681
00682 template <typename From>
00683 typename Enable_If<Is_Singleton<From>::value
00684 || Is_Interval<From>::value, I_Result>::type
00685 assign(const From& x);
00686
00687 template <typename Type>
00688 typename Enable_If<Is_Singleton<Type>::value
00689 || Is_Interval<Type>::value, bool>::type
00690 can_be_exactly_joined_to(const Type& x) const;
00691
00692 template <typename From>
00693 typename Enable_If<Is_Singleton<From>::value
00694 || Is_Interval<From>::value, I_Result>::type
00695 join_assign(const From& x);
00696
00697 template <typename From1, typename From2>
00698 typename Enable_If<((Is_Singleton<From1>::value
00699 || Is_Interval<From1>::value)
00700 && (Is_Singleton<From2>::value
00701 || Is_Interval<From2>::value)), I_Result>::type
00702 join_assign(const From1& x, const From2& y);
00703
00704 template <typename From>
00705 typename Enable_If<Is_Singleton<From>::value
00706 || Is_Interval<From>::value, I_Result>::type
00707 intersect_assign(const From& x);
00708
00709 template <typename From1, typename From2>
00710 typename Enable_If<((Is_Singleton<From1>::value
00711 || Is_Interval<From1>::value)
00712 && (Is_Singleton<From2>::value
00713 || Is_Interval<From2>::value)), I_Result>::type
00714 intersect_assign(const From1& x, const From2& y);
00715
00720 template <typename From>
00721 typename Enable_If<Is_Singleton<From>::value
00722 || Is_Interval<From>::value, I_Result>::type
00723 difference_assign(const From& x);
00724
00729 template <typename From1, typename From2>
00730 typename Enable_If<((Is_Singleton<From1>::value
00731 || Is_Interval<From1>::value)
00732 && (Is_Singleton<From2>::value
00733 || Is_Interval<From2>::value)), I_Result>::type
00734 difference_assign(const From1& x, const From2& y);
00735
00740 template <typename From>
00741 typename Enable_If<Is_Singleton<From>::value
00742 || Is_Interval<From>::value, I_Result>::type
00743 lower_approximation_difference_assign(const From& x);
00744
00752 template <typename From>
00753 typename Enable_If<Is_Interval<From>::value, bool>::type
00754 simplify_using_context_assign(const From& y);
00755
00764 template <typename From>
00765 typename Enable_If<Is_Interval<From>::value, void>::type
00766 empty_intersection_assign(const From& y);
00767
00783 template <typename From>
00784 typename Enable_If<Is_Singleton<From>::value
00785 || Is_Interval<From>::value, I_Result>::type
00786 refine_existential(Relation_Symbol rel, const From& x);
00787
00803 template <typename From>
00804 typename Enable_If<Is_Singleton<From>::value
00805 || Is_Interval<From>::value, I_Result>::type
00806 refine_universal(Relation_Symbol rel, const From& x);
00807
00808 template <typename From>
00809 typename Enable_If<Is_Singleton<From>::value
00810 || Is_Interval<From>::value, I_Result>::type
00811 neg_assign(const From& x);
00812
00813 template <typename From1, typename From2>
00814 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
00815 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
00816 add_assign(const From1& x, const From2& y);
00817
00818 template <typename From1, typename From2>
00819 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
00820 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
00821 sub_assign(const From1& x, const From2& y);
00822
00823 template <typename From1, typename From2>
00824 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
00825 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
00826 mul_assign(const From1& x, const From2& y);
00827
00828 template <typename From1, typename From2>
00829 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
00830 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
00831 div_assign(const From1& x, const From2& y);
00832
00833 template <typename From, typename Iterator>
00834 typename Enable_If<Is_Interval<From>::value, void>::type
00835 CC76_widening_assign(const From& y, Iterator first, Iterator last);
00836
00837 private:
00838 Boundary lower_;
00839 Boundary upper_;
00840 };
00841
00842 }
00843
00844 #include "Interval.inlines.hh"
00845 #include "Interval.templates.hh"
00846
00847 #endif // !defined(PPL_Interval_defs_hh)