fwdpp was initially designed with "standard pop gen" models in mind, meaning a direct mapping from genotype to fitness. However, the library is seeing more and more use in simulating quantitative traits, which brings up an issue. Currently, additive_diploid returns std::max(0., 1 + site_dependent_fitness()(...)), where ... is a bunch of details. This return value inherently assumes that the function is being used to calculate fitness, which is bounded to be a non-negative double. However, it would be easy to modify the function to allow any value to be returned when a trait is being simulated. Further, this change can be made silently, meaning that the current interpretation of additive_diploid remains unchanged. In other words, this does not break the API, but rather enhances its flexibility.
Proposed change:
Add a std::function<double(double)> to additive_diploid and multiplicative_diploid. This function takes the return value of site_dependent_fitness and "does the right thing".
Add a constructor taking a std::function<double(double)> whose default is the current behavior. For example:
fwdpp was initially designed with "standard pop gen" models in mind, meaning a direct mapping from genotype to fitness. However, the library is seeing more and more use in simulating quantitative traits, which brings up an issue. Currently, additive_diploid returns std::max(0., 1 + site_dependent_fitness()(...)), where ... is a bunch of details. This return value inherently assumes that the function is being used to calculate fitness, which is bounded to be a non-negative double. However, it would be easy to modify the function to allow any value to be returned when a trait is being simulated. Further, this change can be made silently, meaning that the current interpretation of additive_diploid remains unchanged. In other words, this does not break the API, but rather enhances its flexibility.
Proposed change:
std::function<double(double)>
to additive_diploid and multiplicative_diploid. This function takes the return value of site_dependent_fitness and "does the right thing".The default in the above matches the current behavior (fitness).
The analogous closure for a trait value calculation would be:
The call operators would have to be modified to call this function.