---
title: "Moment Predictions"
author: ""
date: ""
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Moment Predictions}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---
  
```{r, include=FALSE}
library(ctsmTMB)
library(ggplot2)
```

This vignette demonstrates how to use the `predict` method for calculating *k*-step (state and observation) predictions. 

**Note:** These moment predictions assume that the underlying probability density of the SDE remains approximately Gaussian. This is generally less accurate the longer the prediction horizon for non-linear SDEs, in which case stochastic simulations are more appropriate why the `simulate` method should be used instead (see the relevant [vignette](https://phillipbvetter.github.io/ctsmTMB/articles/simulate.html)).

# Notation

---

Let the set of observations from the initial time $t_0$ until the current time $t_{i}$ be noted by
$$
\mathcal{Y}_{i} = \left\{ y_{i}, y_{i-1},...,y_{1},y_{0}\right\}
$$
A *k*-step **prediction** is a *prior* estimate of the state mean and covariance *k* time-steps into the "future" (without updating to any observations along the way) i.e.:
$$
\hat{x}_{i+k|i} = \mathrm{E}\left[ x_{t_{i+k}} | y_{t_{i}} \right] \\
\hat{P}_{i+k|i} = \mathrm{V}\left[ x_{t_{i+k}} | y_{t_{i}} \right]
$$

We obtain predictions by integrating the moment differential equations (for linear $f$) forward in time i.e:
$$
\hat{x}_{i+k|i} = \hat{x}_{i|i} + \int_{t_{i}}^{t_{i+k}} f(\hat{x}_{i}(\tau)) \, d\tau \\
\hat{P}_{i+k|i} = \hat{P}_{i|i} + \int_{t_{i}}^{t_{i+k}} A(\hat{x}_{i}(\tau)) \hat{P}_{i}(\tau) + \hat{P}_{i}(\tau) A^{T}(\hat{x}_{i}(\tau)) + G(\hat{x}_{i}(\tau)) G^{T}(\hat{x}_{i}(\tau)) \, d\tau
$$
where $\hat{x}_{i}(\tau) = \mathrm{E}\left[ x_{\tau} | y_{t_{i}} \right]$ and $\hat{P}_{i}(\tau) = \mathrm{V}\left[ x_{\tau} | y_{t_{i}} \right]$, and $A = \dfrac{df}{dx}$

# Arguments

---

The `predict` method accepts the following arguments

```{r, eval=FALSE}
model$predict(data,
              pars = NULL,
              use.cpp = FALSE,
              method = "ekf",
              ode.solver = "euler",
              ode.timestep = diff(data$t),
              k.ahead = Inf,
              return.k.ahead = NULL,
              return.covariance = TRUE,
              initial.state = self$getInitialState(),
              estimate.initial.state = private$estimate.initial,
              silent = FALSE
)
```

## Argument: `pars`

---

This argument is a vector of parameter values, which are used to generate the predictions. The default behaviour is to use the parameters obtained from the latest call to `estimate` (if any) or alternative to use the initial guesses defined in `setParameter`.

## Argument: `use.cpp`

---

This argument is a boolean which determines whether a pure **R** (`use.cpp=FALSE`, default) or **C++** (`use.cpp=TRUE`) implementation is used to calculate the predictions. 

The advantage of the **C++** implementation is computational speed but this comes at the cost of 5-10 seconds compilation time (the first time in a session that the **C++** implementation is used, subsequent calls are faster). The number of prediction steps to compute is given by
```{r, eval=FALSE}
k.ahead * (nrow(data) - k.ahead)
```
which is maximized at `k.ahead = nrow(data)/2`. The **C++** implementation is therefore typically advantageous for some (relatively large) range around this maximum, at least when the data has sufficiently many rows.


## Argument: `method`

---

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

**Note:** The `predict` method is currently only available using the Extended Kalman filter (`method="ekf`).

## Argument: `ode.solver`

---

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

**Note:** When the argument `use.cpp=TRUE` then the only solvers available are *euler* and *rk4*.

## Argument: `ode.timestep`

---

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

## Argument: `k.ahead`

---

This integer argument determines the number of prediction steps desired.


## Argument: `return.k.ahead`

---

This vector of integers determines which k-step predictions are returned. The default behaviour is to return all prediction steps (as determined by `k.ahead`).

## Argument: `return.covariance`

---

This boolean argument determines whether the covariance (`return.covariance=TRUE`, default) or the prediction correlations are returned. The returned diagonal elements are always the variances, not the trivial 1's of the correlation matrix.


## Argument: `initial.state`

---

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

## Argument: `estimate.initial.state`

---

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

## Argument: `silent`

---

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

# Example

We consider a modified Ornstein Uhlenbeck process:

$$ 
\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}}
$$
where the mean is some complex time-varying input $a_t = tu_{t}^{2}-\cos(tu_{t})$, and $u_{t}$ is a given time-varying input signal.

