---
title: "Getting started with flexstanr"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting started with flexstanr}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
library(flexstanr)
```

flexstanr gives a Stan-based R package **one interface** for fitting its models
through either [rstan](https://mc-stan.org/rstan/) or
[cmdstanr](https://mc-stan.org/cmdstanr/), neither of which flexstanr requires
(install whichever you use). Your package supplies its own compiled models;
flexstanr resolves them at run time, so the same fitting code works whichever
backend is installed.

This vignette walks through wiring flexstanr into a host package and using it.

## Wiring it into your package

From the root of your Stan package, run the setup helper once:

```{r, eval = FALSE}
flexstanr::use_flexstanr()
```

This adds `flexstanr` to your `Imports`. It does not add a Stan backend, since
flexstanr requires neither; declare `rstan` or `cmdstanr` yourself. To track a
development build off GitHub instead of the CRAN release, pass
`remote = "ACCIDDA/flexstanr"` to also record a `Remotes: ACCIDDA/flexstanr`
entry so `remotes` / `pak` can find it.

## Building sampler options

`stan_options()` validates common sampler arguments and forwards arbitrary
same-backend arguments **verbatim** to that backend's native sampler. The native
sampler validates arguments that flexstanr does not recognize:

```{r, eval = requireNamespace("rstan", quietly = TRUE)}
opts <- stan_options(chains = 2, iter = 500, seed = 1)
str(opts)
```

For example, backend-native controls such as rstan's `refresh` or cmdstanr's
`open_progress` pass through unchanged.

The model object, data, and initial values are reserved for `fit_model()`.
Mixing known vocabulary from the other backend is also caught early with a
"did you mean" hint rather than failing deep inside the sampler:

```{r, eval = requireNamespace("rstan", quietly = TRUE)}
# `parallel_chains` is a cmdstanr word; the rstan backend rejects it.
try(stan_options(backend = "rstan", parallel_chains = 4))
```

## Fitting a model

`fit_model()` dispatches to the backend recorded on the options and resolves the
compiled model by name from your package. A host fitting one of its own models
needs no extra arguments; the calling package is detected automatically.

```{r, eval = FALSE}
# `"coverage"` is resolved from your package's stanmodels (rstan) or
# inst/stan/coverage.stan (cmdstanr).
fit <- fit_model(
  "coverage",
  dat_stan  = data_list,
  init      = init_list,
  stan_opts = opts
)
```

## Reading a fit

The `backend_*` accessors read a fitted object without your code needing to know
which backend produced it:

```{r, eval = FALSE}
# posterior draws as an iterations x chains x parameters array
draws <- backend_draws_array(fit)

# named parameters, matching rstan::extract()'s shape
post <- backend_extract(fit, pars = c("beta", "sigma"))

# omit `pars` to take every parameter
all_post <- backend_extract(fit)

# guard against the degenerate "no draws" case before using a fit
stopifnot(backend_has_draws(fit))
```

`backend_extract()` guarantees its return shape, so the same downstream math
works against either backend. `format` picks the representation:

```{r, eval = FALSE}
# "list" (the default): rstan::extract()'s shape -- one entry per parameter,
# draws first, a scalar as a 1-D array of length S, a vector[2] as S x 2
post$beta

# "draws": a posterior draws array, chains kept, flat Stan variable names
draws_arr <- backend_extract(fit, format = "draws")

# "matrix": one row per draw, one column per flat variable -- what
# backend_generate_quantities() takes as `draws_mat`
mat <- backend_extract(fit, format = "matrix")
gen <- backend_generate_quantities(fit, data = dat, draws_mat = mat, pars = "y_rep")
```

`"draws"` and `"matrix"` keep iteration-chain draw order on both backends.
`"list"` does not: `rstan::extract()` permutes draws by default and the cmdstanr
path does not, so the two agree as a sample rather than draw for draw.

Unrecognized objects pass through `backend_has_draws()` as if they carry draws,
so test doubles are left untouched:

```{r}
backend_has_draws(list())
```

## Choosing cmdstanr

Pass `backend = "cmdstanr"` to `stan_options()`. cmdstanr is optional and not on
CRAN, so install it separately (see the cmdstanr
[getting-started guide](https://mc-stan.org/cmdstanr/)); selecting it without the
package installed errors early with an actionable message.

```{r, eval = FALSE}
opts <- stan_options(backend = "cmdstanr", parallel_chains = 4, iter_warmup = 500)
```
