Parity with catR¶
catpie is a faithful translation of the R package
catR. "Faithful" here is not just a
promise — it is verified automatically by a validation harness that
compares catpie's output against the real R catR package, on every change,
in continuous integration.
How it works¶
- Ground truth. R scripts (
scripts/generate_reference.R,scripts/generate_reference_goodbank.R,scripts/generate_reference_derivatives.R) run the realcatRpackage to produce reference JSON files (ability estimates, standard errors, item information, item selections, derivatives) for simulated participants. These files are committed to the repository underreference/. - Replay. The script
scripts/validate.pyreplays every simulated step with catpie and reports the maximum absolute differences. - Continuous integration. The
Validateworkflow runs the replay on every push tomainand on every pull request, and fails if the differences exceed the documented tolerances.
You can run the checks locally (no R needed — the references are already committed):
uv run python scripts/validate.py
uv run python scripts/validate.py reference/catr_reference_goodbank.json
Tie-breaking note. catR samples randomly among items that tie for the best selection criterion. The validation therefore checks the criterion values (
Ii,|b − θ|) exactly, and checks item selection for tie-consistency (i.e. that the chosen item belongs to the tie set), rather than demanding a bit-identical random pick.
Measured results¶
The references were generated with catR 3.17 / R 4.6.1 on this machine.
Real EWM item bank (145 items) — the experiment's exact path (EAP + MFI + bOpt)¶
| Quantity | Comparisons | Max |diff| |
|---|---|---|
ability estimate theta (EAP) |
500 | 8.9e-16 |
standard error se (EAP) |
500 | 2.2e-16 |
item information Ii |
72,500 | 0.0 (exact) |
| MFI selection | 500 | 0 mismatches |
| bOpt selection | 500 | 0 mismatches |
IRF derivatives (Pi/Ii/Ji) |
9,132 | 5.8e-11 |
Well-behaved synthetic bank (40 items) — proves the BM/ML/WL estimation port¶
| Quantity | Comparisons | Max |diff| |
|---|---|---|
EAP theta / se |
240 | 8.9e-16 |
BM / ML / WL theta |
720 | 8.2e-5 |
BM / ML / WL se |
720 | 7.6e-5 |
| MFI / bOpt selection | 480 | 0 mismatches |
About the BM/ML/WL tolerance
BM/ML/WL estimation solves an equation numerically; catR's own root-finder
(uniroot) has a tolerance of ~1.2e-4, so the 8.2e-5 difference is catR's
own numerical precision, not a catpie error. On the real (degenerate) EWM
bank, BM/ML/WL are numerically unstable in catR itself (catR clamps
~1/3 of ML estimates to ±4) — only EAP is robust there, which is what the
EWM experiment uses. That is why the BM/ML/WL check is only a hard
pass/fail on the well-behaved bank.
Regenerating the references¶
You only need R if you want to regenerate the ground-truth references from scratch (e.g. for a different item bank):
# needs R with the catR and jsonlite packages installed
Rscript scripts/generate_reference.R /path/to/your/itembank.csv
Rscript scripts/generate_reference_goodbank.R
Rscript scripts/generate_reference_derivatives.R /path/to/your/itembank.csv
The item-bank CSV must have columns discrimination, difficulty, guessing,
inattention.