We create the model and simulate the data as follows:
```{r}
model = ctsmTMB$new()
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)
model$setParameter(
  theta   = c(initial = 2, lower = 0,    upper = 100),
  sigma_x = c(initial = 0.2, lower = 1e-5, upper = 5),
  sigma_y = c(initial = 5e-2)
)
model$setInitialState(list(1, 1e-1*diag(1)))

# Set simulation settings
set.seed(20)
true.pars <- c(theta=20, sigma_x=1, sigma_y=5e-2)
dt.sim <- 1e-3
t.sim <- seq(0, 1, by=dt.sim)
u.sim <- cumsum(rnorm(length(t.sim),sd=0.1))
df.sim <- data.frame(t=t.sim, y=NA, u=u.sim)

# Perform simulation
sim <- model$simulate(data=df.sim, 
                      pars=true.pars, 
                      n.sims=1,
                      silent=T)
x <- sim$states$x$i0$x1

# Extract observations from simulation and add noise
iobs <- seq(1,length(t.sim), by=10)
t.obs <- t.sim[iobs]
u.obs <- u.sim[iobs]
y = x[iobs] + true.pars["sigma_y"] * rnorm(length(iobs))

# Create data-frame
.data <- data.frame(
  t = t.obs,
  u = u.obs,
  y = y
)
```
with the true parameters
$$
\theta = 20 \qquad \sigma_{x} = 1.00 \qquad \sigma_{y}=0.05
$$

The data is plotted below:
```{r, echo=FALSE, fig.height=5,fig.width=9,out.width="100%", fig.align='center'}
ggplot() + 
  geom_point(aes(x=t.obs, y=y, color="y(t)")) +
  geom_line(aes(x=t.obs, y=u.obs, color="u(t)")) +
  ctsmTMB:::getggplot2theme() + 
  theme(legend.text = ggplot2::element_text(size=15)) +
  labs(color="",x="Time",y="")
```

A good starting point for using predictions, is to check for appropriate parameter values, which may be provided to `setParameter` for good initial guesses for the optimization. Note however that `setParameter` must be called in order to `predict` to be callable (the parameter names of the model needs to be identified), but the parameter values can be changed when calling `predict`. Let's calculate predictions for a series of parameter values (changing only `theta`):

**Note:** The default behaviour of `predict` is to use a "full" prediction horizon e.g. with `k.ahead` as big as possible (`k.ahead = nrow(.data)-1`), and using the parameters from `setParameter` in this case `pars=c(2,1,1)`:

```{r, message=FALSE}
pred = model$predict(.data, k.ahead=nrow(.data)-1, pars=c(1, 1, 0.05))
pred1 = model$predict(.data, k.ahead=nrow(.data)-1, pars=c(10, 1, 0.05))
pred2 = model$predict(.data, k.ahead=nrow(.data)-1, pars=c(50, 1, 0.05))
pred3 = model$predict(.data, k.ahead=nrow(.data)-1, pars=c(100, 1, 0.05))
```

