// Copyright (c) 1999-2004 Utrecht University (The Netherlands), // ETH Zurich (Switzerland), Freie Universitaet Berlin (Germany), // INRIA Sophia-Antipolis (France), Martin-Luther-University Halle-Wittenberg // (Germany), Max-Planck-Institute Saarbruecken (Germany), RISC Linz (Austria), // and Tel-Aviv University (Israel). All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; version 2.1 of the License. // See the file LICENSE.LGPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $Source$ // $Revision$ $Date$ // $Name$ // // Author(s) : Sylvain Pion #ifndef CGAL_LAZY_EXACT_NT_H #define CGAL_LAZY_EXACT_NT_H #include #include #include #include #include #include #include #include #include // to get the overloaded predicates. /* * This file contains the definition of the number type Lazy_exact_nt, * where ET is an exact number type (must provide the exact operations needed). * * Lazy_exact_nt provides a DAG-based lazy evaluation, like LEDA's real, * Core's Expr, LEA's lazy rationals... * * The values are first approximated using Interval_base. * The exactness is provided when needed by ET. * * Lazy_exact_nt is just a handle to the abstract base class * Lazy_exact_rep which has pure virtual methods .approx() and .exact(). * From this class derives one class per operation, with one constructor. * * The DAG is managed by : * - Handle and Rep. * - virtual functions to denote the various operators (instead of an enum). * * Other packages with vaguely similar design : APU, MetaCGAL, LOOK. */ /* * TODO : * - Generalize it for constructions at the kernel level. * - Interval rafinement functionnality ? * - Separate the handle and the representation(s) in 2 files (?) * maybe not a good idea, better if everything related to one operation is * close together. * - Add a CT template parameter like Filtered_exact_nt<> ? * - Add a string constant to provide an expression string (a la MetaCGAL) ? * // virtual ostream operator<<() const = 0; // or string, like Core ? * - Have a template-expression (?) thing that evaluates a temporary element, * and allocates stuff in memory only when really needs to convert to the * NT. (cf gmp++, and maybe other things, Blitz++, Synaps...) */ /* * Interface of the rep classes: * - .approx() returns Interval_nt<> (assumes rounding=nearest). * [ only called from the handle, and declared in the base ] * - .exact() returns ET, if not already done, computes recursively * * - .rafine_approx() ?? */ CGAL_BEGIN_NAMESPACE template class Lazy_exact_nt; // Abstract base representation class template struct Lazy_exact_rep : public Rep { Interval_nt in; // could be const, except for rafinement ? or mutable ? ET *et; // mutable as well ? Lazy_exact_rep (const Interval_nt & i) : in(i), et(NULL) {} private: Lazy_exact_rep (const Lazy_exact_rep&) { abort(); } // cannot be copied. public: const Interval_nt& approx() const { return in; } const ET & exact() { if (et==NULL) { update_exact(); in = CGAL::to_interval(*et); } return *et; } virtual void update_exact() = 0; virtual ~Lazy_exact_rep () { delete et; }; }; // int constant template struct Lazy_exact_Int_Cst : public Lazy_exact_rep { Lazy_exact_Int_Cst (int i) : Lazy_exact_rep(double(i)) {} void update_exact() { this->et = new ET((int)this->in.inf()); } }; // double constant template struct Lazy_exact_Cst : public Lazy_exact_rep { Lazy_exact_Cst (double d) : Lazy_exact_rep(d) {} void update_exact() { this->et = new ET(this->in.inf()); } }; // Exact constant template struct Lazy_exact_Ex_Cst : public Lazy_exact_rep { Lazy_exact_Ex_Cst (const ET & e) : Lazy_exact_rep(to_interval(e)) { this->et = new ET(e); } void update_exact() { CGAL_assertion(false); } }; // Construction from a Lazy_exact_nt (which keeps the lazyness). template struct Lazy_lazy_exact_Cst : public Lazy_exact_rep { Lazy_lazy_exact_Cst (const Lazy_exact_nt &x) : Lazy_exact_rep(x.approx()), l(x) {} void update_exact() { this->et = new ET(l.exact()); } Lazy_exact_nt l; }; // Unary operations: abs, sqrt, square. // Binary operations: +, -, *, /, min, max. // Base unary operation template struct Lazy_exact_unary : public Lazy_exact_rep { const Lazy_exact_nt op1; Lazy_exact_unary (const Interval_nt &i, const Lazy_exact_nt &a) : Lazy_exact_rep(i), op1(a) {} }; // Base binary operation template struct Lazy_exact_binary : public Lazy_exact_unary { const Lazy_exact_nt op2; Lazy_exact_binary (const Interval_nt &i, const Lazy_exact_nt &a, const Lazy_exact_nt &b) : Lazy_exact_unary(i, a), op2(b) {} }; // Here we could use a template class for all operations (STL provides // function objects plus, minus, multiplies, divides...). But it would require // a template template parameter, and GCC 2.95 seems to crash easily with them. // Macro for unary operations #define CGAL_LAZY_UNARY_OP(OP, NAME) \ template \ struct NAME : public Lazy_exact_unary \ { \ NAME (const Lazy_exact_nt &a) \ : Lazy_exact_unary(OP(a.approx()), a) {} \ \ void update_exact() { this->et = new ET(OP(this->op1.exact())); } \ }; CGAL_LAZY_UNARY_OP(CGAL::opposite, Lazy_exact_Opp) CGAL_LAZY_UNARY_OP(CGAL_NTS abs, Lazy_exact_Abs) CGAL_LAZY_UNARY_OP(CGAL_NTS square, Lazy_exact_Square) CGAL_LAZY_UNARY_OP(CGAL::sqrt, Lazy_exact_Sqrt) // A macro for +, -, * and / #define CGAL_LAZY_BINARY_OP(OP, NAME) \ template \ struct NAME : public Lazy_exact_binary \ { \ NAME (const Lazy_exact_nt &a, const Lazy_exact_nt &b) \ : Lazy_exact_binary(a.approx() OP b.approx(), a, b) {} \ \ void update_exact() \ { \ this->et = new ET(this->op1.exact() OP this->op2.exact()); \ } \ }; CGAL_LAZY_BINARY_OP(+, Lazy_exact_Add) CGAL_LAZY_BINARY_OP(-, Lazy_exact_Sub) CGAL_LAZY_BINARY_OP(*, Lazy_exact_Mul) CGAL_LAZY_BINARY_OP(/, Lazy_exact_Div) // Minimum template struct Lazy_exact_Min : public Lazy_exact_binary { Lazy_exact_Min (const Lazy_exact_nt &a, const Lazy_exact_nt &b) : Lazy_exact_binary(min(a.approx(), b.approx()), a, b) {} void update_exact() { this->et = new ET(min(this->op1.exact(), this->op2.exact())); } }; // Maximum template struct Lazy_exact_Max : public Lazy_exact_binary { Lazy_exact_Max (const Lazy_exact_nt &a, const Lazy_exact_nt &b) : Lazy_exact_binary(max(a.approx(), b.approx()), a, b) {} void update_exact() { this->et = new ET(max(this->op1.exact(), this->op2.exact())); } }; // The real number type, handle class template class Lazy_exact_nt : public Handle { public : typedef typename Number_type_traits::Has_gcd Has_gcd; typedef typename Number_type_traits::Has_division Has_division; typedef typename Number_type_traits::Has_sqrt Has_sqrt; typedef Lazy_exact_nt Self; typedef Lazy_exact_rep Self_rep; // Lazy_exact_nt () {} // Handle is not such a nice stuff... at the moment. Lazy_exact_nt (Self_rep *r) { PTR = r; } // Operations Lazy_exact_nt (double d) { PTR = new Lazy_exact_Cst(d); } Lazy_exact_nt (int i = 0) { PTR = new Lazy_exact_Int_Cst(i); } Lazy_exact_nt (const ET & e) { PTR = new Lazy_exact_Ex_Cst(e); } template Lazy_exact_nt (const Lazy_exact_nt &x) { PTR = new Lazy_lazy_exact_Cst(x); } Self operator- () const { return new Lazy_exact_Opp(*this); } const Interval_nt& approx() const { return ptr()->approx(); } Interval_nt interval() const { const Interval_nt& i = ptr()->approx(); return Interval_nt(i.inf(), i.sup()); } Interval_nt_advanced approx_adv() const { return ptr()->approx(); } const ET & exact() const { return ptr()->exact(); } static const double & get_relative_precision_of_to_double() { return relative_precision_of_to_double; } static void set_relative_precision_of_to_double(const double & d) { CGAL_assertion(d > 0 && d < 1); relative_precision_of_to_double = d; } private: Self_rep * ptr() const { return (Self_rep*) PTR; } static double relative_precision_of_to_double; }; template double Lazy_exact_nt::relative_precision_of_to_double = 0.00001; template bool operator<(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { try { return a.approx() < b.approx(); } catch (Interval_nt::unsafe_comparison) { // std::cerr << "Interval filter failure (<)" << std::endl; return a.exact() < b.exact(); } } template bool operator==(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { try { return a.approx() == b.approx(); } catch (Interval_nt::unsafe_comparison) { // std::cerr << "Interval filter failure (==)" << std::endl; return a.exact() == b.exact(); } } template inline bool operator>(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return b < a; } template inline bool operator<=(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return ! (b < a); } template inline bool operator>=(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return ! (a < b); } template inline bool operator!=(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return ! (a == b); } // Mixed operators with int. template bool operator<(int a, const Lazy_exact_nt& b) { try { return a < b.approx(); } catch (Interval_nt::unsafe_comparison) { return a < b.exact(); } } template bool operator<(const Lazy_exact_nt& a, int b) { try { return a.approx() < b; } catch (Interval_nt::unsafe_comparison) { return a.exact() < b; } } template bool operator==(int a, const Lazy_exact_nt& b) { try { return a == b.approx(); } catch (Interval_nt::unsafe_comparison) { return a == b.exact(); } } template inline bool operator==(const Lazy_exact_nt& a, int b) { return b == a; } template inline bool operator>(int a, const Lazy_exact_nt& b) { return b < a; } template inline bool operator>(const Lazy_exact_nt& a, int b) { return b < a; } template inline bool operator<=(int a, const Lazy_exact_nt& b) { return ! (b < a); } template inline bool operator<=(const Lazy_exact_nt& a, int b) { return ! (b < a); } template inline bool operator>=(int a, const Lazy_exact_nt& b) { return ! (a < b); } template inline bool operator>=(const Lazy_exact_nt& a, int b) { return ! (a < b); } template inline bool operator!=(int a, const Lazy_exact_nt& b) { return ! (a == b); } template inline bool operator!=(const Lazy_exact_nt& a, int b) { return ! (b == a); } template Lazy_exact_nt operator+(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return new Lazy_exact_Add(a, b); } template Lazy_exact_nt operator-(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return new Lazy_exact_Sub(a, b); } template Lazy_exact_nt operator*(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return new Lazy_exact_Mul(a, b); } template Lazy_exact_nt operator/(const Lazy_exact_nt& a, const Lazy_exact_nt& b) { return new Lazy_exact_Div(a, b); } // mixed operators template Lazy_exact_nt operator+(const Lazy_exact_nt& a, int b) { return new Lazy_exact_Add(a, b); } template Lazy_exact_nt operator-(const Lazy_exact_nt& a, int b) { return new Lazy_exact_Sub(a, b); } template Lazy_exact_nt operator*(const Lazy_exact_nt& a, int b) { return new Lazy_exact_Mul(a, b); } template Lazy_exact_nt operator/(const Lazy_exact_nt& a, int b) { return new Lazy_exact_Div(a, b); } template Lazy_exact_nt operator+(int a, const Lazy_exact_nt& b) { return new Lazy_exact_Add(a, b); } template Lazy_exact_nt operator-(int a, const Lazy_exact_nt& b) { return new Lazy_exact_Sub(a, b); } template Lazy_exact_nt operator*(int a, const Lazy_exact_nt& b) { return new Lazy_exact_Mul(a, b); } template Lazy_exact_nt operator/(int a, const Lazy_exact_nt& b) { return new Lazy_exact_Div(a, b); } template double to_double(const Lazy_exact_nt & a) { const Interval_nt& app = a.approx(); if (app.sup() == app.inf()) return app.sup(); // If it's precise enough, then OK. if ((app.sup() - app.inf()) < Lazy_exact_nt::get_relative_precision_of_to_double() * std::max(std::fabs(app.inf()), std::fabs(app.sup())) ) return CGAL::to_double(app); // Otherwise we trigger exact computation first, // which will refine the approximation. a.exact(); return CGAL::to_double(a.approx()); } template inline std::pair to_interval(const Lazy_exact_nt & a) { return a.approx().pair(); } template inline Sign sign(const Lazy_exact_nt & a) { try { return CGAL_NTS sign(a.approx()); } catch (Interval_nt::unsafe_comparison) { // std::cerr << "Interval filter failure (sign)" << std::endl; return CGAL_NTS sign(a.exact()); } } template inline Comparison_result compare(const Lazy_exact_nt & a, const Lazy_exact_nt & b) { try { return CGAL_NTS compare(a.approx(), b.approx()); } catch (Interval_nt::unsafe_comparison) { // std::cerr << "Interval filter failure (compare)" << std::endl; return CGAL_NTS compare(a.exact(), b.exact()); } } template inline Lazy_exact_nt abs(const Lazy_exact_nt & a) { return new Lazy_exact_Abs(a); } template inline Lazy_exact_nt square(const Lazy_exact_nt & a) { return new Lazy_exact_Square(a); } template inline Lazy_exact_nt sqrt(const Lazy_exact_nt & a) { return new Lazy_exact_Sqrt(a); } template inline Lazy_exact_nt min(const Lazy_exact_nt & a, const Lazy_exact_nt & b) { return new Lazy_exact_Min(a, b); } template inline Lazy_exact_nt max(const Lazy_exact_nt & a, const Lazy_exact_nt & b) { return new Lazy_exact_Max(a, b); } template std::ostream & operator<< (std::ostream & os, const Lazy_exact_nt & a) { return os << CGAL::to_double(a); } template std::istream & operator>> (std::istream & is, Lazy_exact_nt & a) { ET e; is >> e; a = e; return is; } template inline Lazy_exact_nt & operator+=(Lazy_exact_nt & a, const Lazy_exact_nt & b) { return a = a + b; } template inline Lazy_exact_nt & operator-=(Lazy_exact_nt & a, const Lazy_exact_nt & b) { return a = a - b; } template inline Lazy_exact_nt & operator*=(Lazy_exact_nt & a, const Lazy_exact_nt & b) { return a = a * b; } template inline Lazy_exact_nt & operator/=(Lazy_exact_nt & a, const Lazy_exact_nt & b) { return a = a / b; } template inline Lazy_exact_nt & operator+=(Lazy_exact_nt & a, int b) { return a = a + b; } template inline Lazy_exact_nt & operator-=(Lazy_exact_nt & a, int b) { return a = a - b; } template inline Lazy_exact_nt & operator*=(Lazy_exact_nt & a, int b) { return a = a * b; } template inline Lazy_exact_nt & operator/=(Lazy_exact_nt & a, int b) { return a = a / b; } template inline bool is_finite(const Lazy_exact_nt & a) { return is_finite(a.approx()) || is_finite(a.exact()); } template inline bool is_valid(const Lazy_exact_nt & a) { return is_valid(a.approx()) || is_valid(a.exact()); } template inline io_Operator io_tag (const Lazy_exact_nt&) { return io_Operator(); } template struct converter > { static inline ET do_it (const Lazy_exact_nt & z) { return z.exact(); } }; CGAL_END_NAMESPACE #endif // CGAL_LAZY_EXACT_NT_H