milena r3733: Modification to parametrized functions, functions tutorial WIP

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena ChangeLog: 2009-04-29 Frederic Bour <bour@lrde.epita.fr> Modification to parametrized functions, functions tutorial WIP. * mln/fun/binary.hh, * mln/fun/unary.hh: Modified parameters system. Now distinguish Exact type from Flag type. * mln/fun/binary_param.hh: New. * mln/fun/from_accu.hh: Updated to latest functions syntax. * mln/fun/unary.hh: Modified parameters system. * mln/fun/unary_param.hh: New. * sandbox/fred/functions.html, * sandbox/fred/functions.mkdown: New. Tutorial * sandbox/fred/tests/Makefile: Added one test. * sandbox/fred/tests/wip.cc: New. --- mln/fun/binary.hh | 4 mln/fun/binary_param.hh | 99 ++++++++ mln/fun/from_accu.hh | 36 --- mln/fun/unary.hh | 4 mln/fun/unary_param.hh | 97 ++++++++ sandbox/fred/functions.html | 478 ++++++++++++++++++++++++++++++++++++++++++ sandbox/fred/functions.mkdown | 441 ++++++++++++++++++++++++++++++++++++++ sandbox/fred/tests/Makefile | 2 sandbox/fred/tests/wip.cc | 25 ++ 9 files changed, 1155 insertions(+), 31 deletions(-) Index: trunk/milena/mln/fun/unary.hh =================================================================== --- trunk/milena/mln/fun/unary.hh (revision 3732) +++ trunk/milena/mln/fun/unary.hh (revision 3733) @@ -49,8 +49,8 @@ } - template <typename F> - struct unary: mln::Meta_Function_v2v< F > + template <typename F, typename E = F> + struct unary: mln::Meta_Function_v2v< E > { typedef F flag; typedef mln_trait_fun_param(flag) param; Index: trunk/milena/mln/fun/unary_param.hh =================================================================== --- trunk/milena/mln/fun/unary_param.hh (revision 0) +++ trunk/milena/mln/fun/unary_param.hh (revision 3733) @@ -0,0 +1,97 @@ +// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory (LRDE) +// +// 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 F 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. +#include "unary.hh" + +#ifndef MLN_FUN_UNARY_PARAM_HH +# define MLN_FUN_UNARY_PARAM_HH + +# include <mln/fun/unary.hh> +# include <mln/fun/param.hh> + +namespace mln +{ + + namespace fun + { + + template <typename F, typename Param, typename Storage = void, typename E = F> + struct unary_param: unary< unary_param<F,Param,Storage,E>, E> + { + unary_param() + { + } + + template <typename U> + unary_param(const U& param) + { + this->init(param); + } + + }; + + template <typename F, typename Param, typename E> + struct parameter< unary_param<F,Param,void,E> > + { + typedef Param param; + typedef void storage; + }; + + template <typename F, typename Param, typename Storage, typename E> + struct parameter< unary_param<F,Param,Storage,E> > + { + typedef Param param; + typedef Storage storage; + + template <typename U> + storage compute(const U& u) + { + return F::compute_param(u); + } + }; + + } + + namespace trait + { + + namespace next + { + + template <typename F, typename Param, typename Storage, typename E, typename T> + struct set_precise_unary_<mln::fun::unary_param<F,Param,Storage,E>, T> + { + typedef mln_trait_nunary(F, T) ret; + }; + + } // end of namespace mln::trait::next + + } // end of namespace mln::trait + + +} // end of namespace mln + +#endif /* ! MLN_FUN_UNARY_PARAM_HH */ Index: trunk/milena/mln/fun/binary.hh =================================================================== --- trunk/milena/mln/fun/binary.hh (revision 3732) +++ trunk/milena/mln/fun/binary.hh (revision 3733) @@ -39,8 +39,8 @@ namespace fun { - template <typename F> - struct binary : mln::Meta_Function_vv2v< binary<F> > + template <typename F, typename E = F> + struct binary : mln::Meta_Function_vv2v< E > { typedef F flag; typedef mln_trait_fun_storage(flag) storage; Index: trunk/milena/mln/fun/from_accu.hh =================================================================== --- trunk/milena/mln/fun/from_accu.hh (revision 3732) +++ trunk/milena/mln/fun/from_accu.hh (revision 3733) @@ -28,10 +28,8 @@ #ifndef MLN_FUN_FROM_ACCU_HH # define MLN_FUN_FROM_ACCU_HH -# include <mln/fun/unary.hh> +# include <mln/fun/unary_param.hh> # include <mln/core/concept/accumulator.hh> -# include <mln/math/acos.hh> -# include <mln/math/cos.hh> namespace mln { @@ -39,13 +37,15 @@ // from_accu: wrap an accumulator into a function namespace fun { + template <typename A> struct from_accu : unary_param<from_accu<A>, A*> { from_accu() : unary_param<from_accu<A>, A*>() {}; from_accu(A* a) : unary_param<from_accu<A>, A*>(a) {}; }; - } + + } // end of namespace mln::fun namespace trait { @@ -58,38 +58,22 @@ typedef set_unary_ ret; typedef typename A::result result; typedef typename A::argument argument; - typedef A* param; - - set_unary_() - { - } - - set_unary_(const param& accu) - : accu_(accu) - { - } + typedef A* param_t; - result read(const argument& x) const + static inline + result read(const param_t& accu_, const argument& x) { mln_precondition(accu_ != 0); accu_->take(x); return accu_->to_result (); } - - void init(const param& accu) - { - accu_ = accu; - } - - protected: - A* accu_; }; - } + } // end of namespace mln::trait::next - } + } // end of namespace mln::trait -} +} // end of namespace mln #endif /* ! MLN_FUN_FROM_ACCU_HH */ \ No newline at end of file Index: trunk/milena/mln/fun/binary_param.hh =================================================================== --- trunk/milena/mln/fun/binary_param.hh (revision 0) +++ trunk/milena/mln/fun/binary_param.hh (revision 3733) @@ -0,0 +1,99 @@ +// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory (LRDE) +// +// 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 F 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. +#include "unary.hh" + +#ifndef MLN_FUN_BINARY_PARAM_HH +# define MLN_FUN_BINARY_PARAM_HH + +# include <mln/fun/binary.hh> +# include <mln/fun/param.hh> + +namespace mln +{ + + namespace fun + { + + template <typename F, typename Param, typename Storage = void, typename E = F> + struct binary_param: binary<binary_param<F,Param,Storage>, E> + { + typedef F flag; + + binary_param() + { + } + + template <typename U> + binary_param(const U& param) + { + this->init(param); + } + + }; + + template <typename F, typename Param, typename E> + struct parameter< binary_param<F,Param,void,E> > + { + typedef Param param; + typedef void storage; + }; + + template <typename F, typename Param, typename Storage, typename E> + struct parameter< binary_param<F,Param,Storage,E> > + { + typedef Param param; + typedef Storage storage; + + template <typename U> + storage compute(const U& u) + { + return F::compute_param(u); + } + }; + + } + + namespace trait + { + + namespace next + { + + template <typename F, typename Param, typename Storage, typename E, typename T1, typename T2> + struct set_precise_binary_<mln::fun::binary_param<F,Param,Storage,E>, T1, T2> + { + typedef mln_trait_nbinary(F, T1, T2) ret; + }; + + } // end of namespace mln::trait::next + + } // end of namespace mln::trait + + +} // end of namespace mln + +#endif /* ! MLN_FUN_BINARY_PARAM_HH */ Index: trunk/milena/sandbox/fred/tests/wip.cc =================================================================== --- trunk/milena/sandbox/fred/tests/wip.cc (revision 0) +++ trunk/milena/sandbox/fred/tests/wip.cc (revision 3733) @@ -0,0 +1,25 @@ +// Meta functions test +#include <mln/accu/min.hh> +#include <mln/fun/accu_result.hh> +#include <mln/fun/from_accu.hh> +#include <mln/fun/math/cos.hh> +#include <mln/fun/compose.hh> +#include <mln/core/var.hh> + +#include <iostream> + +#define dbg_print(val) std::cout << #val << "\n\t -> \t" << (val) << std::endl +int main() +{ + mln::accu::min<int> min; + mln::fun::cos cos; + mln::fun::accu_result result; + mln::fun::from_accu< mln::accu::min<int> > frommin(&min); + + mln_VAR(cosfrommin, cos(frommin)); + + for (int i = 5; i > 0; i--) + std::cout << cosfrommin(i) << std::endl; + for (int i = 1; i <= 5; i++) + std::cout << cosfrommin(i) << std::endl; +} \ No newline at end of file Index: trunk/milena/sandbox/fred/tests/Makefile =================================================================== --- trunk/milena/sandbox/fred/tests/Makefile (revision 3732) +++ trunk/milena/sandbox/fred/tests/Makefile (revision 3733) @@ -1,4 +1,4 @@ -TARGETS=fun.bin thru.bin cos.bin +TARGETS=fun.bin thru.bin cos.bin wip.bin OLENADIR=../../../.. MILENADIR=$(OLENADIR)/milena Index: trunk/milena/sandbox/fred/functions.mkdown =================================================================== --- trunk/milena/sandbox/fred/functions.mkdown (revision 0) +++ trunk/milena/sandbox/fred/functions.mkdown (revision 3733) @@ -0,0 +1,441 @@ +Ecriture de fonctions +===================== + +# Fichiers + +## Fonctions unaires et binaires +* *mln/fun/unary.hh* +* *mln/fun/binary.hh* + +Définitions des meta-fonctions unaires et binaires + +* *mln/fun/spe/binary.hh* +* *mln/fun/spe/unary.hh* + +Modèles des fonctions unaires et binaires, instantiés par les meta-fonctions + +## Fonctions paramétrées +* *mln/fun/param.hh* + +Définitions concernant les fonctions paramétrées. + +* *mln/fun/unary\_param.hh* +* *mln/fun/binary\_param.hh* + +Raccourcis d'écritures pour les fonctions paramétrées + +## Composition +* *mln/fun/compose.hh* + +Fonction permettant de composer deux autres fonctions. + +* *mln/fun/composition.hh* + +Modèle du résultat de la composition de deux fonctions + +## Traits +* *mln/trait/fun.hh* + +Accès à diverses propriétés de la fonction. + +mln\_trait\_fun\_is\_assignable, mln\_trait\_fun\_is\_parametrable: de type metal::bool\_ + +mln\_trait\_fun\_lvalue, mln\_trait\_fun\_param, mln\_trait\_fun\_storage: typedef si la fonction répond à cette propriété, void sinon + + +# Pure + +L'ajout d'une nouvelle fonction s'effectue en deux étapes: +- la création d'un «flag», en général une structure vide héritant d'un modèle de meta-fonction. + + struct succ : mln::fun::unary<succ> {}; + +- la définition de la fonction sur un ou plusieurs types d'argument. Détaillée ci-après. + +## Unaire + + #include <mln/fun/unary.hh> + +Création du «flag» (on suppose que l'on se trouve dans le namespace mln::fun) : + + struct succ : unary<succ> {}; + +Définition sur les entiers, dans le namespace mln::trait::next : + + namespace mln + { + namespace trait + { + namespace next + { + template <typename T> + struct set_unary_<mln::fun::succ, Integer, T> + { + typedef set_unary_ ret; + + typedef T argument; + typedef T result; + + static result read(const argument& a) + { + return a + 1; + } + }; + } + } + } + +Ou, pour uniquement travailler sur les entiers non signés: + + namespace mln + { + namespace trait + { + namespace next + { + template <typename T> + struct set_precise_unary_<mln::fun::succ, unsigned int> + { + typedef set_precise_unary_ ret; + + typedef unsigned int argument; + typedef unsigned int result; + + static result read(const argument& a) + { + return a + 1; + } + }; + } + } + } + +Définitions attendues: + +- typedef **ret**: la classe résultat. On peut ainsi renvoyer vers une autre classe, c'est alors dans celle-ci que devront se trouver les autres définitions. + +- typedef **argument**: type de l'argument (unique) que prend la fonction. + +- typedef **result**: type du résultat de la fonction + +- méthode **read**: méthode donnant le résultat de l'application de la fonction. + + Elle doit répondre au prototype suivant: + static result read(const argument&); + +Le modèle mln::fun::unary prend deux paramètres: + template \<typename F, typename E = F\> + +Le premier est le drapeau, le second est le type exact (dans l'utilisation courante, les deux sont égaux). + + +## Binaire + + #include <mln/fun/binary.hh> + +Création du «flag» (on suppose que l'on se trouve dans le namespace mln::fun) : + + struct plus : binary<plus> {}; + +Définition sur les scalaires, dans le namespace mln::trait::next : + + namespace mln + { + namespace trait + { + namespace next + { + template <typename T1, typename T2> + struct set_binary_<mln::fun::plus, Scalar, T1, Scalar, T2> + { + typedef set_binary_ ret; + + typedef T1 argument1; + typedef T2 argument2; + typedef mln_sum(T1, T2) result; + + static result read(const argument1& a1, const argument2& a2) + { + return a1 + a2; + } + }; + } + } + } + +Ou, pour uniquement travailler entre entier non signé et flottant: + + namespace mln + { + namespace trait + { + namespace next + { + template <typename T> + struct set_precise_binary_<mln::fun::plus, unsigned int, float> + { + typedef set_precise_binary_ ret; + + typedef unsigned int argument1; + typedef float argument2; + typedef float result; + + static result read(const argument1& a, const argument2& b) + { + return a + b; + } + }; + } + } + } + +Définitions attendues: + +- typedef **ret**: la classe résultat. On peut ainsi renvoyer vers une autre classe, c'est alors dans celle-ci que devront se trouver les autres définitions. + +- typedef **argument1**: type du premier argument que prend la fonction. + +- typedef **argument2**: type du second argument que prend la fonction. + +- typedef **result**: type du résultat de la fonction + +- méthode **read**: méthode donnant le résultat de l'application de la fonction. + + Elle doit répondre au prototype suivant: + static result read(const argument1&, const argument2&); + +# Unaire affectable + +Une fonction unaire peut parfois être affectable. Cela autorise des écritures telles que: + cos(x) = 1; + red(col) = 255; + +Le terme "affectable" inclue la notion d'inversibilité de la fonction. +Pour supporter ce comportement, il faut ajouter aux définitions d'une fonction unaire pure les éléments suivants: + +- typedef argument& **lvalue**: une fonction n'est considérée comme affectable que si ce typedef existe. Il donne de plus le type de l'argument de la fonction dans la notation "f(x) = y". + +- méthode **write**: méthode dont le premier argument est accessible en lecture/écriture et dont le second argument donne le résultat attendu de la méthode read après l'application de write (cad, write(x, 1) => read(x) == 1). + + Elle doit répondre au prototype suivant: + static void write(lvalue, const result&); + +# Paramétrable + +La définition des paramètres s'effectue en spécialisant le modèle mln::fun::parameter<Flag>. + + struct cos_ax; + + template <> + struct parameter<cos_ax> + { + typedef int param; + }; + + struct cos_ax : unary<cos_ax> + { + cos_ax(int a) : unary<cos_ax>(a) {}; + }; + +Le modèle devant être spécialisé avant la définition de la meta-fonction, l'écriture peut sembler lourde. Un raccourcis est présenté dans les sections *unary_param* et *binary_param*. Il est nécessaire d'écrire le constructeur! + +## Unaire + +La présence d'un paramètre ajoute un argument aux méthodes read et write: la valeur donnée au paramètre est transmise en premier argument à read et, si applicable, à write. + +Les prototypes deviennent: + static result read(const param&, const argument&); + static void write(const param&, lvalue, const result&); + +### Exemple, implémentation de cos_ax + + template <typename S> + struct set_unary_<mln::fun::cos_ax, Scalar, S> + { + typedef set_unary_ ret; + + typedef S argument; + typedef S& lvalue; + typedef double result; + + static result read(const int& a, const argument& x) + { + return math::cos(x) * a; + } + + static void write(const int& a, lvalue l, const result& r) + { + l = math::acos(r) / a; + } + }; + +### unary_param + +L'écriture passant par un modèle extérieur pouvant paraître lourde, le modèle unary_param permet de simplifier celle-ci. + unary_param<Flag,Param,Storage,E> + +E est le type exact, par défaut identique à Flag. Storage est expliqué dans la section éponyme. + +Param est le type désiré pour le paramètre, similaire à parameter<T>::param. +Ainsi, cos_ax peut se déclarer de manière plus conçise: + + struct cos_ax : unary_param<cos_ax,int> + { + cos_ax(int a) : unary_param<cos_ax,int>(a) {}; + }; + +## Binaire + +De même pour les fonctions binaires, la présence d'un paramètre ajoute un argument à la méthode read: la valeur donnée au paramètre est transmise en premier argument à read. + +Le prototype devient: + static result read(const param&, const argument1&, const argument2&); + +### Exemple, interpolation linéaire + + struct lin_interp; + + template <> + struct parameter<lin_interp> + { + typedef float param; + }; + + struct lin_interp : binary<lin_interp> + { + lin_interp(float a) : binary<lin_interp>(a) {}; + }; + + template <typename S1, typename S2> + struct set_binary_<mln::fun::lin_interp, Scalar, S1, Scalar, S2> + { + typedef set_binary_ ret; + + typedef S1 argument1; + typedef S2 argument2; + typedef double result; + + static result read(const float& a, const argument1& f1, const argument2& f2) + { + return a * f1 + (1.0f - a) * f2; + } + }; + +### binary_param + +L'écriture passant par un modèle extérieur pouvant paraître lourde, le modèle binary_param permet de simplifier celle-ci. + binary_param<Flag,Param,Storage,E> + +E est le type exact, par défaut identique à Flag. Storage est expliqué dans la section éponyme. + +Param est le type désiré pour le paramètre, similaire à parameter<T>::param. +Ainsi, lin_interp peut se déclarer de manière plus conçise: + + struct lin_interp : binary_param<lin_interp,float> + { + lin_interp(float a) : binary_param<lin_interp,float>(a) {}; + }; + +## «Storage» + +Lors de la spécialisation de mln::fun::parameter, on peut définir le type "storage". Cela permet d'utiliser un type différent pour le stockage du paramètre, et éventuellement d'effectuer un calcul. +La présence de "storage" impose celle d'une méthode "compute": + static double compute(const param&); + +### Exemple + +Dans le namespace mln::fun: + + struct log_n; + + template <> + struct parameter<log_n> + { + typedef int param; + typedef double storage; + + static double compute(const param& base) + { + return std::log(base); + } + }; + + struct log_n : unary<log_n> + { + log_n(int n) : unary<log_n>(n) {}; + }; + +Dans le namespace mln::trait::next: + + template <typename S> + struct set_unary_<mln::fun::log_n, Scalar, S> + { + typedef set_unary_ ret; + + typedef S argument; + typedef S& lvalue; + typedef double result; + + static result read(const double& log_base, const argument& x) + { + return std::log(x) / log_base; + } + + static void write(const double& log_base, lvalue l, const result& r) + { + l = std::exp(r * log_base); + } + }; + +### ... avec unary_param + +Dans le namespace mln::fun: + + struct log_n : unary_param<log_n, int, double> + { + log_n(int n) : unary<log_n>(n) {}; + + static double compute_param(const int& n) + { + return std::log(base); + } + }; + +Dans le namespace mln::trait::next: + + template <typename S> + struct set_unary_<mln::fun::log_n, Scalar, S> + { + typedef set_unary_ ret; + + typedef S argument; + typedef S& lvalue; + typedef double result; + + static result read(const double& log_base, const argument& x) + { + return std::log(x) / log_base; + } + + static void write(const double& log_base, lvalue l, const result& r) + { + l = std::exp(r * log_base); + } + }; + +# Composition + +La composition de fonctions opère entre une meta-fonction A unaire et une fonction B, éventuellement meta, unaire ou binaire. Le résultat est une fonction de l'arité de B, ou meta-fonction si B en est une. + +Le type de la composée "F . G" est: + mln::fun::internal::composition<Category_F, F, Category_G, G> + +La manière la plus simple de composer est d'appliquer la seconde fonction à la première: + cos(cos) est l'équivalent de "cos . cos" + +Il existe également une fonction compose: + + mln::fun::compose compose; + compose(cos,cos) en est un autre équivalent + +# «thru» \ No newline at end of file Index: trunk/milena/sandbox/fred/functions.html =================================================================== --- trunk/milena/sandbox/fred/functions.html (revision 0) +++ trunk/milena/sandbox/fred/functions.html (revision 3733) @@ -0,0 +1,478 @@ +<h1>Ecriture de fonctions</h1> + +<h1>Fichiers</h1> + +<h2>Fonctions unaires et binaires</h2> + +<ul> +<li><em>mln/fun/unary.hh</em></li> +<li><em>mln/fun/binary.hh</em></li> +</ul> + +<p>Définitions des meta-fonctions unaires et binaires</p> + +<ul> +<li><em>mln/fun/spe/binary.hh</em></li> +<li><em>mln/fun/spe/unary.hh</em></li> +</ul> + +<p>Modèles des fonctions unaires et binaires, instantiés par les meta-fonctions</p> + +<h2>Fonctions paramétrées</h2> + +<ul> +<li><em>mln/fun/param.hh</em></li> +</ul> + +<p>Définitions concernant les fonctions paramétrées.</p> + +<ul> +<li><em>mln/fun/unary_param.hh</em></li> +<li><em>mln/fun/binary_param.hh</em></li> +</ul> + +<p>Raccourcis d'écritures pour les fonctions paramétrées</p> + +<h2>Composition</h2> + +<ul> +<li><em>mln/fun/compose.hh</em></li> +</ul> + +<p>Fonction permettant de composer deux autres fonctions.</p> + +<ul> +<li><em>mln/fun/composition.hh</em></li> +</ul> + +<p>Modèle du résultat de la composition de deux fonctions</p> + +<h2>Traits</h2> + +<ul> +<li><em>mln/trait/fun.hh</em></li> +</ul> + +<p>Accès à diverses propriétés de la fonction.</p> + +<p>mln_trait_fun_is_assignable, mln_trait_fun_is_parametrable: de type metal::bool_</p> + +<p>mln_trait_fun_lvalue, mln_trait_fun_param, mln_trait_fun_storage: typedef si la fonction répond à cette propriété, void sinon</p> + +<h1>Pure</h1> + +<p>L'ajout d'une nouvelle fonction s'effectue en deux étapes: +- la création d'un «flag», en général une structure vide héritant d'un modèle de meta-fonction.</p> + +<pre><code> struct succ : mln::fun::unary<succ> {}; +</code></pre> + +<ul> +<li>la définition de la fonction sur un ou plusieurs types d'argument. Détaillée ci-après.</li> +</ul> + +<h2>Unaire</h2> + +<pre><code> #include <mln/fun/unary.hh> +</code></pre> + +<p>Création du «flag» (on suppose que l'on se trouve dans le namespace mln::fun) :</p> + +<pre><code> struct succ : unary<succ> {}; +</code></pre> + +<p>Définition sur les entiers, dans le namespace mln::trait::next :</p> + +<pre><code> namespace mln + { + namespace trait + { + namespace next + { + template <typename T> + struct set_unary_<mln::fun::succ, Integer, T> + { + typedef set_unary_ ret; + + typedef T argument; + typedef T result; + + static result read(const argument& a) + { + return a + 1; + } + }; + } + } + } +</code></pre> + +<p>Ou, pour uniquement travailler sur les entiers non signés:</p> + +<pre><code> namespace mln + { + namespace trait + { + namespace next + { + template <typename T> + struct set_precise_unary_<mln::fun::succ, unsigned int> + { + typedef set_precise_unary_ ret; + + typedef unsigned int argument; + typedef unsigned int result; + + static result read(const argument& a) + { + return a + 1; + } + }; + } + } + } +</code></pre> + +<p>Définitions attendues:</p> + +<ul> +<li><p>typedef <strong>ret</strong>: la classe résultat. On peut ainsi renvoyer vers une autre classe, c'est alors dans celle-ci que devront se trouver les autres définitions.</p></li> +<li><p>typedef <strong>argument</strong>: type de l'argument (unique) que prend la fonction.</p></li> +<li><p>typedef <strong>result</strong>: type du résultat de la fonction</p></li> +<li><p>méthode <strong>read</strong>: méthode donnant le résultat de l'application de la fonction.</p> + +<pre><code>Elle doit répondre au prototype suivant: + static result read(const argument&); +</code></pre></li> +</ul> + +<p>Le modèle mln::fun::unary prend deux paramètres: + template \<typename F, typename E = F\></p> + +<p>Le premier est le drapeau, le second est le type exact (dans l'utilisation courante, les deux sont égaux).</p> + +<h2>Binaire</h2> + +<pre><code> #include <mln/fun/binary.hh> +</code></pre> + +<p>Création du «flag» (on suppose que l'on se trouve dans le namespace mln::fun) :</p> + +<pre><code> struct plus : binary<plus> {}; +</code></pre> + +<p>Définition sur les scalaires, dans le namespace mln::trait::next :</p> + +<pre><code> namespace mln + { + namespace trait + { + namespace next + { + template <typename T1, typename T2> + struct set_binary_<mln::fun::plus, Scalar, T1, Scalar, T2> + { + typedef set_binary_ ret; + + typedef T1 argument1; + typedef T2 argument2; + typedef mln_sum(T1, T2) result; + + static result read(const argument1& a1, const argument2& a2) + { + return a1 + a2; + } + }; + } + } + } +</code></pre> + +<p>Ou, pour uniquement travailler entre entier non signé et flottant:</p> + +<pre><code> namespace mln + { + namespace trait + { + namespace next + { + template <typename T> + struct set_precise_binary_<mln::fun::plus, unsigned int, float> + { + typedef set_precise_binary_ ret; + + typedef unsigned int argument1; + typedef float argument2; + typedef float result; + + static result read(const argument1& a, const argument2& b) + { + return a + b; + } + }; + } + } + } +</code></pre> + +<p>Définitions attendues:</p> + +<ul> +<li><p>typedef <strong>ret</strong>: la classe résultat. On peut ainsi renvoyer vers une autre classe, c'est alors dans celle-ci que devront se trouver les autres définitions.</p></li> +<li><p>typedef <strong>argument1</strong>: type du premier argument que prend la fonction.</p></li> +<li><p>typedef <strong>argument2</strong>: type du second argument que prend la fonction.</p></li> +<li><p>typedef <strong>result</strong>: type du résultat de la fonction</p></li> +<li><p>méthode <strong>read</strong>: méthode donnant le résultat de l'application de la fonction.</p> + +<pre><code>Elle doit répondre au prototype suivant: + static result read(const argument1&, const argument2&); +</code></pre></li> +</ul> + +<h1>Unaire affectable</h1> + +<p>Une fonction unaire peut parfois être affectable. Cela autorise des écritures telles que: + cos(x) = 1; + red(col) = 255;</p> + +<p>Le terme "affectable" inclue la notion d'inversibilité de la fonction. +Pour supporter ce comportement, il faut ajouter aux définitions d'une fonction unaire pure les éléments suivants:</p> + +<ul> +<li><p>typedef argument& <strong>lvalue</strong>: une fonction n'est considérée comme affectable que si ce typedef existe. Il donne de plus le type de l'argument de la fonction dans la notation "f(x) = y".</p></li> +<li><p>méthode <strong>write</strong>: méthode dont le premier argument est accessible en lecture/écriture et dont le second argument donne le résultat attendu de la méthode read après l'application de write (cad, write(x, 1) => read(x) == 1).</p> + +<pre><code>Elle doit répondre au prototype suivant: + static void write(lvalue, const result&); +</code></pre></li> +</ul> + +<h1>Paramétrable</h1> + +<p>La définition des paramètres s'effectue en spécialisant le modèle mln::fun::parameter<Flag>.</p> + +<pre><code> struct cos_ax; + + template <> + struct parameter<cos_ax> + { + typedef int param; + }; + + struct cos_ax : unary<cos_ax> + { + cos_ax(int a) : unary<cos_ax>(a) {}; + }; +</code></pre> + +<p>Le modèle devant être spécialisé avant la définition de la meta-fonction, l'écriture peut sembler lourde. Un raccourcis est présenté dans les sections <em>unary_param</em> et <em>binary_param</em>. Il est nécessaire d'écrire le constructeur!</p> + +<h2>Unaire</h2> + +<p>La présence d'un paramètre ajoute un argument aux méthodes read et write: la valeur donnée au paramètre est transmise en premier argument à read et, si applicable, à write.</p> + +<p>Les prototypes deviennent: + static result read(const param&, const argument&); + static void write(const param&, lvalue, const result&);</p> + +<h3>Exemple, implémentation de cos_ax</h3> + +<pre><code> template <typename S> + struct set_unary_<mln::fun::cos_ax, Scalar, S> + { + typedef set_unary_ ret; + + typedef S argument; + typedef S& lvalue; + typedef double result; + + static result read(const int& a, const argument& x) + { + return math::cos(x) * a; + } + + static void write(const int& a, lvalue l, const result& r) + { + l = math::acos(r) / a; + } + }; +</code></pre> + +<h3>unary_param</h3> + +<p>L'écriture passant par un modèle extérieur pouvant paraître lourde, le modèle unary<em>param permet de simplifier celle-ci. + unary</em>param<Flag,Param,Storage,E></p> + +<p>E est le type exact, par défaut identique à Flag. Storage est expliqué dans la section éponyme.</p> + +<p>Param est le type désiré pour le paramètre, similaire à parameter<T>::param. +Ainsi, cos_ax peut se déclarer de manière plus conçise:</p> + +<pre><code> struct cos_ax : unary_param<cos_ax,int> + { + cos_ax(int a) : unary_param<cos_ax,int>(a) {}; + }; +</code></pre> + +<h2>Binaire</h2> + +<p>De même pour les fonctions binaires, la présence d'un paramètre ajoute un argument à la méthode read: la valeur donnée au paramètre est transmise en premier argument à read.</p> + +<p>Le prototype devient: + static result read(const param&, const argument1&, const argument2&);</p> + +<h3>Exemple, interpolation linéaire</h3> + +<pre><code> struct lin_interp; + + template <> + struct parameter<lin_interp> + { + typedef float param; + }; + + struct lin_interp : binary<lin_interp> + { + lin_interp(float a) : binary<lin_interp>(a) {}; + }; + + template <typename S1, typename S2> + struct set_binary_<mln::fun::lin_interp, Scalar, S1, Scalar, S2> + { + typedef set_binary_ ret; + + typedef S1 argument1; + typedef S2 argument2; + typedef double result; + + static result read(const float& a, const argument1& f1, const argument2& f2) + { + return a * f1 + (1.0f - a) * f2; + } + }; +</code></pre> + +<h3>binary_param</h3> + +<p>L'écriture passant par un modèle extérieur pouvant paraître lourde, le modèle binary<em>param permet de simplifier celle-ci. + binary</em>param<Flag,Param,Storage,E></p> + +<p>E est le type exact, par défaut identique à Flag. Storage est expliqué dans la section éponyme.</p> + +<p>Param est le type désiré pour le paramètre, similaire à parameter<T>::param. +Ainsi, lin_interp peut se déclarer de manière plus conçise:</p> + +<pre><code> struct lin_interp : binary_param<lin_interp,float> + { + lin_interp(float a) : binary_param<lin_interp,float>(a) {}; + }; +</code></pre> + +<h2>«Storage»</h2> + +<p>Lors de la spécialisation de mln::fun::parameter, on peut définir le type "storage". Cela permet d'utiliser un type différent pour le stockage du paramètre, et éventuellement d'effectuer un calcul. +La présence de "storage" impose celle d'une méthode "compute": + static double compute(const param&);</p> + +<h3>Exemple</h3> + +<p>Dans le namespace mln::fun:</p> + +<pre><code> struct log_n; + + template <> + struct parameter<log_n> + { + typedef int param; + typedef double storage; + + static double compute(const param& base) + { + return std::log(base); + } + }; + + struct log_n : unary<log_n> + { + log_n(int n) : unary<log_n>(n) {}; + }; +</code></pre> + +<p>Dans le namespace mln::trait::next:</p> + +<pre><code> template <typename S> + struct set_unary_<mln::fun::log_n, Scalar, S> + { + typedef set_unary_ ret; + + typedef S argument; + typedef S& lvalue; + typedef double result; + + static result read(const double& log_base, const argument& x) + { + return std::log(x) / log_base; + } + + static void write(const double& log_base, lvalue l, const result& r) + { + l = std::exp(r * log_base); + } + }; +</code></pre> + +<h3>... avec unary_param</h3> + +<p>Dans le namespace mln::fun:</p> + +<pre><code> struct log_n : unary_param<log_n, int, double> + { + log_n(int n) : unary<log_n>(n) {}; + + static double compute_param(const int& n) + { + return std::log(base); + } + }; +</code></pre> + +<p>Dans le namespace mln::trait::next:</p> + +<pre><code> template <typename S> + struct set_unary_<mln::fun::log_n, Scalar, S> + { + typedef set_unary_ ret; + + typedef S argument; + typedef S& lvalue; + typedef double result; + + static result read(const double& log_base, const argument& x) + { + return std::log(x) / log_base; + } + + static void write(const double& log_base, lvalue l, const result& r) + { + l = std::exp(r * log_base); + } + }; +</code></pre> + +<h1>Composition</h1> + +<p>La composition de fonctions opère entre une meta-fonction A unaire et une fonction B, éventuellement meta, unaire ou binaire. Le résultat est une fonction de l'arité de B, ou meta-fonction si B en est une.</p> + +<p>Le type de la composée "F . G" est: + mln::fun::internal::composition<Category_F, F, Category_G, G></p> + +<p>La manière la plus simple de composer est d'appliquer la seconde fonction à la première: + cos(cos) est l'équivalent de "cos . cos"</p> + +<p>Il existe également une fonction compose:</p> + +<pre><code> mln::fun::compose compose; + compose(cos,cos) en est un autre équivalent +</code></pre> + +<h1>«thru»</h1>
participants (1)
-
Frederic Bour