
https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Roland Levillain <roland@lrde.epita.fr> Refactor the L1-norm, and test it. * mln/norm/l1.hh: Use type `mln_value_sum(C)' instead of `float' to handle L1-norm values. (mln::norm::impl::l1_, mln::norm::impl::l1_distance_): New. Use to factor the implementations of... (mln::norm::l1, mln::norm::l1_distance): ...these functions. * tests/l1.cc: New test. * tests/Makefile.am (check_PROGRAMS): Add l1. (l1_SOURCES): New. mln/norm/l1.hh | 82 +++++++++++++++++++++++++++++++----------------------- tests/Makefile.am | 2 + tests/l1.cc | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 34 deletions(-) Index: mln/norm/l1.hh --- mln/norm/l1.hh (revision 1411) +++ mln/norm/l1.hh (working copy) @@ -31,11 +31,11 @@ /*! \file mln/norm/l1.hh * * \brief Define some l1-norm related routines. + * \see http://mathworld.wolfram.com/L1-Norm.html for more information. */ -# include <cmath> - # include <mln/metal/vec.hh> +# include <mln/math/abs.hh> namespace mln { @@ -43,71 +43,85 @@ namespace norm { - /// Infinity-norm of a vector \p vec. + /// L1-norm of a vector \a vec. + /// \{ template <unsigned n, typename C> - float l1(const C (&vec)[n]); + mln_value_sum(C) l1(const C (&vec)[n]); - /// Infinity-norm distance between vectors \p v1 and \p v2. template <unsigned n, typename C> - float l1_distance(const C (&v1)[n], const C (&v2)[n]); + mln_value_sum(C) l1(const metal::vec<n,C>& vec); + /// \} + /// L1-norm distance between vectors \a v1 and \a v2. + /// \{ template <unsigned n, typename C> - float l1(const metal::vec<n,C>& vec); + mln_value_sum(C) l1_distance(const C (&vec1)[n], const C (&vec2)[n]); template <unsigned n, typename C> - float l1_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) l1_distance(const metal::vec<n,C>& vec1, + const metal::vec<n,C>& vec2); + /// \} # ifndef MLN_INCLUDE_ONLY - template <unsigned n, typename C> - float l1(const C (&vec)[n]) + namespace impl { - float c = 0; + template <unsigned n, typename C, typename V> + mln_value_sum(C) l1_(const V& vec) + { + mln_value_sum(C) c = 0; for (unsigned i = 0; i < n; ++i) { - float v = vec[i]; - c += fabs (v); + mln_value_sum(C) v = vec[i]; + c += mln::math::abs (v); } return c; } - template <unsigned n, typename C> - float l1_distance(const C (&v1)[n], const C (&v2)[n]) + template <unsigned n, typename C, typename V> + mln_value_sum(C) l1_distance_(const V& vec1, const V& vec2) { - float d = 0; + mln_value_sum(C) d = 0; for (unsigned i = 0; i < n; ++i) { - float v = v1[i] - v2[i]; - d += fabs (v); + mln_value_sum(C) v = vec1[i] - vec2[i]; + d += mln::math::abs (v); } return d; } + } // end of namespace mln::norm::impl + + + // Facades. + template <unsigned n, typename C> - float l1(const metal::vec<n,C>& vec) + mln_value_sum(C) + l1(const C (&vec)[n]) { - float c = 0; - for (unsigned i = 0; i < n; ++i) - if (vec[i] > 0) - c += vec[i]; - else - c -= vec[i]; - return c; + return impl::l1_<n, C>(vec); } template <unsigned n, typename C> - float l1(const metal::vec<n,C>& vec1, const metal::vec<n,C>& vec2) + mln_value_sum(C) + l1(const metal::vec<n,C>& vec) { - float d = 0; - for (unsigned i = 0; i < n; ++i) + return impl::l1_<n, C>(vec); + } + + template <unsigned n, typename C> + mln_value_sum(C) + l1_distance(const C (&vec1)[n], const C (&vec2)[n]) { - float v = vec1[i] - vec2[i]; - d += fabs (v); + return impl::l1_distance_<n, C>(vec1, vec2); } - return d; + + template <unsigned n, typename C> + mln_value_sum(C) + l1_distance(const metal::vec<n,C>& vec1, const metal::vec<n,C>& vec2) + { + return impl::l1_distance_<n, C>(vec1, vec2); } # endif // ! MLN_INCLUDE_ONLY Index: tests/l1.cc --- tests/l1.cc (revision 0) +++ tests/l1.cc (revision 0) @@ -0,0 +1,71 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +/// \file tests/l1.hh +/// \brief Test the L1-norm. + +#include <cassert> + +#include <mln/metal/vec.hh> +#include <mln/math/abs.hh> +#include <mln/norm/l1.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; + +template <typename V> +void check_l1 (const V& vec1, const V& vec2) +{ + assert (mln::math::abs(mln::norm::l1(vec1) - mln::norm::l1(vec2)) + < epsilon); +} + +template <typename V, typename S> +void check_l1_distance (const V& vec1, const V& vec2, const S& ref_val) +{ + assert (mln::math::abs(mln::norm::l1_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; + + check_l1(t, u); + check_l1_distance (t, u, d); + + int v[] = {1, -2, 3}; + int w[] = {5, 1, 0}; + + check_l1(v, w); + check_l1_distance (v, w, d); +} Index: tests/Makefile.am --- tests/Makefile.am (revision 1411) +++ tests/Makefile.am (working copy) @@ -84,6 +84,7 @@ io_ppm23 \ io_ppm \ \ + l1 \ labeling_algo \ labeling_estimate \ labeling_foreground \ @@ -270,6 +271,7 @@ io_ppm23_SOURCES = io_ppm23.cc io_ppm_SOURCES = io_ppm.cc +l1_SOURCES = l1.cc labeling_algo_SOURCES = labeling_algo.cc labeling_estimate_SOURCES = labeling_estimate.cc labeling_foreground_SOURCES = labeling_foreground.cc