Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1625 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  [Meta-prog] Les templates-Expressions

 

 

 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Meta-prog] Les templates-Expressions

n°470480
Joel F
Real men use unique_ptr
Posté le 29-07-2003 à 09:16:14  profilanswer
 

Voila, apres le premier post sur la MPT, je récidive avec cette fois quelque chose de plus burné : Les Expressions Templates.
 
Tout d'abord je tiens à signaler que ce post est une tentative d'adaptation des articles de Todd Veldhuizen, ze Boss en MPT, créateur de la librairie Blitz++ en autre.
 
Note : Cette explication fait partie de mes travaux de DEA :D
 
1. Principes
Considérons une fonction qui cacule l'intégrale d'une fonction mathématique.
Un moyen "classique" de l'implementer est d'utiliser un pointeur de fonction :
 

Code :
  1. double integrate( double (*f)(double), double inf, double sup )
  2. {
  3.     double r=0;
  4.     static const double dx = 0.001
  5.     for( double i=inf;i<sup;i+=dx;)  r += dx*f(i);
  6.     return r;
  7. }


 
Simple, efficace, pas de problème. SAUF que si cette fonction est une part critique de votre application, le déréférencement de pointeur va peut etre commencer à devenir tres tres handicapant.
 
Il serait agréable de pouvoir ecrire quelque chose comme :  
 

Code :
  1. Data<double> x;
  2. double r = integrate( 1+1/x,0,10);

 
 
et de voir se dérouler le code de l'intégration :
 

Code :
  1. double r = 0;
  2. for( double i=inf;i<sup;i+=dx;)  r += dx*(1+1/i);


 
Comment faire ?
 
2. Une Solution Elégante : Les Expressions templates
 
Lorsque l'on manipule ce genre d'expression, on peut considérer qu'elles sont l'application d'une grammaire restreinte, contenant juste des valeurs, des opérateurs et des expressions. A partir de la on peut reconstruire un ensemble de classe pour réécrir ces expressions :
 
Il nous faut d'abord une classe pour représenté les variables et les constantes
 

Code :
  1. class Variable
  2. {
  3.    public :
  4.    Variable() {}
  5.    double eval( double x ) const { return x; }
  6. };
  7. class Constante
  8. {
  9.    public :
  10.    Constante( const double& v) : val(v){}
  11.    double eval( double ) { return val; }
  12.    private :
  13.    double val;
  14. };

 
 
Ensuite, il nous font pouvoir coder les divers opérateurs d'une expression
arithmétique. Cantonnons nous au opérateurs bianires de bases : +,-,/,*.
Qu'est-ce qu'un operateur binaire : c'est une opération ET un noeud d'una rbre de syntaxe abstraite ayant deux fils. Ces deux aspects de l'opérateurs se retrouvent dans deux familles de classes :
 

Code :
  1. // classe représentant la caractére binaire d'un opérateur
  2. template<class L,class R,class OP>
  3. class BinaryNode
  4. {
  5.   public :
  6.   BinaryNode( const L& l, const R& r ) : left(l), right(r) {}
  7.   double eval( double x ) { return OP::eval( left.eval(x), right.eval(x));}
  8.   private:
  9.   L left;
  10.   R right;
  11. };
  12. // classes représentant les opérations des opérateurs
  13. struct func_plus
  14. {
  15.     static double eval( double x, double y) { return x+y; }
  16. };
  17. struct func_moins
  18. {
  19.     static double eval( double x, double y) { return x-y; }
  20. };
  21. struct func_fois
  22. {
  23.     static double eval( double x, double y) { return x*y; }
  24. };
  25. struct func_divise
  26. {
  27.     static double eval( double x, double y) { return x/y; }
  28. };


 
Il nous reste à coder une classe pour encapsuler une expression quelconque :
 

Code :
  1. template<class E>
  2. class Expression
  3. {
  4.   public :
  5.   Expression( const E& expr) : xpr(expr) {}
  6.   double eval( double x) { return xpr.eval(x); }
  7.    private :
  8.    E xpr;
  9. };


 
