Concerning the main code: ------------------------- - Policy for overlapping comparisons : another good (faster) solution would be to set a static boolean variable to indicate a buggy comparison happened (a la IEEE inexact flags). Drawback is that it's not thread safe, but could be made safe with pthread_key_create()... Clearly, all this stuff is policy. struct overlap_throw { void operator() const { throw(ce_qui_faut); } }; Or : class overlap_static { static bool pipo = false; public: void operator() const { pipo = true; } void reset() const { pipo = false; } }; - Use expression templates for Interval_nt<> and Lazy_exact_nt<>. - Specializations for is_zero() and co, and make use of them in the kernel. [Filtered_exact<> doesn't define them either, it's a bug...] - SunPro 5.x supports Interval arithmetic... http://docs.sun.com/htmlcoll/coll.693.1/iso-8859-1/CPPARITHPROG/iapg_bookTOC.html http://www.sun.com/forte/cplusplus/interval/index.html;$sessionid$GSXJDFYAABWVTAMTA1FU45Q - Try to get rid of the libc5 compatible version (make benchmarks first). - Have determinant_by_formula() overloading for Lazy_exact_nt<> ? And what about for Interval_nt<> too ? - Turn CGAL_IA_CHECK_RESTRICT into an [expensive] assertion ? - Handle in_smallest_orthogonalcircle_ftC2.h correctly (needs an include) - Bench -fbranch-probabilities ? Use __builtin_expect() for GCC 3 ? - Mark the cache as "mutable" (see Stroustrup, page 232) ? - Filter_Cache: Faire des benchs, et une test-suite qui soit raisonnable. Hum, rajouter un booléen pour calculer le cache seulement sur demande ? (ça évite de le faire inutilement pour les variables intermédiaires, mais ça prend un chouia plus de place... mais en comparaison du reste...) - Replace CGAL_IA_MAX_DOUBLE by standard DBL_MAX in , if portable (add a test). Not possible for CGAL_IA_MIN_DOUBLE, since DBL_MIN is the _normalized_ minimum. - See the C++ Standard numeric_limits<>, section 18.2. ? See ISO C99 and http://http.cs.berkeley.edu/~fateman/fp98/korenF/node3.html. - "C9x FP unordered compares": + /* ISO C99 IEEE Unordered compares. */ + builtin_function ("__builtin_isgreater", default_function_type, + BUILT_IN_ISGREATER, BUILT_IN_NORMAL, NULL_PTR); + builtin_function ("__builtin_isgreaterequal", default_function_type, + BUILT_IN_ISGREATEREQUAL, BUILT_IN_NORMAL, NULL_PTR); + builtin_function ("__builtin_isless", default_function_type, + BUILT_IN_ISLESS, BUILT_IN_NORMAL, NULL_PTR); + builtin_function ("__builtin_islessequal", default_function_type, + BUILT_IN_ISLESSEQUAL, BUILT_IN_NORMAL, NULL_PTR); + builtin_function ("__builtin_islessgreater", default_function_type, + BUILT_IN_ISLESSGREATER, BUILT_IN_NORMAL, NULL_PTR); + builtin_function ("__builtin_isunordered", default_function_type, + BUILT_IN_ISUNORDERED, BUILT_IN_NORMAL, NULL_PTR); [voir le draft C99 ce que c'est] Concerning the doc: ------------------- - In the 2.0 HTML doc, my enums are indexed twice. probably a cc_manual compliance bug from me. Idem, my fct to_double(Ia) is not the same as the others... - add a pointer to my MISC'99 paper. - DOCUMENT the new boolean template parameter, the script, the static filters. Concerning the test-suite: -------------------------- - Check it with GCOV again before the next public release. - Make a more extensive test-suite for the filtered predicates. The script could output information to test them generically somehow. - Test NaN propagation. Comparisons with these should throw the exception... Check that they are correctly propagated (by min(), max(), even operator*...) Special TODO list for the static filters. ----------------------------------------- It's a lot of work here for a "minor" optimization, so it's "low" priority, except we could merge stuff with Olivier's Fixed ! - Known problems with the current approach: - Match operator<(a,b) and co... - What to do with branches (e.g. collinearC3() and power_test()): - The epsilon computation type should return ZERO/EQUAL as default. This way, collinearC3() works. - The user can provide the epsilon variant inside the source code, delimited by special symbols /*CGAL_FILTER_BODY ... */. That's the solution for CGAL. - Checks that the epsilons have been updated (which will not prove that it's correct, but is better than nothing). - Or use G++'s interface as a parser ? See gcc mail archives, 15 august 2000, "XML output for GCC". An XML description for predicates ? - /*DEGREE=2*/ attribute to the arguments ? - # of bounds : one per predicate, or one per argument ? give choice. - # of epsilons: one per predicate, or one set per sub-predicate ? choice. - Check that the compiler optimizes the epsilon computation (use __attribute__((const)) for Static_filter_error operators) ? - As Fred pointed out: the scheme is not thread safe. - Remove the assertions in the original code. - In case there are loops, we must take the max() of the epsilons. This should not happen often, imho... Wait and see. - Move static_infos in src/. - Replace: NEW_bound = max(NEW_bound, fabs(px.to_double())); by: if (NEW_bound < fabs(px.to_double())) NEW_bound = fabs(px.to_double()); or even, using a .bound() member function: if (NEW_bound < px.bound()) NEW_bound = px.bound(); Moreover, to_double() is not exact, we should use abs(to_interval(x)).sup() ! - Member function access for generic type should be (?): .dbl_approx() .bound() (basically a bound on: fabs(.dbl_approx())) .error() - Add a "number of bits" field in Static_filter_error ? (so that we get the same thing as Fixed for 24 bits) - Another approach to consider : Implement predicates taking one or several epsilons as additional parameters, and have the functionality found in Open CasCade, using sign(a, epsilon). Then with a special traits or something, we can define sign(a,epsilon) = sign(a), and get the traditional template predicates from that... So that the epsilons are removed at compile time ? It would be nice to know exactly the desired functionality for epsilons... - Where to put the context of the predicates ? different possibilities : 1- static data member of the predicate object (~as it is now) 2- data member of the predicate object 3- static data member of the kernel 4- data member of the kernel 5- global data Things to take into account : - I want to be able to initialize the bounds externally. This can't be done if we choose 2-. - I want to be able to have different contexts depending where I use the predicate, this can't be done with 5- nor 3- nor 1-. - If I add a failure_counter, it should be at the same place as the context, and I should be able to access it from the outside. If we do that like triangulation, treating geom_traits as a data member of triangulatino, then it's ok. - So it remains 2 possibilities : a- data member of the predicate object. b- data member of the kernel. So 1-, 3-, 5- are out since we can't have different contexts. 2- and 4- are basically equivalent if we can access the context of an object via the kernel object (_gt in triangulation). So, Orientation_2_object(), for this particular kernel, would return a const ref to a data member of the kernel... So the good choice seems to be to have data stored in each predicate object, and having the kernel store a predicate object for each predicate. Then the orientation_2_object() simply returns a reference to it. Then it means algorithms should use one "global" object per predicate (e.g. one orientation object for a whole Triangulation). Except for cases where they actually want different contexts. // Additional kernel for storage type ? template > class Filtered_Point_2 { const CK::Point_2 storage; // IK cached ? It doesn't make sense to do it lazily because it's going to // be used. BUT, what is worth is the case when the storage number type is // like a double : in this case, no approximation needs to be stored. IK::Point_2 app; const IK::Point_2 & approx() { return app; } #if No_cache_EK // via a traits parameter ? Have a generic caching mechanism ? EK::Point_2 exact() { return EK::Point_2(storage); } #else EK::Point_2 ex; const EK::Point_2 & exact { return ex; } #endif }; // For filtered constructions, we should be able to re-use the same predicates, // but have different constructions and objects Point_2... template > class Filtered_kernel { public: Filtered_kernel() : ik(), ek(), orientation_2_obj(ik.orientation_2_object(), ek.orientation_2_object()) // ... {} typedef CGAL::Filtered_Point_2<...> Point_2; // ... typedef CGAL::Filtered_p_Orientation Orientation_2; Orientation_2 orientation_2_obj; const Orientation_2 & orientation_2_object() const { return orientation_2_obj; } const IK & get_ik() const { return ik; } const EK & get_ek() const { return ek; } private: EK ek; IK ik; }; Then you use this thing as a kernel : Filtered_kernel > eventually adding profiling template parameters... Just like we have at the NT level : Lazy_exact_nt. Maybe have a unique (Cartesian) kernel that includes filtering and caching capabilities which are toggleable by a simple traits ? The predicate objects would include the (currently so-called) update_epsilon() member functions... Or probably better, a filtering wrapper that can be used by homogeneous as well...