mrc-ide / odin

ᚩ A DSL for describing and solving differential equations in R
https://mrc-ide.github.io/odin
Other
102 stars 12 forks source link

Support for symbolic differentiation #298

Closed richfitz closed 1 year ago

richfitz commented 1 year ago

This PR adds support for symbolic differentiation of expressions to odin. It is not documented, nor exported to users.

There are several systems for doing this already in R; notably D which is built-in, and the Deriv package which produces nice expressions. However, I've had a poke about for how we'll support odin arrays and we're going to need something slightly more specialised to support that (eg, differentiating lambda[] <- beta * sum(s_ij[, i]) with respect to the matrix s_ij taking into account odin's rules about how partial sums over tensors work). The D function is not extensible, while Deriv is but it'll be awkward to work with for how simple this implementation is (note that D does not support if, so we can't use that for even our simplest models).

Symbolic differentiation is mostly just ploughing through the same set of rules. The main issue is that you quickly get really ugly expressions with way too many parentheses and way too many things like 0 * x or 0 + x that you want to simplify. So the majority of the pain here is in the maths list, which provides a simple set of rules for constructing expressions so that they're not wildly redundant. It does not really need to be perfect, because we're going to be generating code for optimising compilers, but it's best if it's interpretable.

There are more functions to add here, but this set of expressions is sufficient to generate all derivatives in Marc's toy example model.

I've done two different tricks to try and namespace the component bits of of this: differentiate is a list (they don't talk to each other) and maths is an environment (they call each other so its convenient to share scope). Unfortunately covr seems not able to trace along the code here so it's not clear that all branches are actually hit.

codecov[bot] commented 1 year ago

Codecov Report

Patch coverage: 100.00% and no project coverage change.

Comparison is base (1653828) 100.00% compared to head (2ac75e4) 100.00%.

:exclamation: Current head 2ac75e4 differs from pull request most recent head efd8cbd. Consider uploading reports for the commit efd8cbd to get more accurate results

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #298 +/- ## ========================================= Coverage 100.00% 100.00% ========================================= Files 47 48 +1 Lines 5509 5517 +8 ========================================= + Hits 5509 5517 +8 ``` | [Impacted Files](https://app.codecov.io/gh/mrc-ide/odin/pull/298?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mrc-ide) | Coverage Δ | | |---|---|---| | [R/differentiate-expr.R](https://app.codecov.io/gh/mrc-ide/odin/pull/298?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mrc-ide#diff-Ui9kaWZmZXJlbnRpYXRlLWV4cHIuUg==) | `100.00% <100.00%> (ø)` | |

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Do you have feedback about the report comment? Let us know in this issue.