Voila, nous avaons toute nos briques. Comment alors reconstruire à partir de ces classes une expression arithmétique et l'évaluez en ligne ?
 
Trés simplement, nous allons redéfinir les opérateurs +,-,*,/ sur les types Variable, Constante et Expression et reconstruire au sein de ces opérateurs l'arbre de syntaxe de l'expression :
 

Code :
  1. // var+var
  2. inline Expression<BinaryNode<Variable,Variable,func_plus> >
  3. operator+( const Variable& v1, const Variable& v2 )
  4. {
  5.   typedef BinaryNode<Variable,Variable,func_plus> expr_t;
  6.   return Expression<expr_t>( expr_t(v1,v2) );
  7. }
  8. // (expr)+var
  9. template<class E>
  10. inline Expression<BinaryNode<Expression<E>,Variable,func_plus> >
  11. operator+( const Expression<E>& e, const Variable& v )
  12. {
  13.   typedef BinaryNode<Expression<E>,Variable,func_plus> expr_t;
  14.   return Expression<expr_t>( expr_t(e,v) );
  15. }
  16. // var+(expr)
  17. template<class E>
  18. inline Expression<BinaryNode<Variable,Expression<E>,func_plus> >
  19. operator+(  const Variable& v ,const Expression<E>& e)
  20. {
  21.   typedef BinaryNode<Variable,Expression<E>,func_plus> expr_t;
  22.   return Expression<expr_t>( expr_t(v,e) );
  23. }
  24. // expr+expr
  25. template<class E1,class E2>
  26. inline Expression<BinaryNode<Expression<E1>,Expression<E2>,func_plus> >
  27. operator+(  const Expression<E>& e1 ,const Expression<E>& e2)
  28. {
  29.   typedef BinaryNode<Expression<E1>,Expression<E2>,func_plus> expr_t;
  30.   return Expression<expr_t>( expr_t(e1,e2) );
  31. }


 
Voila, rajoutez a cela les opérateurs -,*,/, la surcharge pour gérer les constantes numériques :
 

Code :
  1. // const+expr
  2. // les autres versions sont nécéssaire evidemment
  3. template<class E>
  4. inline Expression<BinaryNode<Constante,Expression<E>,func_fois> >
  5. operator*( const double& c, const Expression<E>& e)
  6. {
  7.   typedef BinaryNode<Constante,Expression<E>,func_fois>  expr_t;
  8.   return Expression<expr_t>( expr_t(Constante(c),e) );
  9. }


 
En écrivant du code comme :
 

Code :
  1. template<class E>
  2. double integrate( Expression<E> e, double inf, double sup)
  3. {
  4.     double r=0;
  5.     static const double dx = 0.001;
  6.     for( double i=inf;i<sup;i+=dx;)  r += dx*e.eval(i);
  7. }


 
Nous générons par instanciation récursives des templates le code suivant :
 

Code :
  1. template<class E>
  2. double integrate( Expression<E> e, double inf, double sup)
  3. {
  4.     double r=0;
  5.     static const double dx = 0.001;
  6.     for( double i=inf;i<sup;i+=dx;)  r += dx*(1+1/i);
  7. }


 
C'est gaagné :D
cette  technique permet aussi via quelques modifications mineurs de
générer du code arithmétique vectoriel ou matriciel inline trés performant, éliminant toutes recopies d'objets temporaires et augmentant les performances d'un facteurs 3 ou 4, faisant du C++ un langage aussi rapide que le C.
 
