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 :

Heritage + specialisation partielle de patron + doxygen


Sujet :

C++

  1. #1
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut Heritage + specialisation partielle de patron + doxygen
    Bonjour à toutes et à tous !

    J'essaie de documenter une portion de mon code avec Doxygen, et je rencontre quelques problèmes. En fait je me demande si Doxygen est capable d'y voir clair dans cette structure syntaxique (je sais pas si elle est pertinente bout en bout, mais elle m'a permis de supprimer des duplications de code en héritant l'implémentation commune aux deux stratégies de simulation).

    Donc on y va:

    Deux types de stratégies pour lesquelles je voudrais un comportement différent:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      namespace strategy {
        struct individual_based {
          using value_type = unsigned int;
        };
     
        struct mass_based {
          using value_type = double;
        };
      }
    Ensuite la classe de base qui récupère toute l'implémentation commune aux deux variantes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template<typename A, typename B, typename Strategy>
    class CommonBase {
      // méthodes communes  
    };
    Le template général (je sais pas si ça a un nom), qui est vide.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     template<typename A, typename B, typename Strategy>
     class MaClasse : public CommonBase<A, B, Strategy>
     { 
    // vide
      };
    Et enfin les spécialisations:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
      template<typename A, typename B>
      class MaClasse<A, B, strategy::individual_based> : public CommonBase<Space, Time, strategy::individual_based>
      {
         // une implémentation particulière d'une méthode foo est rajoutée ici
      }
     
      template<typename A, typename B>
      class MaClasse<A, B, strategy::mass_based> : public CommonBase<Space, Time, strategy::mass_based>
      {
         // une autre implémentation de foo ici
      }
    Le truc c'est que Doxygen ne détecte pas les deux dernières spécialisations, et donc je suis incapable de générer la doc pour MaClasse<A, B, strategy::individual_based>::foo et MaClasse<A, B, strategy::mass_based>::foo. Ce qui est bien embêtant parce que c'est un peu le point important de la manip quand même

    Je sais que le pauvre Doxygen en voit de toute les couleurs avec les templates et que c'est pas vraiment sa faute, mais si j'avais un work-around, ce serait super !

    Qu'en pensez-vous ?

    En vous remerciant d'avance,
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Ajoute simplement un cartouche doxygen à tes spécialisations
    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
     
    /** @brief partial specialization for individual based strategies
      *
      * @tparam A data type for ...
      * @tparam B data type for ...
      *
      * some longer description (which difference with unspecialized class?)
      */
    template<typename A, typename B>
      class MaClasse<A, B, strategy::individual_based> : public CommonBase<Space, Time, strategy::individual_based>
      {
         // une implémentation particulière d'une méthode foo est rajoutée ici
      }
     
    /** @brief partial specialization for mass based strategies
      *
      * @tparam A data type for ...
      * @tparam B data type for ...
      *
      * some longer description (which difference with unspecialized class?)
      */
      template<typename A, typename B>
      class MaClasse<A, B, strategy::mass_based> : public CommonBase<Space, Time, strategy::mass_based>
      {
         // une autre implémentation de foo ici
      }
    Cela devrait inciter doxygen à générer la documentation correctement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut
    Salut,

    Oui j'avais écrit les cartouches, mais cela semble être ignoré par Doxygen ...
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ca, c'est pour le moins bizare, parce que chez moi, un code proche de
    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
    #ifndef TEST_HPP
    #define TEST_HPP
    /** @brief basic unspecialized struture
      *
      * @tparam T first type to use
      * @tparam U second type to use
      *
      */
    template <typename T, typename U>
    struct Test{
        T a;
        U b;
    };
    /** @brief partial specialization to be used wit ints
      *
      * @tparam T first type to be used
      *
      */
    template <typename T>
    struct Test<T, int>{
        T a;
        long b;
     
    };
    /** @brief partial specialization to be used wit reals
      *
      * @tparam T first type to be used
      *
      */
    template <typename T>
    struct Test<T, float>{
        T a;
        long double b;
     
    };
    #endif
    me fournit bien la liste de classes
    • Test Basic unspecialized struture
    • Test< T, float > Partial specialization to be used wit reals
    • Test< T, int > Partial specialization to be used wit ints

    Et le seul reproche que l'on puisse faire au résultat (dans toute sa simplicité), c'est de n'avoir pas les diagrammes de collaboration entre les spécialisations partielles et la classe d'origine.

    Et encore, je subodore que c'est parce qu'il n'y a aucune implémentation des classes (partiellement) spécializée qui est faite

    Pourrais tu nous montrer comment tu organise tes cartouches?

    PS: il faut parfois revenir à une liste ou à une page plus générale actualisée pour voir les ajouts dans la documentation
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut
    Merci de te pencher sur mon problème
    Tu vas peut-être halluciner un peu sur les cartouches (les blocs de doc sont plus gros que les blocs de code ...), et je n'ai pas une très bonne idée de ce qu'est une bonne doc et elle certainement pas encore tout a fait complète, donc tout commentaire est bienvenu !

    Un exemple de cartouche pour une spécialisation partielle:

    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
      /**
      * \brief Demographic history where populations levels are assumed high enough to be considered as divisible masses.
      *
      *  \ingroup demography
      *
      * \tparam Space    Demes identifiers.
      * \tparam Time     EqualityComparable, CopyConstructible.
      *
      * \details $N$ is initialized by setting \f$N(.,t_0)\f$ the initial distribution
      * of individuals across demes at the first time \f$t_0\f$.
      * Typically for a biological invasion, this is restricted to the introduction site(s)
      * with the number of introduced individuals. For endemic species, paleoclimatic
      * distribution can be considered as starting points. The number of descendants
      * \f$\tilde{N}_{x}^{t}\f$ in each deme is sampled in a distribution conditionally
      * to a function of the the local density of parents. Non-overlapping generations
      * are considered (the parents die just after reproduction). The children dispersal
      * is done by sampling their destination in a multinomial law, that defines
      * \f$ \Phi_{x,y}^t \f$ the number of individuals going from \f$x\f$ to \f$y\f$ at time \f$t\f$:
      * \f[ (\Phi_{x,y}^{t})_{y\in  X} \sim \mathcal{M}(\tilde{N}_{x}^{t},(m_{xy})_y) ~. \f]
      * The term \f$ (m_{xy})_y \f$ denotes the parameters of the multinomial law,
      * giving for an individual in \f$x\f$ its probability to go to \f$y\f$.
      * These probabilities are given by the dispersal law with parameter \f$\theta\f$:
      * \f[
      * \begin{array}{cclcl}
      * m  & : &  X^2 & \mapsto & R_{+} \\
      * &   &    (x,y)     & \mapsto & m^{\theta}(x,y)  ~. \\
      * \end{array}
      * \f]
      * After migration, the number of individuals in deme \f$x\f$ is defined by the total number of individuals converging to \f$x\f$:
      * \f[
      * N(x,t+1) = \displaystyle \sum_{i\in X} \Phi_{i,x}^{t}~.
      * \f\]
      *
      * \section Example
      * \snippet demography/test/History/History_test.cpp Example
      * \section Output
      * \include demography/test/History/History_test.output
      */
      template<typename Space, typename Time>
      class History<Space, Time, strategy::mass_based> : public BaseHistory<Space, Time, strategy::mass_based>{
      // blabla
      };
    A toute fin utile, le code complet (désolé pour les doublons de doc, mais j'ai un peu tout essayer du coup c'est clairement le bazar):

    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
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
     
    namespace quetzal {
    namespace demography {
     
      namespace strategy {
     
        /*!
         * \brief Traits class for individual based demographic history simulation, strategy suited for small number of individuals in the landscape (small populations).
         * \ingroup demography
         *
         * \details Simulate the demographic history with an individual-based strategy: each
         * individual is dispersed individually.
         * \par History Initialization:
         * The population size history\f$N\f$ is initialized by setting \f$N(.,t_0)\f$, the initial distribution of individuals across demes at the
         * first time of the history \f$t_0\f$. Typically for a biological invasion,
         * this is restricted to the introduction site(s) with the number of introduced
         * individuals. For endemic species, paleoclimatic distribution can be considered
         * as starting points.
         *
         * \par Growth:
         * The offspring number \f$ \tilde{N}_{x}^{t} \f$ in each deme is freely defined by the user. It can for example be
         * sampled in a distribution conditionally to a function of the local density of
         * parents. Non-overlapping generations are considered (the parents die just after reproduction).
         *
         * \par Dispersal:
         *  The children dispersal is done by sampling their destination in a multinomial
         *  law, that defines \f$ \Phi_{x,y}^t \f$, the number of individuals going from
         *  \f$x\f$ to \f$y\f$ at time \f$t\f$:
         *
         * \f[ (\Phi_{x,y}^{t})_{y\in X} \sim \mathcal{M}(\tilde{N}_{x}^{t},(m_{xy})_y) ~. \f]
         *
         * The term \f$ (m_{xy})_y \f$ denotes the parameters of the multinomial law,
         * giving for an individual in \f$x\f$ its proability to go to \f$y\f$.
         * These probabilities are given by the dispersal law with parameter \f$\theta\f$:
         *
         * \f[
         * \begin{array}{cclcl}
         * m  & : &  X^2 & \mapsto & R_{+} \\
         * &   &    (x,y)     & \mapsto & m^{\theta}(x,y)  ~. \\
         * \end{array}
         * \f]
         *
         * After migration, the number of individuals in deme \f$x\f$ is defined by
         * the total number of individuals converging to \f$x\f$:
         *
         * \f[
         * N(x,t+1) = \displaystyle \sum_{i\in X} \Phi_{i,x}^{t}~.
         * \f]
         * \section Example
         * \snippet demography/test/History/Individual_based_history_test.cpp Example
         * \section Output
         * \include demography/test/History/Individual_based_history_test.output
         */
        struct individual_based {
          using value_type = unsigned int;
        };
     
        /*!
        * \brief Traits class for simulating the demographic history of importnat masses of populations.
        * \ingroup demography
        *
        * \details Simulate the demographic history by considering that populations of individuals are divisible masses,
        *  leading to faster simulations.
        *
        * \par Intialization:
        * \f$N\f$ is initialized by setting \f$N(.,t_0)\f$ the initial distribution
        * of individuals across demes at the first time \f$t_0\f$.
        * Typically for a biological invasion, this is restricted to the introduction site(s)
        * with the number of introduced individuals. For endemic species, paleoclimatic
        * distribution can be considered as starting points.
        *
        * \par Growth:
        * The offspring number \f$\tilde{N}_{x}^{t}\f$ in each deme is freely defined by
        * the user. For example, it can be sampled in a distribution conditionally
        * to a function of the local density of parents. Non-overlapping generations
        * are considered (the parents die just after reproduction).
        *
        * \par Dispersal:
        * The children dispersal is done by splitting the population masses according
        * to their migration probabilities, defining
        * \f$ \Phi_{x,y}^t \f$, the population flow going from \f$x\f$ to \f$y\f$ at time \f$t\f$:
        * \f[ (\Phi_{x,y}^{t})_{y\in  X} = (\tilde{N}_{x}^{t} \times m_{xy})_{y\in  X} ~. \f]
        * The term \f$ m_{xy} \f$ denotes the parameters of the transition kernel,
        * giving for an individual in \f$x\f$ its probability to go to \f$y\f$.
        * These probabilities are given by the dispersal law with parameter \f$\theta\f$:
        * \f[
        * \begin{array}{cclcl}
        * m  & : &  X^2 & \mapsto & R_{+} \\
        * &   &    (x,y)     & \mapsto & m^{\theta}(x,y)  ~. \\
        * \end{array}
        * \f]
        * After migration, the population size in deme \f$x\f$ is defined by the sum of population flows converging to \f$x\f$:
        * \f[
        * N(x,t+1) = \displaystyle \sum_{i\in X} \Phi_{i,x}^{t}~.
        * \f]
        * \section Example
        * \snippet demography/test/History/Mass_based_history_test.cpp Example
        * \section Output
        * \include demography/test/History/Mass_based_history_test.output
        */
        struct mass_based {
          using value_type = double;
        };
     
      }
     
      /*!
       * \brief Base class for spatially explicit and forward-in time population history simulators.
       *
       * \tparam Space    Demes identifiers.
       * \tparam Time     EqualityComparable, CopyConstructible.
       * \tparam Strategy    Strategy use for simulating populations dynamics
       *
       * \details Is used as an implementation base of the specialized simulation strategies.
       *
       * \ingroup demography
       *
       */
      template<typename Space, typename Time, typename Strategy>
      class BaseHistory {
     
          public:
     
            //! \typedef strategy used for simulating populations dynamics
            using strategy_type = Strategy;
     
            //! \typedef type of the population flows database
            using flow_type = Flow<Space, Time, typename strategy_type::value_type>;
     
            //! \typedef type of the population size database
            using pop_sizes_type = PopulationSize<Space, Time, typename strategy_type::value_type>;
     
            //! \typedef space type
            using coord_type = Space;
     
            //! \typedef time type
            using time_type = Time;
     
            //! \typedef type of the discrete distribution used inside the backward dispersal kernel
            using discrete_distribution_type = quetzal::random::DiscreteDistribution<coord_type>;
     
            //! \typedef Backward dispersal kernel type
            using backward_kernel_type = quetzal::random::TransitionKernel<time_type, discrete_distribution_type>;
     
          protected:
     
            // Need to be accessed by the expand method
            std::unique_ptr<pop_sizes_type> m_sizes;
            std::unique_ptr<flow_type> m_flows;
            std::vector<Time> m_times;
            std::unique_ptr<backward_kernel_type> m_kernel;
     
          private:
     
            auto make_backward_distribution(coord_type const& x, time_type const& t) const
            {
     
              std::vector<double> weights;
              std::vector<coord_type> support;
     
              weights.reserve(m_flows->flux_to(x,t).size());
              support.reserve(m_flows->flux_to(x,t).size());
     
              for(auto const& it : m_flows->flux_to(x,t) )
              {
                support.push_back(it.first);
                weights.push_back(static_cast<double>(it.second));
              }
     
              return discrete_distribution_type(std::move(support),std::move(weights));
            }
     
          public:
     
            /**
              * \brief Constructor initializing the demographic database.
              * \param x the coordinate of introduction
              * \param t the introduction time
              * \param N the population size at coordinate x at time t
              * \section Example
              * \snippet demography/test/History/History_test.cpp Example
              * \section Output
              * \include demography/test/History/History_test.output
              */
            BaseHistory(coord_type const& x, time_type const& t, typename strategy_type::value_type N):
            m_sizes(std::make_unique<pop_sizes_type>()),
            m_flows(std::make_unique<flow_type>()),
            m_kernel(std::make_unique<backward_kernel_type>())
            {
              m_sizes->operator()(x,t) = N;
              m_times.push_back(t);
            }
     
            /**
              * \brief Read-only access to the demographic flows database
              */
            flow_type const& flows() const
            {
              return *m_flows;
            }
     
            /**
              * \brief Read and write access to the demographic flows database
              */
            flow_type & flows()
            {
              return *m_flows;
            }
     
            /**
              * \brief Read-only access to the demographic sizes database.
              * \remark Can be used for composition into time dependent growth functions.
              */
            const pop_sizes_type & pop_sizes() const
            {
              return *m_sizes;
            }
     
            /**
              * \brief Read-and-write access to the demographic sizes database
              */
            pop_sizes_type & pop_sizes()
            {
              return *m_sizes;
            }
     
            /**
              * \brief First time recorded in the foward-in-time database history.
              */
            time_type const& first_time() const
            {
              return m_times.front();
            }
     
            /**
              * \brief Last time recorded in the foward-in-time database history.
              */
            time_type const& last_time() const
            {
              return m_times.back();
            }
     
            /**
              * \brief Samples a coordinate from the backward-in-time transition matrix
              *
              * \details The transition matrix is computed from the demographic flows
              * database. The returned coordinate object will basically answer the question:
              * when an individual is found in \f$x\f$ at time \f$t\f$, where could it
              * have been at time \f$t-1\f$ ?
              * Let \f$ X \f$ be the geographic space and \f$\Phi_{x,y}^t\f$ be the number of individuals going
              * from coordinate \f$x \in X \f$ to coordinate \f$y\f$ at time \f$t\f$.
              * Knowing that a child node \f$c\f$ is found in \f$ j \in X \f$, the probability for its parent
              * \f$p\f$ to be in \f$i\in X \f$ is: \f$ P( p \in i ~|~ e \in j) = \frac{\Phi_{i, j}^{t}}{ \sum_{k} \Phi_{k, j}^{t} } ~.\f$
              * \section Example
              * \snippet demography/test/History/Mass_based_history_test.cpp Example
              * \section Output
              * \include demography/test/History/Mass_based_history_test.output
              */
            template<typename Generator>
            coord_type backward_kernel(coord_type const& x, time_type t, Generator& gen)
            {
              --t;
              assert(m_flows->flux_to_is_defined(x,t));
              if( ! m_kernel->has_distribution(x, t))
              {
                m_kernel->set(x, t, make_backward_distribution(x, t));
              }
              return m_kernel->operator()(gen, x, t);
            }
     
      };
     
      /**
      * \brief Demographic history simulated from an individual-based strategy (each individual is dispersed individually).
      *
      * \tparam Space    Demes identifiers.
      * \tparam Time     EqualityComparable, CopyConstructible.
      * \tparam Strategy    Strategy used for simulating populations dynamics
      *
      * \details Inherit from this class and specialize the Strategy template parameter
      *
      * \ingroup demography
      *
      */
      template<typename Space, typename Time, typename Strategy>
      class History : public BaseHistory<Space, Time, Strategy>
      {
      };
     
      /**
      * \brief Demographic history simulated from an individual-based strategy (each individual is dispersed individually).
      *
      * \tparam Space    Demes identifiers.
      * \tparam Time     EqualityComparable, CopyConstructible.
      *
      * \ingroup demography
      *
      * \details $N$ is initialized by setting \f$ N(.,t_0) \f$ the initial distribution
      * of individuals across demes at the first time \f$ t_0 \f$.
      * Typically for a biological invasion, this is restricted to the introduction site(s)
      * with the number of introduced individuals. For endemic species, paleoclimatic
      * distribution can be considered as starting points. The number of descendants
      * \f$ \tilde{N}_{x}^{t} \f$ in each deme is sampled in a distribution conditionally
      * to a function of the the local density of parents. Non-overlapping generations
      * are considered (the parents die just after reproduction). The children dispersal
      * is done by sampling their destination in a multinomial law, that defines
      * \f$ \Phi_{x,y}^t \f$ the number of individuals going from \f$ x \f$ to \f$ y \f$ at time \f$ t \f$:
      * \f[ (\Phi_{x,y}^{t})_{y\in X} \sim \mathcal{M}(\tilde{N}_{x}^{t},(m_{xy})_y) ~. \f]
      * The term \f$ (m_{xy})_y \f$ denotes the parameters of the multinomial law,
      * giving for an individual in \f$x\f$ its proability to go to \f$y\f$.
      * These probabilities are given by the dispersal law with parameter \f$\theta\f$:
      * \f[
      * \begin{array}{cclcl}
      * m  & : &  X^2 & \mapsto & R_{+} \\
      * &   &    (x,y)     & \mapsto & m^{\theta}(x,y)  ~. \\
      * \end{array}
      * \f]
      * After migration, the number of individuals in deme \f$x\f$ is defined by the total number of individuals converging to \f$x\f$:
      * \f[
      * N(x,t+1) = \displaystyle \sum_{i\in X} \Phi_{i,x}^{t}~.
      * \f\]
      *
      * \section Example
      * \snippet demography/test/History/History_test.cpp Example
      * \section Output
      * \include demography/test/History/History_test.output
      */
      template<typename Space, typename Time>
      class History<Space, Time, strategy::individual_based> : public BaseHistory<Space, Time, strategy::individual_based>
      {
        using BaseHistory<Space, Time, strategy::individual_based>::BaseHistory;
     
      public:
     
        /**
          * \brief Expands the demographic database.
          *
          * \tparam Space    Demes identifiers.
          * \tparam Time     EqualityComparable, CopyConstructible.
          *
          * \exception std::domain_error if the population goes extincted before the simulation is completed.
          *
          * \param nb_generations the number of generations to simulate
          * \param sim_growth a functor simulating \f$\tilde{N}_{x}^{t}\f$.
          *
          * The functor can possibly internally use a reference on the population sizes database to represent the time dependency.
          * The signature of the function should be equivalent to the following:
          * `unsigned int sim_growth(Generator &gen, const coord_type &x, const time_type &t);`
          *
          * \param kernel a functor representing the dispersal location kernel that simulates the coordinate of the next location conditionally to the current location.
          * The signature should be equivalent to `coord_type kernel(Generator &gen, const coord_type &x, const time_type &t);`
          *
          * \section Example
          * \snippet demography/test/History/History_test.cpp Example
          * \section Output
          * \include demography/test/History/History_test.output
          */
        template<typename Growth, typename Dispersal, typename Generator>
        void expand(unsigned int nb_generations, Growth sim_growth, Dispersal kernel, Generator& gen)
        {
          for(unsigned int g = 0; g < nb_generations; ++g)
          {
            auto t = this->last_time();
            auto t_next = t; ++ t_next;
     
            this->m_times.push_back(t_next);
     
            unsigned int landscape_individuals_count = 0;
     
            // TODO : optimize the definition_space function (for loop)
            for(auto x : this->m_sizes->definition_space(t) )
            {
              auto N_tilde = sim_growth(gen, x, t);
              landscape_individuals_count += N_tilde;
              if(N_tilde >= 1)
              {
                for(unsigned int ind = 1; ind <= N_tilde; ++ind)
                {
                  auto y = kernel(gen, x, t);
                  this->m_flows->add_to_flux_from_to(x, y, t, 1);
                  this->m_sizes->operator()(y, t_next) += 1;
                }
              }
            }
     
            if(landscape_individuals_count == 0)
            {
              throw std::domain_error("Landscape populations went extinct before sampling");
            }
     
          }
        }
     
      };
     
     
      /**
      * \brief Demographic history where populations levels are assumed high enough to be considered as divisible masses.
      *
      *  \ingroup demography
      *
      * \tparam Space    Demes identifiers.
      * \tparam Time     EqualityComparable, CopyConstructible.
      *
      * \details $N$ is initialized by setting \f$N(.,t_0)\f$ the initial distribution
      * of individuals across demes at the first time \f$t_0\f$.
      * Typically for a biological invasion, this is restricted to the introduction site(s)
      * with the number of introduced individuals. For endemic species, paleoclimatic
      * distribution can be considered as starting points. The number of descendants
      * \f$\tilde{N}_{x}^{t}\f$ in each deme is sampled in a distribution conditionally
      * to a function of the the local density of parents. Non-overlapping generations
      * are considered (the parents die just after reproduction). The children dispersal
      * is done by sampling their destination in a multinomial law, that defines
      * \f$ \Phi_{x,y}^t \f$ the number of individuals going from \f$x\f$ to \f$y\f$ at time \f$t\f$:
      * \f[ (\Phi_{x,y}^{t})_{y\in  X} \sim \mathcal{M}(\tilde{N}_{x}^{t},(m_{xy})_y) ~. \f]
      * The term \f$ (m_{xy})_y \f$ denotes the parameters of the multinomial law,
      * giving for an individual in \f$x\f$ its probability to go to \f$y\f$.
      * These probabilities are given by the dispersal law with parameter \f$\theta\f$:
      * \f[
      * \begin{array}{cclcl}
      * m  & : &  X^2 & \mapsto & R_{+} \\
      * &   &    (x,y)     & \mapsto & m^{\theta}(x,y)  ~. \\
      * \end{array}
      * \f]
      * After migration, the number of individuals in deme \f$x\f$ is defined by the total number of individuals converging to \f$x\f$:
      * \f[
      * N(x,t+1) = \displaystyle \sum_{i\in X} \Phi_{i,x}^{t}~.
      * \f\]
      *
      * \section Example
      * \snippet demography/test/History/History_test.cpp Example
      * \section Output
      * \include demography/test/History/History_test.output
      */
      template<typename Space, typename Time>
      class History<Space, Time, strategy::mass_based> : public BaseHistory<Space, Time, strategy::mass_based>{
     
        using BaseHistory<Space, Time, strategy::mass_based>::BaseHistory;
     
    public:
     
      /**
        * \brief Expands the demographic database,
        * \details $N$ is initialized by setting \f$N(.,t_0)\f$ the initial distribution
        * of individuals across demes at the first time \f$t_0\f$.
        * Typically for a biological invasion, this is restricted to the introduction site(s)
        * with the number of introduced individuals. For endemic species, paleoclimatic
        * distribution can be considered as starting points. The number of descendants
        * \f$\tilde{N}_{x}^{t}\f$ in each deme is sampled in a distribution conditionally
        * to a function of the the local density of parents. Non-overlapping generations
        * are considered (the parents die just after reproduction). The children dispersal
        * is done by sampling their destination in a multinomial law, that defines
        * \f$ \Phi_{x,y}^t \f$ the population flow going from \f$x\f$ to \f$y\f$ at time \f$t\f$:
        * \f[ (\Phi_{x,y}^{t})_{y\in  X} = (\tilde{N}_{x}^{t}*m_{xy})_{y\in  X} ~. \f]
        * The term \f$ m_{xy} \f$ denotes the parameters of the transition kernel,
        * giving for an individual in \f$x\f$ its probability to go to \f$y\f$.
        * These probabilities are given by the dispersal law with parameter \f$\theta\f$:
        * \f[
        * \begin{array}{cclcl}
        * m  & : &  X^2 & \mapsto & R_{+} \\
        * &   &    (x,y)     & \mapsto & m^{\theta}(x,y)  ~. \\
        * \end{array}
        * \f]
        * After migration, the population size in deme \f$x\f$ is defined by the sum of population flows converging to \f$x\f$:
        * \f[
        * N(x,t+1) = \displaystyle \sum_{i\in X} \Phi_{i,x}^{t}~.
        * \f\]
        * \param nb_generations the number of generations to simulate
        * \param sim_growth a functor simulating \f$\tilde{N}_{x}^{t}\f$.
        * The functor can possibly internally use a reference on the population sizes database to represent the time dependency.
        * The signature of the function should be equivalent to the following:
        * `double sim_growth(Generator &gen, const coord_type &x, const time_type &t);`
        * \param kernel a functor representing the dispersal location kernel that simulates the coordinate of the next location conditionally to the current location.
        * The signature should be equivalent to `coord_type kernel(Generator &gen, const coord_type &x, const time_type &t);`.
        * The expression `kernel.support(time_type const& t)` must be valid and return an iterable container of geographic coordinates
        * indicating the transition kernel state space at time \f$t\f$.
        * \section Example
        * \snippet demography/test/History/History_test.cpp Example
        * \section Output
        * \include demography/test/History/History_test.output
        */
        template<typename Growth, typename Dispersal, typename Generator>
        void expand(unsigned int nb_generations, Growth sim_growth, Dispersal kernel, Generator& gen)
        {
          for(unsigned int g = 0; g < nb_generations; ++g)
          {
            auto t = this->last_time();
            auto t_next = t; ++ t_next;
     
            this->m_times.push_back(t_next);
     
            for(auto x : this->m_sizes->definition_space(t) )
            {
              auto N_tilde = sim_growth(gen, x, t);
              for(auto y : kernel.state_space(t) )
              {
                auto m = kernel(x, y, t);
                this->m_flows->set_flux_from_to(x, y, t, m*N_tilde);
                this->m_sizes->operator()(y, t_next) += m*N_tilde;
              }
            }
          }
        }
     
      };
     
    } // namespace demography
    } // namespace quetzal
     
     
    #endif
    Je vais virer toutes les cartouches en recommencer en suivant ton modèle, des fois que ça change quelque chose !

    [EDIT] Humpf oui apparemment faire le menage a l'air de changer quelque chose !!! Bien sur je ne comprend pas pourquoi ça marche maintenant et pas avant Bon, j'attend un peu avant de mettre le sujet en résolu mais apparemment c'est tout bon ! Merci !
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    En fait, la bonne manière d'écrire un cartouche est de fournir à l'utilisateur (de ton type ou de ta fonction) les informations dont il a besoin pour pouvoir l'utiliser correctement.

    Les informatinons @brief et @ingroup ont donc parfaitement leur place: la première permet d'avoir une description rapide, y compris dans certaines listes, la deuxième permet de regrouper correctement les différentes informations.

    Les informations @tparam ont également leur place, car elle permettent d'indiquer le type des données que l'utilisateur peut utiliser. Par contre, leur intitulé pourrait être revu pour que l'utilisateur n'ait aucun doute (l'identifiant de type en lui même pourrait d'ailleurs peut-être êtreplus cohérent par rapport à son usage )

    Elles pourraient prendre la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /** @tparam Space Demographic population type (: representts some clearer informations, maybe? )
      * @tparam Time comparaison scheme type (: allow   some clearer informations, maybe? )
      */
    Comme tu le vois, j'essaye d'indiquer clairement à l'utilisateur les types auxquels cette classe s'attend à être confrontée. Mais, du coup, il y a des précondition qui doivent être remplies à la compilation pour que tout se passe correctement. On va donc les rajouter, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    /** @pre Time is equality comparable and copy constructible
      */
    Concernant ton information @details

    A priori, tu n'as pas vraiment besoin de citer nommément cette partie.

    Mais, surtout, tu dois veiller à fournir "suffisamment" d'informations à l'utilisateur pour qu'il puisse se dire "ok, c'est cette classe que je dois utiliser pour ce que je veux faire" tout en évitant de l"assommer avec un tas de détails dont il n'a pas besoin.

    Il se fout pas mal de la manière dont tu calcule le nombre de descendants, de la loi polynominale ou de la loi de dispertion utilisée. Il veut juste savoir que cette classe lui permettra de déterminer si une population donnée risque de provoquer une épidémie et la rapidité avec laquelle elle se répandra (si j'ai bien compris ).

    Si il sait déjà cela, il y a de fortes chances pour que l'utilisateur "normal" puisse décider en connaissance de cause d'utiliser ta classe, et comment il devra s'y prendre.

    Après, on peut toujours considérer que
    la normalité n'est que la moyenne de toutes les tares
    et que l'on risque donc d'être confronté à des utilisateurs
    • qui ne sont pas habitués à manipuler les classes template (et auxquels un petit exemple d'utilisation ferait le plus grand bien)
    • qui s'intéressent aux formules mathématiques que tu auras utilisées
    • et même à certains qui aimeront connaître le "pourquoi du quoi" et le "pourquoi du comment" (autrement dit,les besoins -- voire les raisons des besoins -- qui t'on mené à créer cette classe ainsi que le raisonnement conceptuel qui t'a mené à le faire de la manière don tu t'y es pris)

    Mais on pourrait presque dire qu'ils sont "exceptionnellement (choisi le terme que tu veux ici)"

    Si tu tiens à les soulager de leur souffrance morale, tu dois faire apparaître clairement que les informations que tu t'apprêtes à leur donner ne sont pas essentielles à la bonne utilisation de la classe de manière à éviter que "l'utilisateur normal" ne perde du temps à lire (et à essayer de comprendre) des informations dont il n'a en réalité absolument rien à battre.

    L'idéal est alors de les mettre dans une section @sa (pour See Also ) en ne mettant que des liens vers les informations en question. Cela pourrait se faire sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /** @sa @ref demography/test/History/History_test.cpp
      * @sa @ref History_rules_and_formulas
      * @sa @ref History_needs_and_conception
      */
    en ayant, bien sur, documenté le fichier History_tes.cpp (qui donnera lui-même accès à History_test.output, voire qui en incluera le contenu), ainsi qu'une section (ou une sous-section) nommée History_rules_and_formulas et une autre section (ou sous-section) History_needs_and_conception qui contiendront les informations "pertinentes" pour le point de vue envisagé.

    Au final, comme j'ai séparé chaque partie, ton cartouche pourrait ressembler à quelque chose comme
    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
    /** \brief Demographic history where populations levels are assumed high enough to be considered as divisible masses.
      *
      * @tparam Space Demographic population type (: representts some clearer informations, maybe? )
      * @tparam Time comparaison scheme type (: allow   some clearer informations, maybe? )
      *
      *
      * Typically for a biological invasion, this is restricted to the introduction site(s)
      * with the number of introduced individuals. 
      *
      *For endemic species, paleoclimatic distribution can be considered as starting points. 
      * The number of descendants in each deme is sampled in a distribution conditionally
      * to a function of the the local density of parents. 
      *
      * Non-overlapping generations are considered (the parents die just after reproduction). 
      *
      * The children dispersal is done by sampling their destination in a probability scheme
      * to see a given number of children to fly from the starting point to some destination.
      *
      * @sa @ref demography/test/History/History_test.cpp
      * @sa @ref History_rules_and_formulas
      * @sa @ref History_needs_and_conception
      */
    (il qse peut d'ailleurs que j'aie été aussi prolixe lors de l'écriture de ce cartouche que lors de la rédaction de cette intervention )

    Quelques remarques en vrac :

    On essaye de se limiter à 80 caractères pour la description @brief...

    Au lieu d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /** \brief Traits class for individual based demographic history simulation, strategy suited for small number of individuals in the landscape (small populations).
    *
    */
    tu aurais pu te limiter au stricte minimum, comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /** @brief traits used by strategies suited for small popultations
      *
      */
    car cette description brêve apparaîtra dans la liste des classes, sans doute tout près du trait de politique dont la description breve serait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /** @brief traits used by strategies suited for large popultations
      *
      */
    et que, si l'utilisateur ne sait pas trop quel trait de politique utiliser une fois qu'il connait cette information, il pourra toujours aller voir du coté de la description longue (par exemple, pour se rendre compte que l'on considère que la population est petite en dessous de XXX individu/Ha et que l'on considère que la population est importante au delà de YYY individus/Ha )

    Et comme je m'en voudrais de ne pas te le donner, voici un exemple du genre de cartouches que tu dois créer. Certains sont sans doute perfectibles, mais cela t'aidera (je l'espère) à comprendre ce que l'utilisateur veut savoir
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut
    Hola oui c'est ultra minimaliste comme doc (ça me plaît bien mieux que les gros pâté de doc dans le code source !). Merci, je vais pomper le style dans ton projet

    Ok pour la section see also.

    on risque donc d'être confronté à des utilisateurs

    • qui ne sont pas habitués à manipuler les classes template (et auxquels un petit exemple d'utilisation ferait le plus grand bien)
    • qui s'intéressent aux formules mathématiques que tu auras utilisées
    • et même à certains qui aimeront connaître le "pourquoi du quoi" et le "pourquoi du comment" (autrement dit,les besoins -- voire les raisons des besoins -- qui t'on mené à créer cette classe ainsi que le raisonnement conceptuel qui t'a mené à le faire de la manière don tu t'y es pris)

    Mais on pourrait presque dire qu'ils sont "exceptionnellement (choisi le terme que tu veux ici)"
    "exceptionnellement académiques" ?

    J'imagine que les choses commencent à bouger (au moins dans certains domaines), mais oui l'utilisateur potentiel qui voudrait utiliser cette librairie est a priori un chercheur en bio, et qui a toutes les raisons du monde de ne pas pouvoir/vouloir connaître la technique (templates, politiques, traits, spécialisation partielle, design, abstraction), et à s'intéresser par contre beaucoup au modèle simulatoire sous-jacent, et à se demander pourquoi une telle prise de tête conceptuelle sur le code et pourquoi est ce qu'il peut pas voir si History c'est une matrice, une liste ou un vecteur. C'est un peu déstabilisant d'essayer avoir la double casquette (on se prend assez souvent des réflexions du genre "c'est de la technique, pas de la science" ) mais j'ai bon espoir de voir la communauté évoluer dans les années à venir (on n'aura pas trop le choix de toute manière, vu le chemin et l'importance que prend la recherche computationnelle en biologie). En Angleterre, ils ont même commencer à monter une communauté (Research Software Engineers) pour se fédérer et pouvoir communiquer sur l'importance et les particularités de notre job, qui échappe un peu à l'intuition du chercheur traditionnel, et essayer de lancer des réseaux de recrutement plus adaptés.

    Bref du coup j'essaie à la fois de me faciliter la vie en tant que dev (donc j'ai pas vraiment envie d'expliquer pourquoi une politique) mais en même temps si je ne peux décemment pas me couper de ma communauté recherche (donc il faut que j'explique quand même ce que c'est une politique). Et du coup ça prend du temps alors que c'est pas directement valorisable dans mon CV. Et du temps j'en ai peu, puisqu'il faut prioriser les publications. Dans les comités de sélection en science, on préférera trois publications avec des jolis graphiques non reproductible et un code illisible plutôt qu'un article, un code propre, deux tutoriels et trois pages de doc. Mais paradoxalement si le projet n'est pas très richement documenté et suffisamment abouti pour qu'un néophyte en C++ puisse l'utiliser (=clic bouton, ou fichier de paramètres), la communauté le jugera inutilisable et tu passeras pour le mec isolé dans ses délires de C++.

    Encore un grand merci pour ces précieuses remarques !
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Seabirds Voir le message
    Hola oui c'est ultra minimaliste comme doc (ça me plaît bien mieux que les gros pâté de doc dans le code source !). Merci, je vais pomper le style dans ton projet
    Ca doit! Mais tu dois malgré tout veiller à être complet (à transmettre toutes les informations utiles pour aider l'utilisateur à sélectionner la classe ou la fonction dont il a réellement besoin),

    Autrement, tu risques d'"assommer" l'utilisateur de ta classe avec des détails sur lesquels il va se focaliser, mais qui n'ont absolument aucun poids dans la décision qu'il doit prendre. Et l'on risque alors de se mettre dans une situation dans laquelle un arbre cacherait la forêt à l'utilisateur

    Allez, un petit exemple. Prenons le code
    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
     
        /** @internal 
          * @brief adds the given slot to the slots list to be called
          *
          * @param[in] slot the slot to be connected
          * @param[in] blocked the slot starting @em blocked @em state (defaults to false)
          * @return a pointer to the created link
          *
          */
        conn_ptr connect(slot_type slot, bool blocked = false) const{
            ++nextId_;
            auto conn=std::make_unique<Link>(
            const_cast<ConcreteSignal *>(this),nextId_, blocked);
            slots_.insert(std::make_pair(nextId_, LinkInfo(*conn.get(),slot)));
            return conn;
        }
        /** @internal
          * @brief calls all (non blocked) slots links
          *
          * @param[in] args parameters to pass to all slot when calling them
          *
          * @note slots will be called only if blocked() == false
          *
          */ 
        void operator()(Args ... args) const {
            if(!blocked()){
                for(auto const & it : slots_){
                    if(! it.second.connection.get().blocked())
                        it.second.slot(args...);
                }
            }
        }
        /** @internal 
          * @brief disconnect a slot
          *
          * destroy and remove a link of the links list to be called
          * @param[in] id the link id to be removed
          *
          */
        void disconnect(size_t id) const final override{
            auto result =slots_.erase(id);
            assert(result == 1);
        }
    (c'est un copier / coller du code qui se trouve entre les lignes 146 et 187 du fichier en question )

    J'ai commencé par marquer les deux fonctions du tag @internal de manière à ce que la documentation ne soit générée que pour les gens qui voudraient participer au développement de la fonctionnalité (ou qui voudraient corriger une erreur que j'aurais pu commettre )

    On ne s'en rend pas forcément compte (parce que j'ai bien évité de trop attirer l'attention du lecteur de la documentation sur ce point ), mais ces trois fonctions représentent véritablement à elles seules le coeur du fonctionnement de mon système de signal et de slots:
    • la première permet d'ajouter un slot,
    • la deuxième permet de transmettre le signal à tous les slots connectés
    • la troisième permet de déconnecter un slot

    Exprimé sous cette forme, tu te rends bien compte que c'est effectivement "tout ce qu'il faut" à la base pour disposer d'un système de signaux et de slots

    J'aurais pu ajouter dans mes cartouches des informations sur les fait que
    1. je maintiens la liste des slots connectés sous la forme d'une std::map
    2. que la clé de la std::map est un identifiant dont j'assure l'unicité en incrémentant systématiquement la valeur de nextId
    3. que la valeur de la std::map est un élément de type LinkInfo
    4. que la classe Link (et la classe Connection au travers d'elle) ne contient que l'identifiant dans la std::map
    5. sans doute bien d'autres informations

    Mais je n'aurais eu aucun intérêt à le faire parce que le code ne cache aucun de ces éléments et que cela aurait incité le lecteur à se focaliser sur de "sordides détails d'implémentation" (comme l'identifiant qui sert de clé à la map ou comme le fait même que l'on travaille avec une std::map) qui non très certainement aucun lien avec le problème auquel il est confronté.
    Citation Envoyé par Seabirds Voir le message
    "exceptionnellement académiques" ?
    Non, ca, c'est un qualificatif qui s'applique surtout à moi
    Citation Envoyé par Seabirds Voir le message
    J'imagine que les choses commencent à bouger (au moins dans certains domaines), mais oui l'utilisateur potentiel qui voudrait utiliser cette librairie est a priori un chercheur en bio, et qui a toutes les raisons du monde de ne pas pouvoir/vouloir connaître la technique (templates, politiques, traits, spécialisation partielle, design, abstraction), et à s'intéresser par contre beaucoup au modèle simulatoire sous-jacent, et à se demander pourquoi une telle prise de tête conceptuelle sur le code et pourquoi est ce qu'il peut pas voir si History c'est une matrice, une liste ou un vecteur. C'est un peu déstabilisant d'essayer avoir la double casquette (on se prend assez souvent des réflexions du genre "c'est de la technique, pas de la science" )
    C'est justement à cause de cette "double (triple ) casquette" que tu dois veiller à séparer clairement les informations qui sont destinées à chaque tête :
    1. D'un coté, tu as des informations destinées à l'épidémiologiste que peuvent représenter l'étendue et la propagation de l'épidémie partie d'un point P en fonction du temps d'infection
    2. D'un deuxième coté, tu as des informations destinées au statisticien que peuvent représenter les règles statistiques qui permettent de calculer la propagation de l'épidémie en fonction du temps et
    3. D'un troisième coté, tu as des informations destinées au programmeur / développeur que peuvent représenter le code et la manière d'expliquer à quelque chose "d'aussi bête qu'un ordinateur" comment utiliser les règles fournie par le statisticien pour calculer les données que l'on donnera à l'épidémiologiste.

    Chacune de ces personnes va avoir ses propres centres d'intérêt, et aucune d'elle n'aura (ne devrait avoir ) de réel intérêt pour les informations destinées aux autres. En séparant clairement les informations (tout en permettant à chacun de faire preuve "d'un peu de curiosité" en allant voir les informations destinées "aux autres"), tu participes "activement" à la prise de conscience de cette double casquette

    Citation Envoyé par Seabirds Voir le message
    Bref du coup j'essaie à la fois de me faciliter la vie en tant que dev (donc j'ai pas vraiment envie d'expliquer pourquoi une politique) mais en même temps si je ne peux décemment pas me couper de ma communauté recherche (donc il faut que j'explique quand même ce que c'est une politique).
    Et tu as tout à fait raison! Mais c'est -- justement -- pour cela que tu dois adapter ton discours (ta documentation) au public auquel il est destiné :

    Si tu t'adresse à un développeur C++ (un tant soit peu expérimenté), tu pourras te contenter de dire "j'ai mis au point un système de politique permettant de prendre plusieurs situations en compte", car il devrait comprendre ce que tu lui dit.

    Au pire, il te répondra "ok, quelles sont les politiques envisagées?".

    Tu répondra à cette question en lui disant "j'ai une politique pour les bas niveau de population, une autre pour les hauts niveaux et une troisième pour les très hauts niveaux de population". Et la discussion s'orientera "naturellement" vers la manière de distinguer les différents niveaux de population.

    Or, les cartouches de tes classes, structures et fonctions ne sont -- a priori -- destinés qu'à des développeurs

    Si tu t'adresse à un statisticien, tu ne parleras sans doute pas de politique, mais plutôt des règles de calculs, en lui disant simplement "j'ai pris en compte la possibilité d'utiliser telle et / ou telle règle, en adaptant le fonctionnement du système de telle et telle manière". Et le statisticien sera content, car il saura que ses formules ont été utilisées "comme il l'espérait".

    Enfin, si tu t'adresse à un épidémiologiste, tu lui diras : voilà, il suffit d'indiquer la population à tel endroit, le "degré de viralité" à tel autre, et tu pourras observer la propagation de l'épidémie de telle manière.
    Et il sera content parce qu'il pourra analyser les risques et donc mettre au point la meilleure manière d'endiguer l'épidémie.

    Evidemment, n'étant ni statisticien ni épidémiologiste, je ne peux pas présumer de la tournure que pourra prendre la discussion avec ces personnes, mais, au final, il est plus que probable que tu aies transmis trois fois les mêmes informations, en les exprimant simplement de manière différentes, selon le centre d'intérêt majeur de chacun de tes interlocuteur
    Citation Envoyé par Seabirds Voir le message
    Et du coup ça prend du temps alors que c'est pas directement valorisable dans mon CV. Et du temps j'en ai peu, puisqu'il faut prioriser les publications. Dans les comités de sélection en science, on préférera trois publications avec des jolis graphiques non reproductible et un code illisible plutôt qu'un article, un code propre, deux tutoriels et trois pages de doc. Mais paradoxalement si le projet n'est pas très richement documenté et suffisamment abouti pour qu'un néophyte en C++ puisse l'utiliser (=clic bouton, ou fichier de paramètres), la communauté le jugera inutilisable et tu passeras pour le mec isolé dans ses délires de C++.
    Ca, c'est tout le problème de l'abîme qui peut séparer deux professions, même si elles sont régulièrement amenées à travailler ensembles : Les centres d'intérêts, et, par conséquents les priorités sont souvent très divergentes

    Personnellement, j'ai résolu le problème. Je m'en tiens à une seule casquette qui me va parfaitement : je suis développeur C++, et je ne veux en aucun cas être épidémiologiste ou statisticien

    Mais je connais plusieurs personnes qui, ayant une formation "non informatique" se sont suffisamment impliqués dans l'étude du développement informatique que pour tenir la double casquette. Certains ont même carrément trouvé des emplois de développeurs n'ayant rien du tout à voir avec leur formation d'origine

    Je peux donc te rassurer sur ce point (car je sens une certaine crainte dans tes propos ) : même si cela prend du temps, il est tout à fait possible d'y arriver
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut
    Pfuou merci encore de cette large réponse !

    C'est justement à cause de cette "double (triple ) casquette" que tu dois veiller à séparer clairement les informations qui sont destinées à chaque tête :
    Je m'y exerce Avec plus ou moins de succès, comme tu peux le voir

    Or, les cartouches de tes classes, structures et fonctions ne sont -- a priori -- destinés qu'à des développeurs
    Moui, enfin plus vraisemblablement a des gens qui sont sans doute aussi perdu que moi entre les trois casquettes Mais en tout cas je vois ce que tu veux dire: les cartouches c'est pour la casquette dev, point barre et tant pis si la casquette bio bloque sur les mots "politique" ou "spécialisation partielle de template": les cartouches sont pas faites pour ça ! Capito !

    Ca, c'est tout le problème de l'abîme qui peut séparer deux professions, même si elles sont régulièrement amenées à travailler ensembles : Les centres d'intérêts, et, par conséquents les priorités sont souvent très divergentes
    Oooooh que oui C'est super dur de vendre ses priorités domaine-spécifiques a l'autre domaine

    Je peux donc te rassurer sur ce point (car je sens une certaine crainte dans tes propos ) : même si cela prend du temps, il est tout à fait possible d'y arriver
    Moi stressé ??? Noooon ...

    Merci de tes encouragements !
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  10. #10
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Je n'ai pas lu toute la prose, mais un truc qui à mon sens marche très bien pour des utilisateurs novices (et même moins novices), c'est de montrer un exemple complet mais simple d'utilisation de ta classe. Ça fixe les idées, et ça permet de faire du copier/coller/adapter et donc d'éviter l’angoisse de la page blanche. Et ça te force aussi à écrire une classe pour laquelle il soit possible d'écrire un exemple d'utilisation simple
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  11. #11
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut
    Merci JolyLoic !
    C'est ce que j'essaie de faire, parce effectivement je me souviens que consulter la doc de la STL a mes tous débuts, ca consistait surtout copier/coller/modifier les fragments de code d'exemple en essayant de deviner le comportement des classes
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. specialisation partielle de template recursif
    Par damiengif dans le forum C++
    Réponses: 7
    Dernier message: 01/09/2012, 17h02
  2. Réponses: 10
    Dernier message: 02/11/2011, 11h49
  3. Réponses: 3
    Dernier message: 29/03/2009, 10h21
  4. Réponses: 5
    Dernier message: 29/12/2005, 21h27
  5. Héritage partielle
    Par ZeLL dans le forum Schéma
    Réponses: 4
    Dernier message: 07/06/2005, 14h14

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