---
title: "Derivatives at Tiny States: Michaelis-Menten"
author: "Konrad Kraemer"
output: html_document

vignette: >
  %\VignetteIndexEntry{Derivatives at Tiny States: Michaelis-Menten}
  %\VignetteEngine{knitr::rmarkdown_notangle}
  \usepackage{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, eval = FALSE)
library(ast2ast)
```

## The problem in one sentence

Two ways of writing the same rate law can give the same value but a different
derivative in floating point: the one with a state in the denominator of a
denominator breaks down when that state gets tiny.

## Michaelis-Menten

The Michaelis-Menten rate of an enzyme with substrate concentration `S`:

$$v = \frac{v_{max} \, S}{K_m + S}$$

Dividing numerator and denominator by `S` gives a form often found in model
code:

$$v = \frac{v_{max}}{1 + K_m / S}$$

Mathematically both are the same function, and its derivative

$$\frac{dv}{dS} = \frac{v_{max} \, K_m}{(K_m + S)^2}$$

is finite for every `S >= 0`.

## What goes wrong at tiny `S`

In ODE and DAE models concentrations can become very small, e.g. `S = 1e-200`,
or exactly 0. For the second form:

- value: `Km / S = 5e199`, so `v = vmax / (1 + 5e199)`, a tiny finite number.
  Nothing unusual.
- derivative (forward or reverse automatic differentiation applies the chain
  rule to every operation):
  - `d(Km / S) = -Km / S^2`, and `S^2 = 1e-400` underflows to 0, giving `-Inf`
  - `d(1 / D) = -dD / D^2`, and `D^2 = 2.5e399` overflows to `Inf`, giving
    `Inf / Inf = NaN`

At `S = 0` exactly, `Km / 0 = Inf`, the value is still `vmax / Inf = 0`, and the
derivative is again `NaN`.

Difference quotients do not see this, because they only use values. It shows up
as soon as a Jacobian comes from automatic differentiation, e.g. a `jac`
function for `ida()` / `cvode()` built with `jacobian()`.

## What ast2ast reports

```{r}
f <- function(S) {
  argtypes(S |> type(vec(double)))
  rate <- function(s) {
    argtypes(s |> type(vec(double)))
    returntype(vec(double))
    vmax <- 2
    Km <- 0.5
    return(vmax / (1 + Km / s))
  }
  return(jacobian(rate, S))
}
fcpp <- ast2ast::translate(f)
fcpp(c(1e-200, 0.3))
```

```
Error: In 'return(vmax/(1 + Km/s))': jacobian: d f[1] / d x[1] is not finite,
although f[1] is. The first non-finite derivative appears in
'return(vmax/(1 + Km/s))'. Typical cause: a division by a (nearly) zero state,
e.g. vmax / (1 + K / c); the same value as vmax * c / (c + K) has a finite
derivative.
```

The check runs when a Jacobian contains a non-finite entry while the function
value is finite: one extra sweep finds the first line where a derivative stops
being finite. If the function value itself is `NaN`, the Jacobian is `NaN` too
and no error is raised, as in R.

## The fix: multiply through

Multiply numerator and denominator by the state that sits in the inner
denominator:

```{r}
return(vmax * s / (Km + s))
```

The value is the same, and `S` now only appears multiplied, so nothing becomes
huge: at `S = 1e-200` and at `S = 0` the derivative is just `vmax / Km`.

```
     [,1]   [,2]
[1,]    4 0.0000
[2,]    0 1.5625
```

## Rule of thumb

> If a state sits in the denominator of a denominator, multiply numerator and
> denominator by that state.

With several substrates, multiply by all of them:

```{r}
# vmax / (1 + K1 / a + K2 / b)
vmax * a * b / (a * b + K1 * b + K2 * a)

# vmax / (1 + K1 / a + K2 / b + K1 * K2 / (a * b))   (random-order bi-substrate)
vmax * a * b / (a * b + K1 * b + K2 * a + K1 * K2)
```

The multiplied-through form is usually the textbook form anyway; the form with
the double fraction tends to come from code that was written for values only.