The output of `predict` is a list of two `data.frames`, one for states and one for observations. The five first columns of the two `data.frames` are identical - they contain the columns `i` and `j` (indices), associated time-points `t.i` and `t.j`, and `k.ahead`. The remaining columns for states are the mean predictions, and associated covariances.

```{r}
head(pred$states) 
```

The *observations* `data.frame` currently only contain mean estimates, which are obtained by passing the mean state estimates through the observation function, which is this case is $y = h(x) = x$. The actual observed data is also provided with the suffix *.data*.

```{r}
head(pred$observations)
```

When we plot these predictions against data we can perhaps identify that $\theta \in \left[10,50\right]$ (with $\theta=20$ being the truth here).

```{r, echo=FALSE, fig.height=5,fig.width=9,out.width="100%", fig.align='center'}
t <- pred$states$t.j
latex.str <- lapply(
  c(sprintf("theta[%s]", c(1,10,50,100)),"y[t[k]]"),
  str2expression
)
ggplot() +
  geom_line(aes(x=t, y=pred$states$x, color="label1")) +
  geom_line(aes(x=t, y=pred1$states$x, color="label2")) +
  geom_line(aes(x=t, y=pred2$states$x, color="label3")) +
  geom_line(aes(x=t, y=pred3$states$x, color="label4")) +
  # geom_line(aes(x=t, y=pred4$states$x, color="label5")) +
  # geom_line(aes(x=t, y=pred5$states$x, color="label6")) +
  geom_point(aes(x=t.obs, y=y, color="y(t)")) +
  scale_color_discrete(labels=latex.str) +
  ctsmTMB:::getggplot2theme() + 
  theme(legend.text = ggplot2::element_text(size=15)) +
  labs(color="",x="Time",y="")
```

# Forecasting Evaluation

We can evaluate the forecast performance of our model by comparing predictions against the observed data. We start by estimating the most likely parameters of the model:

```{r}
fit = model$estimate(.data)
print(fit)
```


and then predict over an appropriate forecast horizon. In this example we let that horizon be 25-steps:
```{r}
pred.horizon <- 25
pred = model$predict(.data, k.ahead=pred.horizon)
```

Let's plot the 10-step predictions against the observations.
```{r}
pred.H = pred$states[pred$states$k.ahead==pred.horizon,]
```


```{r, echo=FALSE, fig.height=5,fig.width=9,out.width="100%", fig.align='center'}
ggplot() +
  geom_line(aes(x=pred.H$t.j, y=pred.H$x,color="25-Step Predictions")) +
  geom_ribbon(aes(x=pred.H$t.j,ymin=pred.H$x-2*sqrt(pred.H$var.x),ymax=pred.H$x+2*sqrt(pred.H$var.x)),fill="grey",alpha=0.5) +
  geom_point(aes(x=t.obs,y,color="Observations")) +
  labs(color="",x="Time",y="") +
  ctsmTMB:::getggplot2theme()
```

Lastly lets calculate the mean prediction accuracy using an RMSE-score:
```{r}
rmse = c()
k.ahead = 1:pred.horizon
for(i in k.ahead){
  xy = data.frame(
    x = pred$states[pred$states$k.ahead==i,"x"],
    y = pred$observations[pred$observations$k.ahead==i,"y.data"]
  )
  rmse[i] = sqrt(mean((xy[["x"]] - xy[["y"]])^2))
}
```


```{r, echo=FALSE, fig.height=5,fig.width=9,out.width="100%", fig.align='center'}
ggplot() +
  geom_line(aes(k.ahead, rmse), color="steelblue") + 
  geom_point(aes(k.ahead, rmse), color="red") +
  labs(
    title = "Root-Mean Square Errors for Different Prediction Horizons",
    x = "Prediction Steps",
    y = "Root-Mean-Square Errors"
  ) +
  ctsmTMB:::getggplot2theme()
```
