---
title: "Latent growth models with missing data"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Latent growth models with missing data}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

## Scope

A latent growth curve model describes change across repeated measurements with
latent intercept and slope factors. From `semTests`' point of view, it is a
continuous SEM. The usual robust p-values therefore work, including with
full-information maximum likelihood (FIML) when a few repeated measurements
have gone missing.

We will fit a linear trajectory, check its overall fit, and then ask whether a
more flexible shape fits noticeably better.

```{r setup}
library("semTests")
library("lavaan")

growth_data <- Demo.growth
```

## A reproducible missing-data mechanism

`Demo.growth` is complete. To exercise FIML, missingness in the later waves `t3`
and `t4` depends on the first wave `t1`. This gives the example a reproducible
MAR-like mechanism and says nothing about a real missingness process.

```{r missing}
set.seed(20260718)
driver <- as.numeric(scale(growth_data$t1))
growth_data$t3[runif(nrow(growth_data)) < plogis(qlogis(.20) + .8 * driver)] <- NA
growth_data$t4[runif(nrow(growth_data)) < plogis(qlogis(.20) + .8 * driver)] <- NA
colMeans(is.na(growth_data[paste0("t", 1:4)]))
```

## Linear growth under FIML

The linear model fixes the slope loadings to `0, 1, 2, 3`:

```{r linear}
linear <- growth(
  "i =~ 1*t1 + 1*t2 + 1*t3 + 1*t4
   s =~ 0*t1 + 1*t2 + 2*t3 + 3*t4",
  growth_data,
  missing = "fiml", estimator = "MLR"
)

pvalues(linear, c("SB", "SS", "ALL", "PEBA4"))
```

FIML uses the standard likelihood-ratio statistic and the observed-information
convention by default. The footer records both choices, so they do not vanish
when the result is copied into another script.

## Is the growth linear?

A latent-basis model frees the last two slope loadings and lets the data choose
the shape of change. Linear growth fixes those loadings to `2` and `3`, which
makes it a special case of the latent-basis model. The linear model is the more
constrained fit, so it goes first:

```{r basis}
basis <- growth(
  "i =~ 1*t1 + 1*t2 + 1*t3 + 1*t4
   s =~ 0*t1 + 1*t2 + t3 + t4",
  growth_data,
  missing = "fiml", estimator = "MLR"
)

pvalues_nested(linear, basis, tests = c("SB", "SS", "ALL", "PEBA2"))
```

A small p-value would be evidence that the linear shape is too rigid. A large
one means this comparison found no clear reason to let the trajectory bend.
The two freed loadings give a two-degree-of-freedom test, so we use `PEBA2`.
The number of blocks cannot exceed the test degrees of freedom.

The missing-data details are collected in
`vignette("fiml-missing-data", package = "semTests")`.
