---
title: "Modification Indices in umx"
subtitle: "Exploring model improvement suggestions with umxMI()"
author: "Timothy C. Bates"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{Modification Indices in umx}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.height = 5
)
library(umx)
library(OpenMx)
umx_set_auto_plot(FALSE)
```

## Introduction

**Modification indices** (MIs) flag single parameters whose addition or removal would most improve model fit (if freed and the model re-estimated). They are useful for exploring *where* a misspecified model struggles, but they are **not** a substitute for theory-driven model comparison.

`umxMI()` wraps [OpenMx::mxMI()] and prints the largest indices (by default those above $\chi^2_1(0.01) = 6.63$). By default `full = FALSE` (only the tested parameter moves — fast). Set `full = TRUE` to allow all free parameters to re-adjust (slower).

This vignette uses the classic Holzinger & Swineford (1939) data (`HS.ability.data` in OpenMx): fit a deliberately poor **one-factor** model (the worst of the usual teaching sequence), run **one** `umxMI()` call, then show a better three-factor alternative with `umxCompare()` (no second MI pass).

## Data

```{r data-setup}
data("HS.ability.data", package = "OpenMx")

manifests = c("visual", "cubes", "flags", "paragrap", "sentence", "wordm",
  "addition", "counting", "straight")

# Scale for stable optimization (recommended for this dataset in umx)
df = umx_scale(HS.ability.data)
```

## One-factor model (worst fit → one MI call)

```{r one-factor, results = "hide", message = FALSE}
m1 = umxRAM("Holzinger_1f", data = df,
  umxPath("g", to = manifests),
  umxPath(v.m. = manifests),
  umxPath(v1m0 = "g")
)
```

```{r one-factor-summary, message = FALSE}
umxSummary(m1, refModels = FALSE)
```

Fit is poor (as expected for a single factor on these data). What does `umxMI()` suggest?

```{r one-factor-mi, message = FALSE}
umxMI(m1)
```

Large indices often point to **within-domain residual covariances** (e.g. `flags_with_visual`) or **cross-domain loadings** that a single factor cannot represent. That pattern hints at multiple abilities rather than one `g`.

## Three-factor alternative (no second MI)

Holzinger and Swineford's data are usually modeled with three correlated abilities:

```{r three-factor, results = "hide", message = FALSE}
model3f = "
  spatial =~ visual + cubes + flags
  verbal  =~ paragrap + sentence + wordm
  speed   =~ addition + counting + straight
"
m3 = umxRAM(model3f, data = df, name = "Holzinger_3f")
```

```{r three-factor-summary, message = FALSE}
umxSummary(m3, refModels = FALSE)
```

```{r three-factor-compare, message = FALSE}
umxCompare(m3, m1)
```

The three-factor model fits substantially better. Remaining residual associations are typically smaller; run `umxMI(m3)` locally if you want that table.

## Bifactor / multi-group (optional, local)

```{r bifactor-multigroup-demo, eval = FALSE}
# Bifactor + umxMI, or multi-group one-factor by sex
modelBifactor = "
  g =~ visual + cubes + flags + paragrap + sentence + wordm + addition + counting + straight
  spatial =~ visual + cubes + flags
  verbal  =~ paragrap + sentence + wordm
  speed   =~ addition + counting + straight
  spatial ~~ 0*verbal + 0*speed + 0*g
  verbal  ~~ 0*speed + 0*g
  speed   ~~ 0*g
"
mBio = umxRAM(modelBifactor, data = df, name = "Holzinger_bifactor")
umxMI(mBio)

mMG = umxRAM("Holzinger_1f_MG", data = df, group = "Gender",
  umxPath("g", to = manifests),
  umxPath(v.m. = manifests),
  umxPath(v1m0 = "g")
)
umxMI(mMG)
```

## Summary

| Model                  | Role                                              |
|:-----------------------|:--------------------------------------------------|
| One-factor             | Baseline misspecification; **one** `umxMI()` call |
| Three-factor           | Theory-driven improvement via `umxCompare()`      |
| Bifactor / multi-group | Optional local demos                              |

**Take-home:** Use `umxMI()` to diagnose *where* a model misfits; prefer `umxCompare()` on **theory-driven** competing models for inference.

## References
Holzinger, K. J., & Swineford, F. (1939). A study in factor analysis: The stability of a bi-factor solution. *Supplementary Educational Monographs*, **48**. University of Chicago Press.
