PPL  0.12.1
Interval.defs.hh
Go to the documentation of this file.
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)