IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les r�ponses en temps r�el, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Template metaprogramming et fonctions du second ordre


Sujet :

C++

Vue hybride

Message pr�c�dent Message pr�c�dent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Ing�nieur g�omaticien
    Inscrit en
    Juillet 2015
    Messages
    34
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Is�re (Rh�ne Alpes)

    Informations professionnelles :
    Activit� : Ing�nieur g�omaticien

    Informations forums :
    Inscription : Juillet 2015
    Messages : 34
    Par d�faut Template metaprogramming et fonctions du second ordre
    Bonjour � tous !

    Je m'excuse par avance de ce post qui risque d'�tre long, et plut�t technique... Elle s'adresse plut�t aux fans de la programmation fonctionnelle .

    J'essaie de reproduire un simulacre de Blitz++, permettant d'effectuer des calculs vectoriels � la sauce Matlab / J.
    Je pense avoir bien compris l'int�r�t des template expressions permettant de regrouper les boucles for et ainsi �viter les allocations de donn�es superflus qui plombent la RAM.
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    template<typename Left, typename Op, typename Right>
    struct X {
       Left leftNode_;
       Right rightNode_;
     
       X(Left t1, Right t2)
       : leftNode_(t1), rightNode_(t2)
       { }
     
       // The trick: delegate the [] operator to subexpressions, recursively
       double operator[](int i)
       {
          return Op::apply(leftNode_[i],rightNode_[i]);
       }
    };
     
    // Simple array class (fixed size)
    struct Array {
       Array(double* data, int N)
       : data_(data), N_(N)
       { }
     
       // Assign an expression to the array
       // It is only at that time than evaluation occurs
       template<typename Left, typename Op, typename Right>
       void operator=(X<Left,Op,Right> expression)
       {
       for (int i=0; i < N_; ++i)
          data_[i] = expression[i];
       }
     
       // Access element
       double operator[](int i)
       {
          return data_[i];
       }
       double* data_;
       int N_;
    };
     
    // Operator +
    template<typename Left>
    X<Left, plus, Array> operator+(Left a, Array b)
    {
    return X<Left, plus, Array>(a,b);
    }
     
    // Tests
    int main()
    {
    double a_data[] = { 2, 3, 5, 9 },
    b_data[] = { 1, 0, 0, 1 },
    c_data[] = { 3, 0, 2, 5 },
    d_data[4];
    Array A(a_data,4), B(b_data,4), C(c_data,4), D(d_data,4);
    D = A + B + C;
    for (int i=0; i < 4; ++i)
    cout << D[i] << " "; // Output --> 6 3 7 15 
    cout << endl;
    return 0;
    }
    (exemple extrait du livre Techniques for Scientific C++, Todd Veldhuizen)

    Je me pose maintenant la question de savoir comment introduire dans ce sch�ma les fonctions du second ordre, comme la r�duction, qui prend une fonction et renvoie une fonction d�riv�e. J'ai d�j� r�alis� un mod�le qui permettait de le faire :
    Une fonction du premier ordre prend un vector (ou array) ou deux vectors et retourne un vector.
    Si elle prend un vector alors elle est monadique, si elle en prend deux elle est dyadique.

    Une fonction du second ordre prend une fonction du premier ordre et en renvoie une fonction du premier ordre d�riv�e. Cette fonction d�riv�e peut potentiellement prendre un argument (monadique), ou bien deux (dyadique).

    "plus" est une fonction du premier ordre, la r�duction une fonction du second ordre.

    En C++14 (merci � jo_link_noir pour ton aide !)
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    #include <iostream>
    #include <vector>
    #include <array>
     
     
    using namespace std;
     
     
    struct Function {
        constexpr Function() noexcept {}
    };
     
     
    struct Function_1st_Order : Function {
        const bool neutral;
        constexpr Function_1st_Order(bool neutral) noexcept :  Function(), neutral(neutral) {}
    };
     
    struct Add : Function_1st_Order {
     
      constexpr Add() noexcept : Function_1st_Order(0) {};
     
      /* Monad : add(a) = a*/
      template<class T>
      auto operator()(const vector<T> & right) const {
        return right;
      }
     
      /* Dyad : add(a, b) = a + b */
      template<class T, class U>
      auto operator()(const vector<T> & right, const vector<U> & left) const {
        size_t n = right.size();
        typedef typename common_type<T, U>::type C;
        vector<C> res(n);
        for(unsigned int i=0; i<n; i++) {
           res[i] = left[i] + right[i];
        }
        return res;
      }
     
    };
     
    template<typename M, typename D>
    struct Derived_Function_1st_Order : Function_1st_Order {
        const M m; /* Monadic use */
        const D d; /* Dyadic use */
     
        Derived_Function_1st_Order(bool neutral, M m, D d) noexcept :  Function_1st_Order(neutral), m(m), d(d) {}
        template<class T>
        auto operator()(const vector<T> & right) const {return m(right);};
     
        template<class T, class U>
        auto operator()(const vector<T> & right, const vector<U> & left) const {return d(right, left);};
    };
     
     
    struct Function_2nd_Order : Function {
      constexpr Function_2nd_Order() noexcept : Function() {};
    };
     
    struct Reduce : Function_2nd_Order {
      constexpr Reduce() noexcept : Function_2nd_Order() {}
      template<class F> // Replace function. Mandatory to avoid virtual template fonction declaration in class function, which is impossible
      constexpr auto operator()(const F & f) const {
     
        auto monad = [f](const auto & cont) {
          auto res = decltype(cont){f.neutral}; // Copy type of cont, without the flags
          size_t n = cont.size();
          for(int i=n-1; i>=0; i--) {
               auto cur = decltype(cont){cont[i]}; // Copy type of cont, without the flags
               res = f(res, cur);
          }
          return res[0];
        };
     
        auto dyad = [f]() {
            // Undefined for the moment
        };
     
        return Derived_Function_1st_Order<decltype(monad), decltype(dyad)>(0, monad, dyad);
      }
     
     
    };
     
    namespace {
        constexpr auto const & reduce = Reduce();
        constexpr auto const & add = Add();
    }
     
    int main()
    {
        auto cumulate = reduce(add);
        vector<int> l = {1,2,3};
        cout << cumulate(l);
        return 0;
    }
    Comment traduire �a en template expression ?
    Je prends le symbole / pour la r�duction, qui prend son argument-fonction � gauche (syntaxe J).
    Pour les classes template, j'appelle :
    X un n�ud d'application d'une fonction du 1er ordre, en mode dyadique : X<Left, Function, Right>
    Y un n�ud d'application d'une fonction du 1er ordre, en mode monadique : Y<Function, Right>
    Z un n�ud d'application d'une fonction du 2�me ordre, en mode monadique : Z<Left, Function>
    Je sais qu'un expression du type C=A+(+/)B, avec A, B et C des tableaux, pourrait �tre pars�e ainsi :
    • C= A + Z<plus, reduce>() B
    • C= A + Y<Z<plus, reduce>, array>()
    • C= Z<array, Y<Z<plus, reduce>, array>()


    Comment effectuer l'�valuation paresseuse pour pouvoir affecter C � la derni�re ligne ? Que mettre dans la classe Z ?

    Auriez-vous des id�es, ne serait-ce qu'un d�but de piste que je pourrais creuser ? Je sais que ce que je demande est plut�t compliqu�, mais je n'ai trouv� aucune r�f�rence en la mati�re, et pour le moment je s�che lamentablement...

    Merci beaucoup !

    Jean

    PS : En effet, en me relisant, c'est long et technique ...

  2. #2
    Membre Expert
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, H�rault (Languedoc Roussillon)

    Informations professionnelles :
    Activit� : Ing�nieur d�veloppement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par d�faut
    Pour avoir du lazy, il faudrait que cumulate(l) retourne une expression lazy<M, std::vector<int>&> et faire un operateur+(T, lazy<M,V>) en cons�quence.

    Ce qui sera compliqu� avec le DSL est la partie optimisation des calculs (r�ordonner, pr�-calculer les sorties de reduce puis �valuer les containers).

Discussions similaires

  1. R�ponses: 2
    Dernier message: 07/04/2011, 15h41
  2. R�ponses: 2
    Dernier message: 22/11/2007, 14h58
  3. Equation diff�rentielle du second ordre
    Par moustiqu3 dans le forum MATLAB
    R�ponses: 1
    Dernier message: 21/05/2007, 09h38
  4. R�ponses: 3
    Dernier message: 22/11/2006, 21h10
  5. Template d'une fonction (!= classe)
    Par Rodrigue dans le forum Langage
    R�ponses: 7
    Dernier message: 08/05/2006, 22h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo