URL:
https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-04-29 Frederic Bour <bour(a)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>