|
PPL
0.12.1
|
00001 /* Declarations for the Interval class and its constituents. 00002 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00003 Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com) 00004 00005 This file is part of the Parma Polyhedra Library (PPL). 00006 00007 The PPL is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 The PPL is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software Foundation, 00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00020 00021 For the most up-to-date information see the Parma Polyhedra Library 00022 site: http://bugseng.com/products/ppl/ . */ 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 // Temporary! 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 unsigned res = static_cast<unsigned>(l) | (static_cast<unsigned>(u) << 6); 00045 return static_cast<I_Result>(res); 00046 } 00047 00048 struct Interval_Base { 00049 }; 00050 00051 using namespace Boundary_NS; 00052 using namespace Interval_NS; 00053 00054 template <typename T, typename Enable = void> 00055 struct Is_Singleton : public Is_Native_Or_Checked<T> {}; 00056 00057 template <typename T> 00058 struct Is_Interval : public Is_Same_Or_Derived<Interval_Base, T> {}; 00059 00061 00082 template <typename Boundary, typename Info> 00083 class Interval : public Interval_Base, private Info { 00084 private: 00085 PPL_COMPILE_TIME_CHECK(!Info::store_special 00086 || !std::numeric_limits<Boundary>::has_infinity, 00087 "store_special is meaningless" 00088 " when boundary type may contains infinity"); 00089 Info& w_info() const { 00090 return const_cast<Interval&>(*this); 00091 } 00092 00093 public: 00094 typedef Boundary boundary_type; 00095 typedef Info info_type; 00096 00097 typedef Interval_NS::Property Property; 00098 00099 template <typename T> 00100 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type 00101 operator=(const T& x) { 00102 assign(x); 00103 return *this; 00104 } 00105 00106 template <typename T> 00107 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type 00108 operator+=(const T& x) { 00109 add_assign(*this, x); 00110 return *this; 00111 } 00112 template <typename T> 00113 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type 00114 operator-=(const T& x) { 00115 sub_assign(*this, x); 00116 return *this; 00117 } 00118 template <typename T> 00119 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type 00120 operator*=(const T& x) { 00121 mul_assign(*this, x); 00122 return *this; 00123 } 00124 template <typename T> 00125 typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type 00126 operator/=(const T& x) { 00127 div_assign(*this, x); 00128 return *this; 00129 } 00130 00132 void m_swap(Interval& y); 00133 00134 Info& info() { 00135 return *this; 00136 } 00137 00138 const Info& info() const { 00139 return *this; 00140 } 00141 00142 Boundary& lower() { 00143 return lower_; 00144 } 00145 00146 const Boundary& lower() const { 00147 return lower_; 00148 } 00149 00150 Boundary& upper() { 00151 return upper_; 00152 } 00153 00154 const Boundary& upper() const { 00155 return upper_; 00156 } 00157 00158 I_Constraint<boundary_type> lower_constraint() const { 00159 PPL_ASSERT(!is_empty()); 00160 if (info().get_boundary_property(LOWER, SPECIAL)) 00161 return I_Constraint<boundary_type>(); 00162 return i_constraint(lower_is_open() ? GREATER_THAN : GREATER_OR_EQUAL, 00163 lower(), true); 00164 } 00165 I_Constraint<boundary_type> upper_constraint() const { 00166 PPL_ASSERT(!is_empty()); 00167 if (info().get_boundary_property(UPPER, SPECIAL)) 00168 return I_Constraint<boundary_type>(); 00169 return i_constraint(upper_is_open() ? LESS_THAN : LESS_OR_EQUAL, 00170 upper(), true); 00171 } 00172 00173 bool is_empty() const { 00174 return lt(UPPER, upper(), info(), LOWER, lower(), info()); 00175 } 00176 00177 bool check_empty(I_Result r) const { 00178 return (r & I_ANY) == I_EMPTY 00179 || ((r & I_ANY) != I_NOT_EMPTY && is_empty()); 00180 } 00181 00182 bool is_singleton() const { 00183 return eq(LOWER, lower(), info(), UPPER, upper(), info()); 00184 } 00185 00186 bool lower_is_open() const { 00187 PPL_ASSERT(OK()); 00188 return is_open(LOWER, lower(), info()); 00189 } 00190 00191 bool upper_is_open() const { 00192 PPL_ASSERT(OK()); 00193 return is_open(UPPER, upper(), info()); 00194 } 00195 00196 bool lower_is_boundary_infinity() const { 00197 PPL_ASSERT(OK()); 00198 return Boundary_NS::is_boundary_infinity(LOWER, lower(), info()); 00199 } 00200 00201 bool upper_is_boundary_infinity() const { 00202 PPL_ASSERT(OK()); 00203 return Boundary_NS::is_boundary_infinity(UPPER, upper(), info()); 00204 } 00205 00206 bool lower_is_domain_inf() const { 00207 PPL_ASSERT(OK()); 00208 return Boundary_NS::is_domain_inf(LOWER, lower(), info()); 00209 } 00210 00211 bool upper_is_domain_sup() const { 00212 PPL_ASSERT(OK()); 00213 return Boundary_NS::is_domain_sup(UPPER, upper(), info()); 00214 } 00215 00216 bool is_bounded() const { 00217 PPL_ASSERT(OK()); 00218 return !lower_is_boundary_infinity() && !upper_is_boundary_infinity(); 00219 } 00220 00221 bool is_universe() const { 00222 PPL_ASSERT(OK()); 00223 return lower_is_domain_inf() && upper_is_domain_sup(); 00224 } 00225 00226 I_Result lower_extend() { 00227 info().clear_boundary_properties(LOWER); 00228 set_unbounded(LOWER, lower(), info()); 00229 return I_ANY; 00230 } 00231 00232 template <typename C> 00233 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type 00234 lower_extend(const C& c); 00235 00236 I_Result upper_extend() { 00237 info().clear_boundary_properties(UPPER); 00238 set_unbounded(UPPER, upper(), info()); 00239 return I_ANY; 00240 } 00241 00242 template <typename C> 00243 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type 00244 upper_extend(const C& c); 00245 00246 I_Result build() { 00247 return assign(UNIVERSE); 00248 } 00249 00250 template <typename C> 00251 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type 00252 build(const C& c) { 00253 Relation_Symbol rs; 00254 switch (c.rel()) { 00255 case V_LGE: 00256 case V_GT_MINUS_INFINITY: 00257 case V_LT_PLUS_INFINITY: 00258 return assign(UNIVERSE); 00259 default: 00260 return assign(EMPTY); 00261 case V_LT: 00262 case V_LE: 00263 case V_GT: 00264 case V_GE: 00265 case V_EQ: 00266 case V_NE: 00267 assign(UNIVERSE); 00268 rs = static_cast<Relation_Symbol>(c.rel()); 00269 return refine_existential(rs, c.value()); 00270 } 00271 } 00272 00273 template <typename C1, typename C2> 00274 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C1>::value 00275 && 00276 Is_Same_Or_Derived<I_Constraint_Base, C2>::value, 00277 I_Result>::type 00278 build(const C1& c1, const C2& c2) { 00279 switch (c1.rel()) { 00280 case V_LGE: 00281 return build(c2); 00282 case V_NAN: 00283 return assign(EMPTY); 00284 default: 00285 break; 00286 } 00287 switch (c2.rel()) { 00288 case V_LGE: 00289 return build(c1); 00290 case V_NAN: 00291 return assign(EMPTY); 00292 default: 00293 break; 00294 } 00295 build(c1); 00296 I_Result r = add_constraint(c2); 00297 return r - (I_CHANGED | I_UNCHANGED); 00298 } 00299 00300 template <typename C> 00301 typename Enable_If<Is_Same_Or_Derived<I_Constraint_Base, C>::value, I_Result>::type 00302 add_constraint(const C& c) { 00303 Interval x; 00304 x.build(c); 00305 return intersect_assign(x); 00306 } 00307 00308 I_Result assign(Degenerate_Element e) { 00309 I_Result r; 00310 info().clear(); 00311 switch (e) { 00312 case EMPTY: 00313 lower_ = 1; 00314 upper_ = 0; 00315 r = I_EMPTY | I_EXACT; 00316 break; 00317 case UNIVERSE: 00318 set_unbounded(LOWER, lower(), info()); 00319 set_unbounded(UPPER, upper(), info()); 00320 r = I_UNIVERSE | I_EXACT; 00321 break; 00322 default: 00323 PPL_UNREACHABLE; 00324 r = I_EMPTY; 00325 break; 00326 } 00327 PPL_ASSERT(OK()); 00328 return r; 00329 } 00330 00331 template <typename From> 00332 typename Enable_If<Is_Special<From>::value, I_Result>::type 00333 assign(const From&) { 00334 info().clear(); 00335 Result rl, ru; 00336 switch (From::vclass) { 00337 case VC_MINUS_INFINITY: 00338 rl = Boundary_NS::set_minus_infinity(LOWER, lower(), info()); 00339 ru = Boundary_NS::set_minus_infinity(UPPER, upper(), info()); 00340 break; 00341 case VC_PLUS_INFINITY: 00342 rl = Boundary_NS::set_plus_infinity(LOWER, lower(), info()); 00343 ru = Boundary_NS::set_plus_infinity(UPPER, upper(), info()); 00344 break; 00345 default: 00346 PPL_UNREACHABLE; 00347 rl = V_NAN; 00348 ru = V_NAN; 00349 break; 00350 } 00351 PPL_ASSERT(OK()); 00352 return combine(rl, ru); 00353 } 00354 00355 I_Result set_infinities() { 00356 info().clear(); 00357 Result rl = Boundary_NS::set_minus_infinity(LOWER, lower(), info()); 00358 Result ru = Boundary_NS::set_plus_infinity(UPPER, upper(), info()); 00359 PPL_ASSERT(OK()); 00360 return combine(rl, ru); 00361 } 00362 00363 static bool is_always_topologically_closed() { 00364 return !Info::store_open; 00365 } 00366 00367 bool is_topologically_closed() const { 00368 PPL_ASSERT(OK()); 00369 return is_always_topologically_closed() 00370 || is_empty() 00371 || ((lower_is_boundary_infinity() || !lower_is_open()) 00372 && (upper_is_boundary_infinity() || !upper_is_open())); 00373 } 00374 00376 void topological_closure_assign() { 00377 if (!Info::store_open || is_empty()) 00378 return; 00379 if (lower_is_open() && !lower_is_boundary_infinity()) 00380 info().set_boundary_property(LOWER, OPEN, false); 00381 if (upper_is_open() && !upper_is_boundary_infinity()) 00382 info().set_boundary_property(UPPER, OPEN, false); 00383 } 00384 00385 void remove_inf() { 00386 PPL_ASSERT(!is_empty()); 00387 if (!Info::store_open) 00388 return; 00389 info().set_boundary_property(LOWER, OPEN, true); 00390 } 00391 00392 void remove_sup() { 00393 PPL_ASSERT(!is_empty()); 00394 if (!Info::store_open) 00395 return; 00396 info().set_boundary_property(UPPER, OPEN, true); 00397 } 00398 00399 int infinity_sign() const { 00400 PPL_ASSERT(OK()); 00401 if (is_reverse_infinity(LOWER, lower(), info())) 00402 return 1; 00403 else if (is_reverse_infinity(UPPER, upper(), info())) 00404 return -1; 00405 else 00406 return 0; 00407 } 00408 00409 bool contains_integer_point() const { 00410 PPL_ASSERT(OK()); 00411 if (is_empty()) 00412 return false; 00413 if (!is_bounded()) 00414 return true; 00415 Boundary l; 00416 if (lower_is_open()) { 00417 add_assign_r(l, lower(), Boundary(1), ROUND_DOWN); 00418 floor_assign_r(l, l, ROUND_DOWN); 00419 } 00420 else 00421 ceil_assign_r(l, lower(), ROUND_DOWN); 00422 Boundary u; 00423 if (upper_is_open()) { 00424 sub_assign_r(u, upper(), Boundary(1), ROUND_UP); 00425 ceil_assign_r(u, u, ROUND_UP); 00426 } 00427 else 00428 floor_assign_r(u, upper(), ROUND_UP); 00429 return u >= l; 00430 } 00431 00432 void drop_some_non_integer_points() { 00433 if (is_empty()) 00434 return; 00435 if (lower_is_open() && !lower_is_boundary_infinity()) { 00436 add_assign_r(lower(), lower(), Boundary(1), ROUND_DOWN); 00437 floor_assign_r(lower(), lower(), ROUND_DOWN); 00438 info().set_boundary_property(LOWER, OPEN, false); 00439 } 00440 else 00441 ceil_assign_r(lower(), lower(), ROUND_DOWN); 00442 if (upper_is_open() && !upper_is_boundary_infinity()) { 00443 sub_assign_r(upper(), upper(), Boundary(1), ROUND_UP); 00444 ceil_assign_r(upper(), upper(), ROUND_UP); 00445 info().set_boundary_property(UPPER, OPEN, false); 00446 } 00447 else 00448 floor_assign_r(upper(), upper(), ROUND_UP); 00449 } 00450 00451 template <typename From> 00452 typename Enable_If<Is_Singleton<From>::value || Is_Interval<From>::value, I_Result>::type 00453 wrap_assign(Bounded_Integer_Type_Width w, 00454 Bounded_Integer_Type_Representation r, 00455 const From& refinement) { 00456 if (is_empty()) 00457 return I_EMPTY; 00458 if (lower_is_boundary_infinity() || upper_is_boundary_infinity()) 00459 return assign(refinement); 00460 PPL_DIRTY_TEMP(Boundary, u); 00461 Result result = sub_2exp_assign_r(u, upper(), w, ROUND_UP); 00462 if (result_overflow(result) == 0 && u > lower()) 00463 return assign(refinement); 00464 info().clear(); 00465 switch (r) { 00466 case UNSIGNED: 00467 umod_2exp_assign(LOWER, lower(), info(), 00468 LOWER, lower(), info(), w); 00469 umod_2exp_assign(UPPER, upper(), info(), 00470 UPPER, upper(), info(), w); 00471 break; 00472 case SIGNED_2_COMPLEMENT: 00473 smod_2exp_assign(LOWER, lower(), info(), 00474 LOWER, lower(), info(), w); 00475 smod_2exp_assign(UPPER, upper(), info(), 00476 UPPER, upper(), info(), w); 00477 break; 00478 default: 00479 PPL_UNREACHABLE; 00480 break; 00481 } 00482 if (le(LOWER, lower(), info(), UPPER, upper(), info())) 00483 return intersect_assign(refinement); 00484 PPL_DIRTY_TEMP(Interval, tmp); 00485 tmp.info().clear(); 00486 Boundary_NS::assign(LOWER, tmp.lower(), tmp.info(), 00487 LOWER, lower(), info()); 00488 set_unbounded(UPPER, tmp.upper(), tmp.info()); 00489 tmp.intersect_assign(refinement); 00490 lower_extend(); 00491 intersect_assign(refinement); 00492 return join_assign(tmp); 00493 } 00494 00496 memory_size_type total_memory_in_bytes() const; 00497 00499 memory_size_type external_memory_in_bytes() const; 00500 00501 void ascii_dump(std::ostream& s) const; 00502 bool ascii_load(std::istream& s); 00503 00504 bool OK() const { 00505 #if 0 00506 if (!Info::may_be_empty && is_empty()) { 00507 #ifndef NDEBUG 00508 std::cerr << "The interval is unexpectedly empty.\n"; 00509 #endif 00510 return false; 00511 } 00512 #endif 00513 00514 if (is_open(LOWER, lower(), info())) { 00515 if (is_plus_infinity(LOWER, lower(), info())) { 00516 #ifndef NDEBUG 00517 std::cerr << "The lower boundary is +inf open.\n"; 00518 #endif 00519 } 00520 } 00521 else if (!Info::may_contain_infinity 00522 && (is_minus_infinity(LOWER, lower(), info()) 00523 || is_plus_infinity(LOWER, lower(), info()))) { 00524 #ifndef NDEBUG 00525 std::cerr << "The lower boundary is unexpectedly infinity.\n"; 00526 #endif 00527 return false; 00528 } 00529 if (!info().get_boundary_property(LOWER, SPECIAL)) { 00530 if (is_not_a_number(lower())) { 00531 #ifndef NDEBUG 00532 std::cerr << "The lower boundary is not a number.\n"; 00533 #endif 00534 return false; 00535 } 00536 } 00537 00538 if (is_open(UPPER, upper(), info())) { 00539 if (is_minus_infinity(UPPER, upper(), info())) { 00540 #ifndef NDEBUG 00541 std::cerr << "The upper boundary is -inf open.\n"; 00542 #endif 00543 } 00544 } 00545 else if (!Info::may_contain_infinity 00546 && (is_minus_infinity(UPPER, upper(), info()) 00547 || is_plus_infinity(UPPER, upper(), info()))) { 00548 #ifndef NDEBUG 00549 std::cerr << "The upper boundary is unexpectedly infinity." 00550 << std::endl; 00551 #endif 00552 return false; 00553 } 00554 if (!info().get_boundary_property(UPPER, SPECIAL)) { 00555 if (is_not_a_number(upper())) { 00556 #ifndef NDEBUG 00557 std::cerr << "The upper boundary is not a number.\n"; 00558 #endif 00559 return false; 00560 } 00561 } 00562 00563 // Everything OK. 00564 return true; 00565 } 00566 00567 Interval() { 00568 } 00569 00570 template <typename T> 00571 explicit Interval(const T& x) { 00572 assign(x); 00573 } 00574 00579 explicit Interval(const char* s); 00580 00581 template <typename T> 00582 typename Enable_If<Is_Singleton<T>::value 00583 || Is_Interval<T>::value, bool>::type 00584 contains(const T& y) const; 00585 00586 template <typename T> 00587 typename Enable_If<Is_Singleton<T>::value 00588 || Is_Interval<T>::value, bool>::type 00589 strictly_contains(const T& y) const; 00590 00591 template <typename T> 00592 typename Enable_If<Is_Singleton<T>::value 00593 || Is_Interval<T>::value, bool>::type 00594 is_disjoint_from(const T& y) const; 00595 00596 00597 template <typename From> 00598 typename Enable_If<Is_Singleton<From>::value 00599 || Is_Interval<From>::value, I_Result>::type 00600 assign(const From& x); 00601 00602 template <typename Type> 00603 typename Enable_If<Is_Singleton<Type>::value 00604 || Is_Interval<Type>::value, bool>::type 00605 can_be_exactly_joined_to(const Type& x) const; 00606 00607 template <typename From> 00608 typename Enable_If<Is_Singleton<From>::value 00609 || Is_Interval<From>::value, I_Result>::type 00610 join_assign(const From& x); 00611 00612 template <typename From1, typename From2> 00613 typename Enable_If<((Is_Singleton<From1>::value 00614 || Is_Interval<From1>::value) 00615 && (Is_Singleton<From2>::value 00616 || Is_Interval<From2>::value)), I_Result>::type 00617 join_assign(const From1& x, const From2& y); 00618 00619 template <typename From> 00620 typename Enable_If<Is_Singleton<From>::value 00621 || Is_Interval<From>::value, I_Result>::type 00622 intersect_assign(const From& x); 00623 00624 template <typename From1, typename From2> 00625 typename Enable_If<((Is_Singleton<From1>::value 00626 || Is_Interval<From1>::value) 00627 && (Is_Singleton<From2>::value 00628 || Is_Interval<From2>::value)), I_Result>::type 00629 intersect_assign(const From1& x, const From2& y); 00630 00635 template <typename From> 00636 typename Enable_If<Is_Singleton<From>::value 00637 || Is_Interval<From>::value, I_Result>::type 00638 difference_assign(const From& x); 00639 00644 template <typename From1, typename From2> 00645 typename Enable_If<((Is_Singleton<From1>::value 00646 || Is_Interval<From1>::value) 00647 && (Is_Singleton<From2>::value 00648 || Is_Interval<From2>::value)), I_Result>::type 00649 difference_assign(const From1& x, const From2& y); 00650 00655 template <typename From> 00656 typename Enable_If<Is_Singleton<From>::value 00657 || Is_Interval<From>::value, I_Result>::type 00658 lower_approximation_difference_assign(const From& x); 00659 00667 template <typename From> 00668 typename Enable_If<Is_Interval<From>::value, bool>::type 00669 simplify_using_context_assign(const From& y); 00670 00675 template <typename From> 00676 typename Enable_If<Is_Interval<From>::value, void>::type 00677 empty_intersection_assign(const From& y); 00678 00694 template <typename From> 00695 typename Enable_If<Is_Singleton<From>::value 00696 || Is_Interval<From>::value, I_Result>::type 00697 refine_existential(Relation_Symbol rel, const From& x); 00698 00714 template <typename From> 00715 typename Enable_If<Is_Singleton<From>::value 00716 || Is_Interval<From>::value, I_Result>::type 00717 refine_universal(Relation_Symbol rel, const From& x); 00718 00719 template <typename From> 00720 typename Enable_If<Is_Singleton<From>::value 00721 || Is_Interval<From>::value, I_Result>::type 00722 neg_assign(const From& x); 00723 00724 template <typename From1, typename From2> 00725 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value) 00726 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type 00727 add_assign(const From1& x, const From2& y); 00728 00729 template <typename From1, typename From2> 00730 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value) 00731 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type 00732 sub_assign(const From1& x, const From2& y); 00733 00734 template <typename From1, typename From2> 00735 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value) 00736 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type 00737 mul_assign(const From1& x, const From2& y); 00738 00739 template <typename From1, typename From2> 00740 typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value) 00741 && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type 00742 div_assign(const From1& x, const From2& y); 00743 00744 template <typename From, typename Iterator> 00745 typename Enable_If<Is_Interval<From>::value, void>::type 00746 CC76_widening_assign(const From& y, Iterator first, Iterator last); 00747 00748 private: 00749 Boundary lower_; 00750 Boundary upper_; 00751 }; 00752 00754 00755 template <typename Boundary, typename Info> 00756 void swap(Interval<Boundary, Info>& x, Interval<Boundary, Info>& y); 00757 00758 } // namespace Parma_Polyhedra_Library 00759 00760 #include "Interval.inlines.hh" 00761 #include "Interval.templates.hh" 00762 00763 #endif // !defined(PPL_Interval_defs_hh)