// ============================================================================ // // Copyright (c) 1999,2000 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------------- // // release : // release_date : // // file : include/CGAL/Lazy_exact_nt.h // revision : $Revision$ // revision_date : $Date$ // package : Interval Arithmetic // author(s) : Sylvain Pion // coordinator : INRIA Sophia-Antipolis () // // ============================================================================ #ifndef CGAL_LAZY_EXACT_NT_H #define CGAL_LAZY_EXACT_NT_H #include #include #include #include #include #include /* * 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 ? */ /* * 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() later we can do that (having a birthdate like LOOK ?). * could use update_approx(). */ CGAL_BEGIN_NAMESPACE template class Lazy_exact_nt; // Abstract base representation class template struct Lazy_exact_rep : public Rep { Interval_base in; // could be const, except for rafinement ? or mutable ? ET *et; Lazy_exact_rep (const Interval_base i) : in(i), et(NULL) {} Interval_nt<> approx() const // Better return a const ref instead ? { return in; } ET exact() // Better return a const ref instead ? { if (et==NULL) update_exact(); return *et; } virtual void update_approx() = 0; // Not used anymore... at the moment :) virtual void update_exact() = 0; virtual ~Lazy_exact_rep () {}; }; // 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_approx() { CGAL_assertion(false); } void update_exact() { et = new ET((int)in.inf()); } }; // double constant template struct Lazy_exact_Cst : public Lazy_exact_rep { Lazy_exact_Cst (double d) : Lazy_exact_rep(d) {} void update_approx() { CGAL_assertion(false); } void update_exact() { et = new ET(in.inf()); } }; // 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_base &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_base &i, const Lazy_exact_nt &a, const Lazy_exact_nt &b) : Lazy_exact_unary(i, a), op2(b) {} }; // 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)) { et = new ET(e); } void update_approx() { CGAL_assertion(false); } void update_exact() { CGAL_assertion(false); } }; // 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_approx() { in = OP(op1.approx()); } \ void update_exact() { et = new ET(OP(op1.exact())); } \ }; 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_approx() { in = op1.approx() OP op2.approx(); } \ void update_exact() { et = new ET(op1.exact() OP 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_approx() { in = min(op1.approx(), op2.approx()); } void update_exact() { et = new ET(min(op1.exact(), 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_approx() { in = max(op1.approx(), op2.approx()); } void update_exact() { et = new ET(max(op1.exact(), op2.exact())); } }; // The real number type, handle class template class Lazy_exact_nt : public Handle { public : 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); } Self operator+ (const Self & a) const { return new Lazy_exact_Add(*this, a); } Self operator- (const Self & a) const { return new Lazy_exact_Sub(*this, a); } Self operator* (const Self & a) const { return new Lazy_exact_Mul(*this, a); } Self operator/ (const Self & a) const { return new Lazy_exact_Div(*this, a); } Interval_nt<> approx() const // throw() ? { return ptr()->approx(); } Interval_nt_advanced approx_adv() const { return ptr()->approx(); } ET exact() const { return ptr()->exact(); } // The other comparison operators are currently provided by the STL. bool operator< (const Self & a) const { try { return approx() < a.approx(); } catch (Interval_base::unsafe_comparison) { std::cerr << "Interval filter failure (<)" << std::endl; return exact() < a.exact(); } } bool operator== (const Self & a) const { try { return approx() == a.approx(); } catch (Interval_base::unsafe_comparison) { std::cerr << "Interval filter failure (==)" << std::endl; return exact() == a.exact(); } } private: Self_rep * ptr() const { return (Self_rep*) PTR; } }; template inline double to_double(const Lazy_exact_nt & a) { return CGAL::to_double(a.approx()); } template inline Interval_base to_interval(const Lazy_exact_nt & a) { return a.approx(); } // VC++ doesn't support partial overloading of function templates. // The other way would be to not define the global templates so that // they don't interfere with template NTs. #ifndef _MSC_VER // Note: GCC 2.95 completely and silently ignores the catch block // of _template_ function-try-blocks. Later versions fix the bug. namespace NTS { template inline Sign sign(const Lazy_exact_nt & a) { try { return CGAL_NTS sign(a.approx()); } catch (Interval_base::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_base::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); } } // namespace NTS #endif // _MSC_VER template inline Lazy_exact_nt sqrt(const Lazy_exact_nt & a) { return new Lazy_exact_Sqrt(a); } #ifndef _MSC_VER 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); } #endif // _MSC_VER template std::ostream & operator<< (std::ostream & os, const Lazy_exact_nt & a) { return os << a.approx(); } 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 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 inline Number_tag number_type_tag (const Lazy_exact_nt&) { return Number_tag(); } #ifndef CGAL_CFG_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION template struct converter > { static inline ET do_it (const Lazy_exact_nt & z) { return z.exact(); } }; #endif CGAL_END_NAMESPACE #endif // CGAL_LAZY_EXACT_NT_H