On peut aussi ecrire des classes pour générer du code inline de parser/lexer à la YACC, des filtres de flux, du TI rapide (oops la c'est mon job :p) bref, des infinités d'applications.
 
EDIt : typo/ortho :p


Message édité par Joel F le 29-07-2003 à 10:19:30
mood
Publicité
Posté le 29-07-2003 à 09:16:14  profilanswer
 

n°470914
Joel F
Real men use unique_ptr
Posté le 29-07-2003 à 14:01:57  profilanswer
 

Bon un exemple concret, un peu brutale mais bon.
le but du jeu est d'utiliser les E.T vu ci dessus pour générer du
code arithmétiques sur des classes du types Vecteur ou matrices.
Style :
 

Code :
  1. std::vector<float> a(10),b(10),c(10);
  2. a = 2*a+b*ln(c);

 
 
et généré un code sans recopie ni objets temporaires, stadire :
 

Code :
  1. std::vector<float> a(10),b(10),c(10);
  2. for(int i=0;i<10;++i)
  3. a[i] = 2*a[i]+b[i]*ln(c[i]);

 
 
ce qu'AUCUN COMPILATEUR NE SAIT FAIRE AUTOMATIQUEMENT je precise ...
 
Voila le code, il utilise le même style de code que précédemment :
 

Code :
  1. class vecDouble
  2. {
  3.     public
  4.     vecDouble( int taille=16) : data(NULL), size(taille) { allocate();}
  5.     virtual ~vecDouble() {deallocate();}
  6.     double& operator[](int i) { return data[i]; }
  7.     double operator[](int i) const { return data[i]; }
  8.     double* begin() { return data; }
  9.     template<class E>
  10.     operator=( const Expression<E>& xpr )
  11.     {
  12.         for( int i=0;i<size;i++)
  13.         {
  14.             data[i] = xpr.eval(i);
  15.         }
  16.        return *this;
  17.     }
  18.     private :
  19.     double* data;
  20.     long size;
  21.     void allocate() { if(data) deallocate(); data = new double[size]; }
  22.     void deallocate() { if(data) delete[] data; }
  23. };
  24. class Variable
  25. {
  26.   public :
  27.   Variable( double* it) : val(it) {}
  28.   double eval( int i ) const { return val[i]; }
  29.    private :
  30.    double* val;
  31. };
  32. class Constante
  33. {
  34.   public :
  35.   Constante( const double& v) : val(v){}
  36.   double eval( int ) { return val; }
  37.   private :
  38.   double val;
  39. };
  40. // classe représentant la caractére binaire d'un opérateur  
  41. template<class L,class R,class OP>
  42. class BinaryNode
  43. {
  44.  public :
  45.  BinaryNode( const L& l, const R& r ) : left(l), right(r) {}
  46.  double eval( int i ) { return OP::eval( left.eval(i), right.eval(i));}
  47.  private:
  48.  L left;
  49.  R right;
  50. };
  51. template<class E>
  52. class Expression
  53. {
  54.  public :
  55.  Expression( const E& expr) : xpr(expr) {}
  56.  double eval( int i) { return xpr.eval(i); }
  57.   private :
  58.   E xpr;
  59. };
  60. // var+var  
  61. inline Expression<BinaryNode<Variable,Variable,func_plus> >
  62. operator+( const vecDouble& v1, const vecDouble& v2 )
  63. {
  64.  typedef BinaryNode<Variable,Variable,func_plus> expr_t;
  65.  return Expression<expr_t>( expr_t(Variable(v1.begin()), Variable (v2.begin())) );
  66. }
  67. // etc ....

 
 
 
Voila quelquechose de + concret peut etre :p
gain de perf garanti pour des tres garande expressions :D


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  [Meta-prog] Les templates-Expressions

 

Sujets relatifs
Spécialisation des templatesMeta-Programmation Template : une introduction ....
[JS] problème avec les expressions régulièresMettre des couleurs dans un prog en mode console ?
Question sur les expressions régulières en PHPexpressions régulières et balises HTML
w3c validator, prog avec des "entity" et "refc delimiter"Voila j'ai a peu près fini mon prog ... download et beta test
une demande de précision pour prog en .net + winform sous 98[ PHP et autre ] Les expressions régulières.
Plus de sujets relatifs à : [Meta-prog] Les templates-Expressions


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR