1416: Refactor the L2-norm, and test it.

https://svn.lrde.epita.fr/svn/oln/trunk/milena A bit of explanation about why there are deletions (lines starting with a `-') in the diff of tests/l2.cc: I used `svn copy' to create this file from tests/l1.cc. So, the differences you see are w.r.t. the latter. Index: ChangeLog from Roland Levillain <roland@lrde.epita.fr> Refactor the L2-norm, and test it. * mln/norm/l2.hh: Use type `mln_value_sum(C)' instead of `float' to handle L2-norm values. (mln::norm::impl::l2_, mln::norm::impl::l2_distance_): New. Use to factor the implementations of... (mln::norm::l2, mln::norm::l2_distance): ...these functions. * tests/l2.cc: New test. * tests/Makefile.am (check_PROGRAMS): Add l2. (l2_SOURCES): New. mln/norm/l2.hh | 91 +++++++++++++++++++++++++++++++++--------------------- tests/Makefile.am | 2 + tests/l2.cc | 37 +++++++++++---------- 3 files changed, 78 insertions(+), 52 deletions(-) Index: mln/norm/l2.hh --- mln/norm/l2.hh (revision 1416) +++ mln/norm/l2.hh (working copy) @@ -30,78 +30,99 @@ /*! \file mln/norm/l2.hh * - * \brief Define some l2-norm related routines. + * \brief Define some L2-norm related routines. + * \see http://mathworld.wolfram.com/L2-Norm.html for more information. */ -# include <cmath> - +# include <mln/math/sqr.hh> +# include <mln/math/sqrt.hh> # include <mln/metal/vec.hh> + namespace mln { namespace norm { - /// Infinity-norm of a vector \p vec. + /// L2-norm of a vector \a vec. + /// \{ template <unsigned n, typename C> - float l2(const C (&vec)[n]); + mln_value_sum(C) l2(const C (&vec)[n]); - /// Infinity-norm distance between vectors \p v1 and \p v2. template <unsigned n, typename C> - float l2_distance(const C (&v1)[n], const C (&v2)[n]); + mln_value_sum(C) l2(const metal::vec<n,C>& vec); + /// \} + /// L2-norm distance between vectors \a vec1 and \p vec2. + /// \{ template <unsigned n, typename C> - float l2(const metal::vec<n,C>& vec); + mln_value_sum(C) l2_distance(const C (&vec1)[n], const C (&vec2)[n]); template <unsigned n, typename C> - float l2_distance(const metal::vec<n,C>& vec1, const metal::vec<n,C>& vec2); - - // FIXME: Replace float by mln_value_sum(C)... + mln_value_sum(C) l2_distance(const metal::vec<n,C>& vec1, + const metal::vec<n,C>& vec2); + /// \} # ifndef MLN_INCLUDE_ONLY - template <unsigned n, typename C> - float l2(const C (&vec)[n]) + namespace impl + { + + template <unsigned n, typename C, typename V> + mln_value_sum(C) + l2_(const V& vec) { - C c = 0; + mln_value_sum(C) m = 0; for (unsigned i = 0; i < n; ++i) - c += vec[i] * vec[i]; - return sqrt(c); + m += mln::math::sqr(vec[i]); + return mln::math::sqrt(m); } - template <unsigned n, typename C> - float l2_distance(const C (&v1)[n], const C (&v2)[n]) + template <unsigned n, typename C, typename V> + mln_value_sum(C) + l2_distance_(const V& vec1, const V& vec2) { - C d = 0; + mln_value_sum(C) d = 0; for (unsigned i = 0; i < n; ++i) - { - C dd = v1[i] - v2[i]; - d += dd * dd; - } - return sqrt(d); + d += mln::math::sqr(vec1[i] - vec2[i]); + return mln::math::sqrt(d); } + } // end of namespace mln::norm::impl + + + /*----------. + | Facades. | + `----------*/ + template <unsigned n, typename C> - float l2(const metal::vec<n,C>& vec) + mln_value_sum(C) + l2(const C (&vec)[n]) { - C c = 0; - for (unsigned i = 0; i < n; ++i) - c += vec[i] * vec[i]; - return sqrt(c); + return impl::l2_<n, C>(vec); } template <unsigned n, typename C> - float l2(const metal::vec<n,C>& vec1, const metal::vec<n,C>& vec2) + mln_value_sum(C) + l2(const metal::vec<n,C>& vec) { - C d = 0; - for (unsigned i = 0; i < n; ++i) + return impl::l2_<n, C>(vec); + } + + template <unsigned n, typename C> + mln_value_sum(C) + l2_distance(const C (&vec1)[n], const C (&vec2)[n]) { - C dd = vec1[i] - vec2[i]; - d += dd * dd; + return impl::l2_distance_<n, C>(vec1, vec2); } - return sqrt(d); + + template <unsigned n, typename C> + mln_value_sum(C) + l2_distance(const metal::vec<n,C>& vec1, const metal::vec<n,C>& vec2) + { + return impl::l2_distance_<n, C>(vec1, vec2); } # endif // ! MLN_INCLUDE_ONLY Index: tests/l2.cc --- tests/l2.cc (revision 1411) +++ tests/l2.cc (working copy) @@ -25,47 +25,50 @@ // reasons why the executable file might be covered by the GNU General // Public License. -/// \file tests/l1.hh -/// \brief Test the L1-norm. +/// \file tests/l2.hh +/// \brief Test the L2-norm. +#include <cmath> #include <cassert> #include <mln/metal/vec.hh> #include <mln/math/abs.hh> -#include <mln/norm/l1.hh> +#include <mln/norm/l2.hh> // FIXME: We should have a almost_equal function somewhere in Milena. static const float epsilon = 0.0001; using mln::metal::vec; -using mln::norm::l1; +using mln::norm::l2; template <typename V> -void check_l1 (const V& vec1, const V& vec2) +void check_l2 (const V& vec1, const V& vec2) { - assert (mln::math::abs(mln::norm::l1(vec1) - mln::norm::l1(vec2)) + assert (mln::math::abs(mln::norm::l2(vec1) - mln::norm::l2(vec2)) < epsilon); } template <typename V, typename S> -void check_l1_distance (const V& vec1, const V& vec2, const S& ref_val) +void check_l2_distance (const V& vec1, const V& vec2, const S& ref_val) { - assert (mln::math::abs(mln::norm::l1_distance(vec1, vec2) - ref_val) + assert (mln::math::abs(mln::norm::l2_distance(vec1, vec2) - ref_val) < epsilon); } int main () { - vec<3, int> t; t.set (1, -2, 3); - vec<3, int> u; u.set (5, 1, 0); - int d = (5 - 1) + (1 + 2) + 3; + vec<3, int> t; t.set (2, -2, 3); + vec<3, int> u; u.set (4, 1, 0); + float d = std::sqrt((4 - 2) * (4 - 2) + + (1 + 2) * (1 + 2) + + (0 - 3) * (0 - 3)); - check_l1(t, u); - check_l1_distance (t, u, d); + check_l2(t, u); + check_l2_distance (t, u, d); - int v[] = {1, -2, 3}; - int w[] = {5, 1, 0}; + int v[] = {2, -2, 3}; + int w[] = {4, 1, 0}; - check_l1(v, w); - check_l1_distance (v, w, d); + check_l2(v, w); + check_l2_distance (v, w, d); } Index: tests/Makefile.am --- tests/Makefile.am (revision 1416) +++ tests/Makefile.am (working copy) @@ -85,6 +85,7 @@ io_ppm \ \ l1 \ + l2 \ labeling_algo \ labeling_estimate \ labeling_foreground \ @@ -272,6 +273,7 @@ io_ppm_SOURCES = io_ppm.cc l1_SOURCES = l1.cc +l2_SOURCES = l2.cc labeling_algo_SOURCES = labeling_algo.cc labeling_estimate_SOURCES = labeling_estimate.cc labeling_foreground_SOURCES = labeling_foreground.cc
participants (1)
-
Roland Levillain