---
title: "Getting Started with lepidoptera"
author: "Danilo A. Sarti"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with lepidoptera}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

## Overview

**lepidoptera** is a domain-agnostic causal simulation engine for structural
causal models with mixed variable types.  The package separates the causal
graph (which variables exist and who depends on whom) from the mechanism (how
each variable is generated given its parents), enabling clean intervention
semantics and individual-level counterfactual queries.

The core workflow has four steps:

1. Declare feature specifications (`feature_spec()`).
2. Attach a mechanism to each node (`mechanism_library_get()` or a custom
   factory).
3. Assemble and finalise the system (`new_system()`, `add_feature()`,
   `add_dependency()`, `finalize_system()`).
4. Simulate (`simulate()`) and propagate interventions (`propagate()`).

## A minimal example

```{r minimal}
library("lepidoptera")

# 1. Feature specs
age_spec  <- feature_spec("age",    "continuous",  list(min = 18, max = 100))
cvd_spec  <- feature_spec("cvd",    "categorical", list(levels = c("no", "yes")))

# 2. Mechanisms
mech_age <- mechanism_library_get("normal")(mean = 55, sd = 12)
mech_cvd <- mechanism_library_get("multinomial_logit")(
  levels     = c("no", "yes"),
  coefs      = list(yes = list(age = 0.04)),
  intercepts = list(yes = -3.0)
)

# 3. System
sys <- new_system()                                  |>
  add_feature(age_spec)                              |>
  add_feature(cvd_spec)                              |>
  add_dependency(character(0), "age", mech_age)      |>
  add_dependency("age",        "cvd", mech_cvd)      |>
  finalize_system()

# 4. Simulate
pop <- simulate(sys, n = 1000, seed = 1)
head(pop)
prop.table(table(pop$cvd))
```

## Interventions and counterfactuals

`propagate()` applies one or more interventions and returns both baseline and
intervened populations.  With `mode = "full"` each unit is drawn independently
from the interventional distribution (suitable for ATE estimation); with
`mode = "partial"` unaffected nodes retain their baseline draws so the same
individual appears in both worlds (suitable for ITE estimation).

```{r propagate}
# Population-level intervention: what if everyone were 70?
result_full <- propagate(
  sys,
  interventions = list(do_fix("age", 70)),
  n = 1000, seed = 1, mode = "full"
)
cat("Baseline CVD rate:     ", mean(result_full$baseline$cvd  == "yes"), "\n")
cat("Under age=70 CVD rate: ", mean(result_full$intervened$cvd == "yes"), "\n")

# Individual-level counterfactual: same 1000 people, age set to 70
result_cf <- propagate(
  sys,
  interventions = list(do_fix("age", 70)),
  n = 1000, seed = 1, mode = "partial"
)
ite <- (result_cf$intervened$cvd == "yes") - (result_cf$baseline$cvd == "yes")
cat("Mean ITE: ", mean(ite), "\n")
```

## Vine copula mechanism

When observed data are available, `copula_mechanism()` fits the full joint
dependence structure non-parametrically and uses it as the conditional
generating rule at simulation time.

```{r copula, eval = requireNamespace("rvinecopulib", quietly = TRUE)}
set.seed(42)
obs <- data.frame(
  sbp = rnorm(300, 130, 15),
  dbp = NA_real_
)
obs$dbp <- 0.5 * obs$sbp + rnorm(300, 10, 8)

sbp_spec <- feature_spec("sbp", "continuous", list(min = 70,  max = 250))
dbp_spec <- feature_spec("dbp", "continuous", list(min = 40,  max = 150))

mech_sbp <- mechanism_library_get("normal")(mean = 130, sd = 15)
mech_dbp <- copula_mechanism(
  variables = c("dbp", "sbp"),
  family    = "auto",
  fit_data  = obs
)

sys_bp <- new_system()                                        |>
  add_feature(sbp_spec) |> add_feature(dbp_spec)             |>
  add_dependency(character(0), "sbp", mech_sbp)              |>
  add_dependency("sbp",        "dbp", mech_dbp)              |>
  finalize_system()

sim_bp <- simulate(sys_bp, n = 500, seed = 7)
cat(sprintf(
  "Observed Spearman rho: %.2f  |  Simulated: %.2f\n",
  cor(obs$sbp, obs$dbp, method = "spearman"),
  cor(sim_bp$sbp, sim_bp$dbp, method = "spearman")
))
```

## Further reading

The companion paper (Sarti, 2026, *Journal of Statistical Software*) provides
a full technical description of the framework, the mechanism library, the
partial propagation algorithm, and three worked illustrations spanning clinical
trial simulation, emergency-ward digital twins, and epidemiological mediation
analysis.

```r
citation("lepidoptera")
```
