oln 10.189: Change functions to functors

Index: olena/ChangeLog from Damien Thivolle <damien@lrde.epita.fr> * oln/transforms/shapelets.hh: Change functions to functors, bug fixes. Index: olena/oln/transforms/shapelets.hh --- olena/oln/transforms/shapelets.hh Sun, 06 Jun 2004 23:17:15 +0200 thivol_d (oln/r/10_shapelets. 1.1 600) +++ olena/oln/transforms/shapelets.hh Mon, 07 Jun 2004 19:39:27 +0200 thivol_d (oln/r/10_shapelets. 1.2 600) @@ -7,71 +7,89 @@ #include <oln/core/point2d.hh> #include <oln/level/fill.hh> #include <vector> +#include <bits/stl_function.h> namespace oln { - inline double - hermite(int n, double x) + namespace internal + { + template <class T> + struct hermite : public std::binary_function<T, int, T> + { + T operator()(unsigned n, T x) { - assert(n >= 0); if (n == 0) return 1; if (n == 1) return 2. * x; - return 2. * (x * hermite(n - 1, x) - (n - 1) * hermite(n - 2, x)); + return 2. * x * (*this)(n - 1, x) - 2. * double(n - 1) * (*this)(n - 2, x); } + }; - inline double - fact(double n) + template <class T> + struct fact : public std::unary_function<T, T> + { + T operator() (T n) { precondition(n >= 0); + T res = 1; - double res = n; - - if (n <= 1) - return 1; - while (n > 1) + while (n > 0) { res *= n; n--; } return res; } + }; - inline double - beta(int n, double x) + template <class T> + struct shapelets_beta : public std::binary_function<T, int, T> + { + T operator()(int n, T x) { assert(n >= 0); - const double c = sqrt(pow(2., n) * sqrt(M_PI) * fact(n)); + const double c = sqrt(pow(2.0, n) * sqrt(M_PI) * T(fact<int>()(n))); - assert(finite(hermite(n, x) * exp(x * x / -2.0) / c)); - return hermite(n, x) * exp(x * x / -2.0) / c; + return hermite<T>()(n, x) * exp(x * x / -2.0) / c; } + }; + template <unsigned Dim, class T> + struct shapelets_basis + { + }; - - inline double - shapelet_basis_1d(int n, point1d p, double b) + template <class T> + struct shapelets_basis<1, T> + { + T operator() (int n, point1d p, T b) { assert(n >= 0 && b >= 0); - return beta(n, p.col() / b) / sqrt(b); + return shapelets_beta<T>(n, p.col() / b) / sqrt(b); } + }; - double - shapelet_basis_2d(int m, int n, point2d p, double b) + template <class T> + struct shapelets_basis<2, T> + { + T operator() (int m, int n, T x, T y, T b) { assert(m >= 0 && n >= 0 && b >= 0); - return beta(m, p.col() / b) * beta(n, p.row() / b) / b; + return shapelets_beta<T>()(m, x / b) * shapelets_beta<T>()(n, y / b) / b; } + }; + //FIXME: ima should be non_vectorial template <class I> std::vector<double> - to_shapelet_basis_2d(const oln::abstract::image_with_dim<2, I>& ima, + shapelets(const oln::abstract::image_with_dim<2, I>& ima, int m, int n, double b) { assert(m >= 0 && n >= 0 && b >= 0); + shapelets_basis<2, double> func; // Center of the image const int col = ima.ncols() / 2; @@ -90,7 +108,7 @@ for_all(it) { s += (ima[it] - ntg_max_val(oln_value_type(I)) / 2) * - shapelet_basis_2d(k, l, point2d(it.row() - row, it.col() - col), b); + func(k, l, double(it.row() - row), double(it.col() - col), b); } res[k * n + l] = s; } @@ -120,18 +138,20 @@ // Add the value at the point for_all(it) resf[it] += vec[k * n + l] * - shapelet_basis_2d(k, l, point2d(it.row() - nrows / 2, it.col() - ncols / 2), b); + shapelets_basis<2, double>()(k, l, double(it.row() - nrows / 2), double(it.col() - ncols / 2), b); image2d<D> res(oln::image2d_size(nrows, ncols, 0)); for_all(it) { - if ( !(resf[it] >= 0 && resf[it] < 256)) + if ( !(resf[it] >= 0 && resf[it] <= 255)) { - std::cout << "err:" << resf[it] << std::endl; + std::cout << "- "; + std::cout << "err:" << resf[it]; // min = (resf[it] < min)? resf[it]:min; // max = (resf[it] >max)? resf[it]:max; res[it] = resf[it] < 0 ? 0 : ntg_max_val(D); + std::cout << " -" << std::endl; } else res[it] = resf[it]; @@ -142,3 +162,4 @@ } } +} -- Damien Thivolle damien.thivolle@lrde.epita.fr

C'est bien. Une petite remarque: lors d'un changement de base (dans un sens ou dans l'autre) tu fais nbpixels * calcul entier de chaque shaplet. En enregistrant dans un vecteur temporaire les shapelets, tu ne calcules chaque shapelets qu'une fois (ce qui devrait booster à mort le changement de base). (vecteur d'image 2d de double).
+ struct hermite : public std::binary_function<T, int, T> + { + T operator()(unsigned n, T x) { - assert(n >= 0); if (n == 0) return 1; if (n == 1) return 2. * x; - return 2. * (x * hermite(n - 1, x) - (n - 1) * hermite(n - 2, x)); + return 2. * x * (*this)(n - 1, x) - 2. * double(n - 1) * (*this)(n - 2, x);
Ces deux lignes ne sont pas identiques?
} + };
Dans les functors c'est pratique d'avoir un typedef du type de retour (result_type).
//FIXME: ima should be non_vectorial
Normalement il faudrait une abstract::non_vectorial_image_with_dim. Il n'y en a pas. Actuellement le mieux est de faire une assertion statique (is_a).
template <class I> std::vector<double> - to_shapelet_basis_2d(const oln::abstract::image_with_dim<2, I>& ima, + shapelets(const oln::abstract::image_with_dim<2, I>& ima, int m, int n, double b) { assert(m >= 0 && n >= 0 && b >= 0);
Pense à changer assert en precondition.
+ shapelets_basis<2, double> func;
Peux-tu essayer avec des float pour voir s'il y a une différence (précision/temps)?
- if ( !(resf[it] >= 0 && resf[it] < 256)) + if ( !(resf[it] >= 0 && resf[it] <= 255))
0 => ntg_min_val(T) (! parfois c'est ntg_zero_val(T)!) 255 => ntg_max_val(T) PS: qu'en est-il des tests avec b != 4 sur l'exemple de l'auteur? -- Niels

Akim Demaille wrote:
"Niels" == Niels van Vliet <van-vl_n@lrde.epita.fr> writes:
assert(m >= 0 && n >= 0 && b >= 0);
Pense à changer assert en precondition.
Par ailleurs, c'est pas cool les && : ça empêche de savoir lequel a échoué sans rentrer dans le code.
d'ailleurs (Cf. lrde.olena.bugs) : Thierry GERAUD wrote:
impossible de placer un breakpoint dans mlc/contract.hh car ce fichier n'apparaît pas sous ddd (après compil avec -ggdb ou -ggdb3 et, bien sûr, sans -DNDEBUG)
participants (4)
-
Akim Demaille
-
Damien Thivolle
-
Niels van Vliet
-
Thierry GERAUD