---
title: "Projecting enrollment with enrollcast"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Projecting enrollment with enrollcast}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

```{r setup}
library(enrollcast)
```

## The grade progression ratio method

The cohort survival / grade progression ratio method projects enrollment by
asking: of the students in grade *g* this year, how many appear in grade *g+1*
next year? That ratio captures net retention, migration, and repetition.
`enrollcast` estimates these ratios from history and applies them forward with
a matrix projection.

## A small district

```{r}
history <- data.frame(
  year = rep(2021:2023, each = 3),
  grade = factor(rep(c("K", "1", "2"), 3), levels = c("K", "1", "2")),
  enrollment = c(100, 90, 80, 110, 95, 88, 120, 99, 91)
)
history
```

## Step 1: progression ratios

```{r}
ratios <- progression_ratios(history, method = "mean")
ratios
```

Ratios are calculated only from observed adjacent calendar-year pairs. If the
history contains a gap, `progression_ratios()` warns and uses the adjacent pairs
on either side without constructing a transition across the missing period. A
history with no adjacent year pair cannot produce progression ratios and is
rejected. Gap detection examines the complete supplied history before `n_years`
selects the most recent adjacent transitions, so an older gap still warns even
when it lies outside the selected transitions.

The ratios sit on the sub-diagonal of the projection matrix; the entry-grade row
is zero because entry is supplied exogenously.

```{r}
progression_matrix(ratios)
```

## Step 2: project forward

The entry grade (kindergarten here) has no feeder grade, so you supply its
future values — for example from a birth-cohort or housing model.

```{r}
base <- history[history$year == 2023, c("grade", "enrollment")]
projection <- project_enrollment(
  base = base,
  ratios = ratios,
  horizon = 3,
  entry = c(125, 130, 128),
  start_year = 2023
)
projection
```

## Stitching history and projection

`project_enrollment()` returns projected years only. Combine with history for
plotting:

```{r}
observed <- data.frame(
  year = history$year,
  grade = as.character(history$grade),
  enrollment = history$enrollment
)
combined <- rbind(observed, projection)
head(combined)
```

## Modeling a school modernization swing

A school temporarily relocated during modernization typically sees depressed
enrollment that recovers after it returns. `swing_schedule()` builds a per-year
projection schedule: enrollment is held flat during the swing, scaled by
recovery multipliers for a few years, then projected normally.

Schedules may contain `NA` or `NaN` matrix coefficients. These values are
preserved and warned about rather than imputed. A missing coefficient can make
its output grade missing. If that missing enrollment remains after the entry
grade is replaced, the next matrix multiplication spreads missingness to all
grade results because zero times a missing value is still missing. A non-`NULL`
entry value then restores only the entry grade.

```{r}
depressed <- c(K = 80, `1` = 66, `2` = 60)
schedule <- swing_schedule(ratios,
  horizon = 6, swing_years = 2,
  recovery = c(1.10, 1.10, 1.05), entry = 130
)
project_enrollment(depressed, schedule = schedule, start_year = 2023)
```
