diff --git a/Filtered_kernel/TODO b/Filtered_kernel/TODO index 7cdd402d50f..91adb1153ad 100644 --- a/Filtered_kernel/TODO +++ b/Filtered_kernel/TODO @@ -1,5 +1,3 @@ -[See also the file TODO_static_filters] - Concerning the main code: ------------------------- - Policy for overlapping comparisons : another good (faster) solution @@ -70,3 +68,143 @@ Concerning the test-suite: 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 traditionnal 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... + + diff --git a/Filtered_kernel/TODO_static_filters b/Filtered_kernel/TODO_static_filters deleted file mode 100644 index 47d6e085a71..00000000000 --- a/Filtered_kernel/TODO_static_filters +++ /dev/null @@ -1,138 +0,0 @@ -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 traditionnal 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... - diff --git a/Filtered_kernel/include/CGAL/Restricted_double.h b/Filtered_kernel/archive/include/CGAL/Restricted_double.h similarity index 100% rename from Filtered_kernel/include/CGAL/Restricted_double.h rename to Filtered_kernel/archive/include/CGAL/Restricted_double.h diff --git a/Filtered_kernel/dont_submit b/Filtered_kernel/dont_submit deleted file mode 100644 index 1d17d44920a..00000000000 --- a/Filtered_kernel/dont_submit +++ /dev/null @@ -1,2 +0,0 @@ -TODO_static_filters -Restricted_double.h