---
title: "Stochastic Simulations"
author: "Phillip Vetter"
date: "`r Sys.Date()`"
output: 
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{Stochastic Simulations}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
  editor_options: 
  markdown: 
    wrap: 72
---

<style>
body {
  text-align: justify;
  hyphens: auto;
}
</style>

\newcommand{\E}[1]{\mathrm{E}\left[#1\right]}
\newcommand{\V}[1]{\mathrm{V}\left[#1\right]}
\newcommand{\diff}{\mathrm{d}}
\newcommand{\dp}[2]{\dfrac{\partial #1}{\partial #2}}
\newcommand{\dd}[2]{\dfrac{\diff #1}{\diff #2}}

```{r setup, include=FALSE}
knitr::opts_chunk$set(collapse=TRUE, cache=FALSE)
```

```{r set-options, echo=FALSE}
options(width=1e2)
```

```{r, eval=FALSE, include=FALSE}
# We can use this to type 'rmd' in the console, and the markdown html document is then knitted fast.
render.rmd("rmd")
```

This vignette demonstrates how to use the `simulate` method for
calculating *k-step-ahead* stochastic simulations trajectories.

## Introduction

### Notation
- We use subscript $x_{t} = x(t)$ to denote time for continuous variables.

- We use subscript $y_k = y(t_k)$ to indicate discrete time-points for discrete variables.

- We denote the set of observations from the initial time $t_0$ until the "current" time $t_{i}$ by
$$
\mathcal{Y}_{i} = \left\{ y_{i}, y_{i-1},...,y_{1},y_{0} \right\}
$$

- We denote mean and variance by $\mu_{t} = \E{x_t}$ and $P_{t} = \V{x_t}$.

- We use $\mu_{k \mid k-1}$ and $P_{k \mid k-1}$ to denote the mean/variance at time $t_{k}$ conditional on the observations $\mathcal{Y}_{k-1}$ i.e.
$$
\mu_{k \mid k} = \E{x_{t_k} \mid \mathcal{Y}_{k}} \qquad\qquad P_{k \mid k} = \V{x_{t_k} \mid \mathcal{Y}_{k}}
$$

### Stochastic State Space System

We consider the following types of stochastic state space systems

$$
x_{t} = f(t,x_t,u_t,\theta) \, \mathrm{d}t + G(t,x_t,u_t, \theta) \, \diff \diff B_{t}
$$

$$
y_{k} = h(t_k, x_{t_k}, u_{t_k}, \theta) + \varepsilon_{k}
$$

where the observation noise is zero-mean Gaussian $\varepsilon_{k} \sim \mathcal{N}(0,\Sigma(t_k, x_{t_k}, u_{t_k}, \theta))$. In this notation $u$ are inputs and $\theta$ are fixed effects parameters to be estimated. 

We refer to the functions $f$ as the *drift*, $G$ as the *diffusion*, and $h$ as the *link*. We may omit arguments and just write e.g. $f(x_t)$ for readability.

### Observations and Likelihood

The likelihood, which is the joint density of all observations, can be rewritten by using repeated conditioning as

$$
L(\theta) = p(\mathcal{Y}_{N}) = \prod_{k=1}^{N} p(y_{k} \mid \mathcal{Y}_{k-1}) = \prod_{k=1}^{N} p(h(x_{k}) + \varepsilon_{k} \mid \mathcal{Y}_{k-1}) 
$$

### What is a "Simulation"?

When we say a *stochastic simulation*(s) we mean sample
trajectories drawn from the joint state distribution at all future
sampling times conditional on the (relative) initial posterior state
distribution i.e.

$$
\mathcal{X}_{t_{i+k}} = \left( x_{t_i}, x_{t_{i+1}}, \dots, x_{t_{i+k-1}}, x_{t_{i+k} } \right) \mid \, p(x_{t_i})
$$

The initial distribution $p_{X_{t_i}}$ is approximated by a Gaussian
with mean and covariance given by the posterior expectation and
covariance i.e.

$$
X_{t_{i}} \sim N(\hat{x}_{i|i}, P_{i|i} )
$$

We may sample such trajectories as follows:

1.  Sample from $p(x_{t_i})$ to generate $X_{t_{i}}$.

2.  Use the Euler-Maruyama method to generate the future state values iteratively

The Euler-Maruyama discretization for the SDE is given by

$$
X_{t_{j+1}} = X_{t_{j}} + f(X_{t_{j}},u_{t_{j}},t_{j}) \, \Delta t_{j} + G(X_{t_{j}},u_{t_{j}},t_{j}) \, \Delta B_{j}
$$ 

for $j = i, ... , i+k-1$, and where $\Delta B_{j} \sim N(0,\Delta t_{j})$.


### Algorithm \label{sec:algo_overview}

When using the `simulate` method the forecast horizon is controlled by
the `k.ahead` argument, i.e. how many time-steps "into the future"
forecasts are wanted for.

The algorithm returns $N$ forecast scenarios, calculated by `nrow(data)-k.ahead`. Each of these $i=0,1,..,N$ scenarios consist of $k_{\text{ahead}}+1$ state values, for every $n_{\text{sims}}$ requested simulation trajectories, one for each time point $t=t_{i+j}$ where $j=0,1,..,k_{\text{ahead}}$. The number of simulation trajectories $n_{\text{sim}}$ can be controlled via the `n.sims` argument.

The algorithm carries out the following step-wise procedure:

-   Filter with the provided data to obtain posterior state and covariance estimates for every point in time in the provided `data[,"t"]` column.

-   Extract the first $N$ estimates and discard the remainder.

-   For each $i=0,1,..,N$ sample $k=0,1,..,n_{\text{sims}}$ realisations $X^{(k)}$ from the posterior Gaussians given by

$$
X^{(k)} \sim \mathcal{N}\left(\hat{x}_{i \mid i}, P_{i \mid i}\right)
$$

-   For each of the realized variables $X^{(k)}$ apply the Euler-Maruyama scheme repeatedly until from the initial time $t_{i}$ until time $t_{i+k_{\text{ahead}}}$ producing forecasts at each of the intermediate times $t_{i+j}$.

In summary this produces for each of the system states (i.e. for each element of $x_t$) a `list` with $N$ entries, where each entry is a `matrix` of $k_{\text{ahead}}+1$ rows and $n_{\text{sims}}$ columns. Each column is thus a stochastic realisation of the associated forecast distribution.

## Example

We consider a modified Ornstein Uhlenbeck process:

$$
\begin{align}
\mathrm{d}x_{t} & = \theta (a_t - x_{t}) \, \mathrm{d}t \, + \sigma_{x} \, \mathrm{d}b_{t} \\
y_{t_{k}} & = x_{t_{k}} + \varepsilon_{t_{k}}
\end{align}
$$

where the mean is given by (some time-varying input) 

$$
a_t = tu_{t}^{2}-\cos(tu_{t})
$$

and $u_{t}$ is a known *input* signal. The variance is zero-mean Gaussian $\varepsilon_{t_{k}} \sim \mathcal{N}(0,\sigma_{y}^2)$, and we assume that $\sigma_{y}$ is known.

### Create Model

First we create the model as follows:

```{r}
## Load libraries
library(ctsmTMB)
library(ggplot2) ## plots

## Create model
model <- newModel()
model$addSystem(dx ~ theta * (t*u^2-cos(t*u) - x) * dt + sigma_x*dw)
model$addObs(y ~ x)
model$setVariance(y ~ sigma_y^2)
model$addInput(u)

## Set parameter values
## note: not strictly necessary to set lower/upper bounds
model$setParameter(
  theta   = c(initial = 2, lower = 0,    upper = 100),
  sigma_x = c(initial = 0.2, lower = 1e-5, upper = 5),
  ## fix sigma_y to 0.05 by not giving any upper/lower bounds
  sigma_y = c(initial = 5e-2)
)

## Set initial state mean and covariance
## note: diag(1) is not strictly needed
model$setInitialState(list(1, 1e-1*diag(1)))
```

### Create Data

Next we create a `data.frame` that contains time-points and input
values.

```{r, collapse=TRUE}
## set true parameters, and create data
true.pars <- c(theta=20, sigma_x=1, sigma_y=0.05)
dt.sim <- 1e-3
t.sim <- seq(0, 1, by=dt.sim)

## seed for input creation
set.seed(20)
u.sim <- cumsum(rnorm(length(t.sim),sd=0.1))
df.sim <- data.frame(t=t.sim, y=NA, u=u.sim)
```

### Simulate

Then we call the method to simulate.

```{r, collapse=TRUE}
## Set rng seeds for C++ states and observations
cpp.seeds <- c(20,20)

## perform simulation
sim <- model$simulate(data=df.sim, 
                      pars=true.pars, 
                      k.ahead = nrow(df.sim)-1, ## default
                      n.sims = 2,
                      cpp.seeds = cpp.seeds)

```

A few notes for the code above:

-   We use the default value of argument `k.ahead = nrow(data)-1` to get a forecast over the entire time-vector. This means that there is only $N=1$ forecast scenario.

-   We remove the first observation to prevent a posterior update at the initial time-point `t[1]`. This allows us to fully control the initial state mean and covariance via `setInitialState`.

-   Since `k.ahead = nrow(data)-1` and $N=1$ implies just one forecast scenario starting from the initial time point the remaining observations `y[2:nrow(data)]` will not be used, why we set them as `NA`.

- The `cpp.seeds` argument control the RNG seed for the state and observations respectively, i.e. for the Brownian increments $dB_t$ and for the observation noise $\varepsilon_t$.

### Output

The returned `sim` object is a list of lists of lists of matrices.

-   The outer list has the three elements `states`, `observations` and
`times`.

-   The `states`, and `observations` list each contain entries for all state and observation variables respectively named accordingly.

-   The state and observation variable lists e.g. `x`, `y` contain matrices where the columns are simulated forecast trajectories, and the rows corresponds to forecast time-points, as described in the **Algorithm Overview** section. These are named `i0`, `i1`, `i2` indicative of the time-point from which the forecast begun.

-   Each entry in the 'times' list contains 5-column matrices with time indices and time-values for each of the forecast scenarios. These are also named `i0`, `i1`, `i2` matching those from the states and observations.

Below we bind together the matching output from `times`, `states$x`, `observations$y` for the first (and only in this case) forecast scenario.

```{r}
mat <- as.matrix(data.frame(sim$times$i0, x=sim$states$x$i0, y=sim$observations$y$i0))
head(mat)
tail(mat)
```

-   The column `i` holds the time-index from where the forecast began.

-   The column `j` holds the time-index for where the forecast is.

-   The column `t.i` is the numeric time value associated with index
`i.`

-   The column `t.j` is the numeric time value associated with index
`j.`

-   The column `k.ahead` is the number of forecasted timesteps since the last posterior update (if any data was available at that time-point).

Note that because we chose only a single simulation by setting $n_{\text{sims}}=2$ via the argument `n.sims=2` we get two columns (trajectories) for `x` and `y`.

### Estimating with the Simulated Observations

Let us extract the observations that we just simulated, and feed them to estimate to see if we can recover the true parameters.

```{r, collapse=TRUE}
## Extract all observations
y.sim <- sim$observations$y$i0[,1]

## Only select every tenth, to reduce the available information
iobs <- seq(1, length(t.sim), by=10)
t.obs <- t.sim[iobs]
y.obs <- y.sim[iobs]
u.obs <- u.sim[iobs]

## Create data for re-estimation
df.obs <- data.frame(
  t = t.obs,
  u = u.obs,
  y = y.obs
)

## Try to estimate the parameters
fit <- model$estimate(df.obs)
```

So that was fairly straight-forward. We can inspect the fit to see the related Wald test statistics.

```{r, collapse=TRUE}
fit
```

### Many Simulations

We can change the `n.sims` argument to get more trajectories, and these can be plotted easily with `matplot`:

```{r, fig.height=5, fig.width=9, out.width="100%", fig.align='center'}
sim <- model$simulate(data=df.sim, pars=true.pars, n.sims=5, cpp.seeds = cpp.seeds)
x <- sim$states$x$i0
t <- sim$times$i0
matplot(t[,"t.j"], x, type="l", lty="solid", ylim=c(-4,4), xlab="Time")
```

### Increasing Process Noise

Let's check the effect of the process noise by increasing from $\sigma_{x}=1$ up to $\sigma_{x}=4$.


```{r, fig.height=5, fig.width=9, out.width="100%", fig.align='center'}
new.pars <- true.pars
new.pars["sigma_x"] <- 4
sim <- model$simulate(data=df.sim, pars=new.pars, n.sims=5, cpp.seeds=cpp.seeds)
x <- sim$states$x$i0
t <- sim$times$i0
matplot(t[,"t.j"], x, type="l", lty="solid", ylim=c(-4,4), xlab="Time")
```

### Distribution Plot

We demonstrate how one might plot the entire distribution using `ggplot2` below:

```{r, fig.height=5, fig.width=9, out.width="100%", fig.align='center'}
new.pars["sigma_x"] <- 4
sim <- model$simulate(data=df.sim, pars=new.pars, n.sims=100, cpp.seeds=cpp.seeds)

## quantiles
p <- c(0.01, 0.05, seq(0.1,0.9,by=0.1), 0.95, 0.99)
Q <- t(apply(sim$states$x$i0, 1,function(x) quantile(x, probs=p)))

## create data for distribution plot
p.center <- p[-length(p)] + diff(p)/2
col.ids <- c(col(Q[,-1]))
row.ids <- c(row(Q[,-1]))
fan.df <- data.frame(
  t = sim$times$i0[row.ids,"t.j"],
  ymin = c(Q[,-ncol(Q)]),
  ymax = c(Q[,-1]),
  ids = col.ids,
  ## symmetric colors around median
  fill.value = abs(0.5 - p.center[col.ids])
)

## Create plot
ggplot() +
  geom_ribbon(data=fan.df, aes(x=t, ymin=ymin, ymax=ymax, fill=fill.value, group=ids)) +
  geom_line(aes(x=sim$times$i0[,"t.j"], y=Q[,"50%"]), color="black", linewidth=0.3) +
  scale_fill_gradientn(colors=c("red","yellow")) +
  coord_cartesian(ylim=c(-4,4)) +
  guides(fill="none") +
  labs(x="Time",y="") +
  theme_minimal()
```


## Method Arguments

The `simulate` method accepts the following arguments

```{r, eval=FALSE}
model$simulate(data,
               pars = NULL,
               use.cpp = TRUE,
               cpp.seeds = NULL,
               method = "ekf",
               ode.solver = "rk4",
               ode.timestep = diff(data$t),
               simulation.timestep = diff(data$t),
               k.ahead = nrow(data)-1,
               return.k.ahead = 0:min(k.ahead, nrow(data)-1),
               n.sims = 100,
               ukf.hyperpars = c(1, 0, 3),
               initial.state = self$getInitialState(),
               estimate.initial.state = private$estimate.initial,
               silent = FALSE,
               ...)
```

### `pars`

See the description in the [predict
vignette](https://phillipbvetter.github.io/ctsmTMB/articles/predict.html).

---

### `use.cpp`

Use C++ or pure R implementation.

See the description in the [predict
vignette](https://phillipbvetter.github.io/ctsmTMB/articles/predict.html).

---

### `method`

Filtering method used - one of 'ekf', 'lkf', or 'ukf'.

See the description in the [estimate
vignette](https://phillipbvetter.github.io/ctsmTMB/articles/estimate.html).

---

### `ode.solver`

See the description in the [estimate
vignette](https://phillipbvetter.github.io/ctsmTMB/articles/estimate.html).

---

### `ode.timestep`

See the description in the [estimate
vignette](https://phillipbvetter.github.io/ctsmTMB/articles/estimate.html).

---

### `k.ahead`

See the description in the [predict
vignette](https://phillipbvetter.github.io/ctsmTMB/articles/predict.html).

---

### `return.k.ahead`

See the description in the [predict
vignette](https://phillipbvetter.github.io/ctsmTMB/articles/predict.html).

---

### `simulation.timestep`

The number of intermediate time-steps taken between time-points in the provided
data for the Euler-Maruyama method.

---

### `n.sims`

The number of stochastic simulation trajectories generated.

---

### `initial.state`

Sets the initial state $\hat{x}_{0 \mid 0}$ and variance $P_{0 \mid 0}$.

---

### `estimate.initial.state`

A boolean to indicate whether or not estimate the initial state mean value instead of using the one provided via the `model$setInitialState` method or the `initial.state` argument to this method.

The estimation is carried out by root-finding the stationary mean equation equivalent to minimizing

$$
\hat{x}_{0 \mid 0} = \min_{x} \left(f(t_0, x, u_{0}, \theta)\right)^{2}
$$

using a Newton approach.

**Note**: This option is only available when `use.cpp=FALSE` using the pure R implementation.

---

### `silent`

Disable message print-outs.

---
