Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ARCHITECTURE.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes to TEPP are documented here. The format follows Keep a Chang

## [Unreleased]

- `psychometric_core` recovers the Driver, Oud, and Voelkle (2017, p. 16 `DRIFTstd`; Eq. 1, p. 4; footnote 4; §7.1, pp. 18–19; JSS PDF re-opened 2026-08-23T13:28Z from https://www.jstatsoft.org/index.php/jss/article/download/v077i05/1104) scalar standardised continuous `DRIFT`. Page 16 prints continuous-time parameters (e.g., `DRIFT`) and, when appropriate, standardised matrices with the suffix `std`. Footnote 4: standardisations use only the relevant variance, not the total. For `DRIFT` that relevant variance is within-subject `asymDIFFUSION` `-q / (2 a)`, because `DRIFT` is intended to represent individual, or average individual, temporal dynamics. Form strictly positive `asymDIFFUSION` first. In the scalar stationary case the within-subject SD ratio is 1, so the standardised auto-effect equals the unstandardised log-rate numerically; those remain distinct named quantities. Unstandardised `a` is defined for growing `a ≥ 0` and for zero diffusion; standardised `DRIFT` is not. Zero `asymDIFFUSION` has no positive SD and fails closed. The discrete standardisation `e^{a Δt}` depends on the event interval and is not the continuous map. Section 7.1 warns that omitting trait variance confounds between- and within-person information. `a p / (trait + p + added)` uses the total, not `asymDIFFUSION`, and is not `DRIFTstd` when `TRAITVAR` is nonzero. `TRAITVAR` is not the standardisation variance. Still not a Kalman filter, not a matrix `expm`, not ESEM estimation, not DSEM, and not ctsem estimation. Meredith (1993) remains unread (Unpaywall 2026-08-23T13:19Z: `is_oa: false`; title *Measurement Invariance, Factor Analysis and Factorial Invariance*). Mislevy (1991, *Psychometrika, 56*, 177–196) remains unread (Unpaywall 2026-08-23T13:19Z: `is_oa: false`; title *Randomization-Based Inference about Latent Variables from Complex Samples*).
- `psychometric_core` recovers the Driver, Oud, and Voelkle (2017, p. 16 `DIFFUSIONstd`; Eq. 4, p. 5; footnote 4; §7.1, pp. 18–19; JSS PDF re-opened 2026-08-23T13:20Z from https://www.jstatsoft.org/index.php/jss/article/download/v077i05/1104) scalar standardised continuous `DIFFUSION`. Page 16 prints continuous-time parameters (e.g., `DRIFT`, `DIFFUSION`) and, when appropriate, standardised matrices with the suffix `std`. Footnote 4: standardisations use only the relevant variance, not the total. Process noise is within-subject stochastic input, so that relevant variance is within-subject `asymDIFFUSION` `-q / (2 a)`, the same footnote 4 variance used for `DRIFT`. Form strictly positive `asymDIFFUSION` first, then `q / (−q / (2 a))`. In the scalar stationary case that ratio equals `-2 a` and does not depend on `q` once `q > 0`. Unstandardised `q` is defined for growing `a ≥ 0` and for zero diffusion; standardised `DIFFUSION` is not. Zero `asymDIFFUSION` has no positive SD and fails closed. The discrete standardisation `Q_Δt / (−q / (2 a)) = 1 − exp(2 a Δt)` depends on the event interval and is not the continuous map. Section 7.1 warns that omitting trait variance confounds between- and within-person information. `q / (trait + p + added)` uses the total, not `asymDIFFUSION`, and is not `DIFFUSIONstd` when `TRAITVAR` is nonzero. `TRAITVAR` is not the standardisation variance. Still not a Kalman filter, not a matrix `expm`, not ESEM estimation, not DSEM, and not ctsem estimation. Meredith (1993) remains unread (Unpaywall 2026-08-23T13:19Z: `is_oa: false`; title *Measurement Invariance, Factor Analysis and Factorial Invariance*). Mislevy (1991, *Psychometrika, 56*, 177–196) remains unread (Unpaywall 2026-08-23T13:19Z: `is_oa: false`; title *Randomization-Based Inference about Latent Variables from Complex Samples*).
- `psychometric_core` recovers the Driver, Oud, and Voelkle (2017, p. 16 `discreteDIFFUSIONstd`; Eq. 3–4, pp. 4–5; footnote 4; §7.1, pp. 18–19; JSS PDF re-opened 2026-08-23T13:06Z from https://www.jstatsoft.org/index.php/jss/article/download/v077i05/1104) scalar standardised discrete `DIFFUSION`. Page 16 prints discrete-time transformations for a chosen event interval (`discreteDRIFT`, `discreteDIFFUSION`) and, when appropriate, standardised matrices with the suffix `std`. Footnote 4: standardisations use only the relevant variance, not the total. Process noise is within-subject stochastic input, so that relevant variance is within-subject `asymDIFFUSION` `-q / (2 a)`, the same footnote 4 variance used for `DRIFT`. Form strictly positive `asymDIFFUSION` first, then `Q_Δt` from Equation 4, then `Q_Δt / (−q / (2 a))`. In the scalar stationary case that ratio equals `1 − exp(2 a Δt)`. Unstandardised `Q_Δt` is defined for growing `a ≥ 0` and for zero diffusion; standardised `DIFFUSION` is not. Zero `asymDIFFUSION` has no positive SD and fails closed. The continuous standardisation `q / (−q / (2 a)) = −2 a` is not the discrete map. Section 7.1 warns that omitting trait variance confounds between- and within-person information. `Q_Δt / (trait + p + added)` uses the total, not `asymDIFFUSION`, and is not `discreteDIFFUSIONstd` when `TRAITVAR` is nonzero. `TRAITVAR` is not the standardisation variance. Still not a Kalman filter, not a matrix `expm`, not ESEM estimation, not DSEM, and not ctsem estimation. Meredith (1993) remains unread (Unpaywall 2026-08-23T13:06Z: `is_oa: false`; title *Measurement Invariance, Factor Analysis and Factorial Invariance*). Mislevy (1991, *Psychometrika, 56*, 177–196) remains unread (Unpaywall 2026-08-23T13:06Z: `is_oa: false`; title *Randomization-Based Inference about Latent Variables from Complex Samples*).
- `psychometric_core` recovers the Driver, Oud, and Voelkle (2017, p. 16 `discreteDRIFTstd`; Eq. 3, p. 5; footnote 4; §7.1, pp. 18–19; JSS PDF re-opened 2026-08-23T11:40Z from https://www.jstatsoft.org/index.php/jss/article/download/v077i05/1104) scalar standardised discrete `DRIFT`. Page 16 prints `discreteDRIFT` as `expm(DRIFT Δt)` and, when appropriate, `discreteDRIFTstd`. Footnote 4: standardisations use only the relevant variance, not the total. For `DRIFT` that relevant variance is within-subject `asymDIFFUSION` `-q / (2 a)`, because `DRIFT` is intended to represent individual, or average individual, temporal dynamics. Form strictly positive `asymDIFFUSION` first, then `φ = exp(a Δt)`. In the scalar stationary case the within-subject SD ratio is 1, so the standardised auto-effect equals the unstandardised discrete lag numerically; those remain distinct named quantities. Unstandardised `e^{a Δt}` is defined for growing `a ≥ 0` and for zero diffusion; standardised `DRIFT` is not. Zero `asymDIFFUSION` has no positive SD and fails closed. Section 7.1 warns that omitting trait variance confounds between- and within-person information. The trait-plus-state autocorrelation `(trait + e^{a Δt} p + added) / (trait + p + added)` uses the total, not `asymDIFFUSION`, and is not `discreteDRIFTstd` when `TRAITVAR` is nonzero. `TRAITVAR` is not the standardisation variance. Still not a Kalman filter, not a matrix `expm`, not ESEM estimation, not DSEM, and not ctsem estimation. Meredith (1993) remains unread (Unpaywall 2026-08-23T11:40Z: `is_oa: false`; title *Measurement Invariance, Factor Analysis and Factorial Invariance*). Mislevy (1991, *Psychometrika, 56*, 177–196) remains unread (Unpaywall 2026-08-23T11:40Z: `is_oa: false`; title *Randomization-Based Inference about Latent Variables from Complex Samples*).
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions crates/psychometric_core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,22 @@ pub enum PsychometricError {
/// `q / (trait + p + added)` was treated as p. 16 `DIFFUSIONstd`.
/// Footnote 4 uses only `asymDIFFUSION`, not `TRAITVAR`.
TraitContaminatedContinuousDiffusionIsNotStandardisedContinuousDiffusion,
/// Driver p. 16 `DRIFTstd` was requested with a non-positive
/// within-subject variance. Footnote 4 standardises `DRIFT` using
/// only strictly positive `asymDIFFUSION`.
StandardisedContinuousDriftRequiresPositiveWithinSubjectVariance,
/// Driver p. 16 unstandardised `DRIFT` `a` was treated as
/// `DRIFTstd`. Unstandardised `a` is defined for growing or
/// zero-diffusion processes; standardised `DRIFT` is not.
UnstandardisedContinuousDriftIsNotStandardisedContinuousDrift,
/// Driver p. 16 `discreteDRIFTstd` `e^{a Δt}` was treated as
/// `DRIFTstd`. The discrete auto-effect is not the continuous
/// log-rate.
StandardisedDiscreteDriftIsNotStandardisedContinuousDrift,
/// Driver §7.1 trait-contaminated continuous drift
/// `a p / (trait + p + added)` was treated as p. 16 `DRIFTstd`.
/// Footnote 4 uses only `asymDIFFUSION`, not `TRAITVAR`.
TraitContaminatedContinuousDriftIsNotStandardisedContinuousDrift,
}

impl fmt::Display for PsychometricError {
Expand Down Expand Up @@ -1269,6 +1285,18 @@ impl fmt::Display for PsychometricError {
Self::TraitContaminatedContinuousDiffusionIsNotStandardisedContinuousDiffusion => {
"trait-contaminated continuous DIFFUSION is not standardised continuous DIFFUSION"
}
Self::StandardisedContinuousDriftRequiresPositiveWithinSubjectVariance => {
"standardised continuous DRIFT requires strictly positive within-subject variance"
}
Self::UnstandardisedContinuousDriftIsNotStandardisedContinuousDrift => {
"unstandardised continuous DRIFT is not standardised continuous DRIFT"
}
Self::StandardisedDiscreteDriftIsNotStandardisedContinuousDrift => {
"standardised discrete DRIFT is not standardised continuous DRIFT"
}
Self::TraitContaminatedContinuousDriftIsNotStandardisedContinuousDrift => {
"trait-contaminated continuous DRIFT is not standardised continuous DRIFT"
}
};
formatter.write_str(message)
}
Expand Down Expand Up @@ -2176,4 +2204,28 @@ mod tests {
"trait-contaminated continuous DIFFUSION is not standardised continuous DIFFUSION"
);
}

#[test]
fn standardised_continuous_drift_boundary_messages_are_stable() {
assert_eq!(
PsychometricError::StandardisedContinuousDriftRequiresPositiveWithinSubjectVariance
.to_string(),
"standardised continuous DRIFT requires strictly positive within-subject variance"
);
assert_eq!(
PsychometricError::UnstandardisedContinuousDriftIsNotStandardisedContinuousDrift
.to_string(),
"unstandardised continuous DRIFT is not standardised continuous DRIFT"
);
assert_eq!(
PsychometricError::StandardisedDiscreteDriftIsNotStandardisedContinuousDrift
.to_string(),
"standardised discrete DRIFT is not standardised continuous DRIFT"
);
assert_eq!(
PsychometricError::TraitContaminatedContinuousDriftIsNotStandardisedContinuousDrift
.to_string(),
"trait-contaminated continuous DRIFT is not standardised continuous DRIFT"
);
}
}
Loading
Loading