| Type: | Package |
| Title: | Robust Test Statistics for Structural Equation Models |
| Description: | Computes robust p-values for overall fit and nested comparisons of structural equation models fitted with 'lavaan'. Implements penalized eigenvalue block averaging and penalized regression (Foldnes, Moss, Grønneberg, 2025) <doi:10.1080/10705511.2024.2372028>, including their extension to nested models (Foldnes, Grønneberg, Moss, 2026) <doi:10.3758/s13428-026-02968-4>, alongside familiar corrections such as Satorra-Bentler. Supported settings include complete-data ML, GLS, and ULS, categorical DWLS and ULS, and full-information maximum likelihood with one or several groups. Score and criterion-difference tests of parameter restrictions are also available, including restrictions in misspecified models. |
| Version: | 2.0.0 |
| License: | GPL (≥ 3) |
| Encoding: | UTF-8 |
| URL: | https://github.com/JonasMoss/semTests |
| Depends: | R (≥ 3.5.0) |
| Imports: | lavaan (≥ 0.7-3), methods, pbivnorm |
| Suggests: | testthat (≥ 3.0.0), knitr, rmarkdown |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| Config/roxygen2/version: | 8.0.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-10-28 19:19:58 UTC; jonas |
| Author: | Jonas Moss |
| Maintainer: | Jonas Moss <jonas.moss.statistics@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-29 08:40:02 UTC |
Align an H0 parameter basis to H1's full-parameter ordering.
Description
Align an H0 parameter basis to H1's full-parameter ordering.
Usage
align_parameter_basis(m0, m1, basis0)
Verify that two categorical fits define one comparable nested problem.
Description
Verify that two categorical fits define one comparable nested problem.
Usage
check_categorical_nested_pair(m0, m1)
Require a converged fit and flag inadmissible solutions.
Description
Require a converged fit and flag inadmissible solutions.
Usage
check_fit_quality(fit, arg = "object")
Reject anything that is not a fitted lavaan object.
Description
The class gate for pvalues() / pvalues_nested(). It must run before any
@-slot access so a NULL / data.frame / list argument fails with a readable
message instead of a cryptic S4 "no slot of name ..." error – the nested
entry point in particular reads m0@test to compute the degrees of freedom
before the support gate runs.
Usage
check_lavaan(x, arg = "object")
Arguments
x |
The object passed by the user. |
arg |
The argument name, used in the message (e.g. |
Value
x, invisibly.
Verify that two fits describe one comparable nested problem.
Description
This gate checks fit-level compatibility that is required regardless of data type. It prevents a difference test across different samples, variables, groups, estimators, or information conventions. Substantive nesting still needs an argument based on the model specifications.
Usage
check_nested_pair(m0, m1)
Reject a fit whose configuration is outside the supported surface.
Description
The single entry-level gate for pvalues(). It admits exactly the
configurations documented in semTests-support – the supported continuous
and categorical estimators, complete data, and FIML with one or several
groups – and stops
with a pointer to ?semTests-support otherwise. Statistic- and gamma-specific
rejections (the normal-theory-only RLS statistic and UG gamma) depend on the
parsed test string and stay with the code that consumes them (make_chisqs()
and gamma_matrices()). This gate checks the shape of the fit.
Usage
check_supported(fit, arg = "object")
Arguments
fit |
A fitted |
Value
fit, invisibly.
Reject a nested pair whose configuration is outside the supported surface.
Description
The single entry-level gate for pvalues_nested(): categorical nesting uses
Satorra 2000 with a moment-space restriction map, missing-data nesting otherwise
requires both fits to be FIML, and FIML nesting supports method = "2000"
only. Each fit is also run through
check_supported(). The UG-gamma rejection for FIML stays in the p-value
engine because it depends on the parsed test string.
Usage
check_supported_nested(m0, m1, method, A.method = "weighted")
Arguments
m0, m1 |
Two nested |
method |
The nested reduction method, |
A.method |
The restriction matrix, |
Value
TRUE, invisibly.
Compute p-values for one parsed test specification.
Description
Compute p-values for one parsed test specification.
Usage
compute_pvalues(
m0,
unbiased,
trad,
eba,
peba,
pols,
chisq = c("ml", "rls"),
m1 = NULL,
A.method = "weighted",
fiml.convention = "observed",
cache = NULL
)
Nested criterion-difference test with a complete profile reference
Description
Uses twice the difference of the summed fitting criteria, with the spectrum
computed at the restricted fit using full profile curvature. The null is a
common population minimizer under the shared criterion. Both fits must
converge and use identical first-stage moments and weights. This is distinct
from the existing exact-fit nested corrections in pvalues_nested().
Usage
criterion_test_nested(
object,
alternative,
curvature = c("observed", "expected"),
score_covariance = c("centered", "uncentered"),
weight_effect = c("estimated", "fixed"),
derivative_step = 1e-04,
hypothesis = "Equal population minimum under the shared criterion",
keep = FALSE,
tolerance = 1e-10
)
Arguments
object |
Converged restricted lavaan fit. |
alternative |
Nested alternative lavaan fit or unoptimized template, using the same observations, estimator and moment conventions. |
curvature |
|
score_covariance |
Group-centered or uncentered Gaussian score products.
LS influence functions are centered by definition and require |
weight_effect |
|
derivative_step |
Relative central-difference step for full curvature. Ordinal frequency perturbations use its square root times pattern frequency with Richardson extrapolation. |
hypothesis |
Description of the common pseudo-target null. |
keep |
Retain profile matrices and estimating-equation ingredients. |
tolerance |
Matrix validation tolerance. |
Value
A semTests_test with a weighted chi-square reference. The reference
is evaluated at the restricted fit; negative criterion differences fail.
Calculate the jth eba pvalue.
Description
Calculate the jth eba pvalue.
Usage
eba_pvalue(chisq, lambdas, j)
Generalized inverse of a symmetric information-type matrix after equilibrating its diagonal, so that the rank decision does not depend on the units of the parameters.
Description
Generalized inverse of a symmetric information-type matrix after equilibrating its diagonal, so that the rank decision does not depend on the units of the parameters.
Usage
equilibrated_inverse(x)
Verify that two FIML fits use identical observations.
Description
Verify that two FIML fits use identical observations.
Usage
fiml_check_same_data(m0, m1)
Saturated observed-data FIML information in moment space.
Description
lavaan exposes the corrected FIML H1 information. Setting
h1.information on a local copy requests the unstructured, observed
saturated information without refitting or changing the fitted parameters.
Usage
fiml_h1_information_observed(fit)
FIML goodness-of-fit eigenvalues.
Description
The observed convention uses observed saturated information, matching the
convention independently implemented and validated in magmaan. The lavaan
convention returns lavaan's own inspected UGamma spectrum.
Usage
fiml_lambdas(fit, df, fiml.convention = c("observed", "lavaan"))
FIML Satorra-2000 nested restriction eigenvalues.
Description
FIML Satorra-2000 nested restriction eigenvalues.
Usage
fiml_lambdas_nested(
m0,
m1,
df,
A.method = c("weighted", "delta", "exact"),
fiml.convention = c("observed", "lavaan")
)
Gamma-free nested FIML ingredients in H1's effective parameter space.
Description
Gamma-free nested FIML ingredients in H1's effective parameter space.
Usage
fiml_nested_ingredients(m1, fiml.convention = c("observed", "lavaan"))
FIML restriction matrix for A.method; see get_a_matrix().
Description
FIML restriction matrix for A.method; see get_a_matrix().
Usage
fiml_restriction(m0, m1, df, A.method)
Return the leading symmetric-product eigenvalues without forming AB.
Description
Return the leading symmetric-product eigenvalues without forming AB.
Usage
fiml_sandwich_eigenvalues(U, Gamma, df)
Extract model degrees of freedom through lavaan's public API.
Description
Extract model degrees of freedom through lavaan's public API.
Usage
fit_df(fit)
Provenance of a semTests_pvalues object.
Description
Records the fit-level options actually used to compute the p-values, so the returned object is self-describing across estimators and data types.
Usage
fit_provenance(
fit,
nested,
method = NA,
A.method = NA,
fiml.convention = NA,
df = NULL,
tests = NULL,
parsed_options = NULL
)
Keys of lavaan's full free parameters, in free-parameter order.
Description
Keys of lavaan's full free parameters, in free-parameter order.
Usage
full_parameter_keys(fit)
Get gamma from a model.
Description
Get gamma from a model.
Usage
gamma_matrices(m1, unbiased = 1, m0 = NULL)
Arguments
m1 |
Model to extract gamma from. |
unbiased |
Biased (1), unbiased (2), or both (3). |
m0 |
Optional second model, used if |
Value
List of (un)biased gammas.
Calculate unbiased gamma from gamma and object.
Description
Calculate unbiased gamma from gamma and object.
Usage
gamma_to_gamma_unbiased(gammas, object)
Arguments
gammas |
List of gammas for each group. |
object |
|
Value
List of unbiased gammas.
Nested restriction matrix in H1's effective parameter space.
Description
Nested restriction matrix in H1's effective parameter space.
Usage
get_a_matrix(m1, m0, method = c("weighted", "delta", "exact"))
Arguments
m1, m0 |
The unrestricted and restricted |
method |
|
Upper tail of a linear combination of chi-square_1 variables
Description
Computes P(Q > q) for Q = \sum_j \lambda_j Z_j^2 with
independent Z_j \sim N(0,1). Drop-in replacement for
CompQuadForm::imhof(q, lambda)$Qq: the Imhof integral in the body of the
distribution, a Lugannani-Rice saddlepoint in the far tail where the integral
degrades.
Usage
imhof_pvalue(q, lambda)
Arguments
q |
Numeric scalar or vector of thresholds representing the observed chi-square. |
lambda |
Numeric vector of eigenvalues (may be mixed sign). |
Value
Numeric vector of upper-tail probabilities, length length(q).
References
Imhof, J. P. (1961). Computing the distribution of quadratic forms in normal variables. Biometrika, 48(3/4), 419–426. doi:10.1093/biomet/48.3-4.419
Lugannani, R., & Rice, S. O. (1980). Saddle point approximation for the distribution of the sum of independent random variables. Advances in Applied Probability, 12(2), 475–490. doi:10.2307/1426607
Ruben, H. (1962). Probability content of regions under spherical normal distributions, IV: The distribution of homogeneous and non-homogeneous quadratic functions of normal variables. The Annals of Mathematical Statistics, 33(2), 542–570. doi:10.1214/aoms/1177704580
Computation settings for semtest()
Description
Collects the convention choices used when building a test. These are
deliberately separated from semtest()'s own arguments: the signature states
the question, the control states how the matrices are formed.
Usage
inference_control(
curvature = NULL,
score_covariance = NULL,
weight_effect = c("estimated", "fixed"),
derivative_step = 1e-04,
tolerance = 1e-10,
keep = FALSE
)
Arguments
curvature |
|
score_covariance |
|
weight_effect |
|
derivative_step |
Relative central-difference step for numerical criterion curvature. Must lie in (0, .01]. |
tolerance |
Relative tolerance for matrix symmetry and definiteness validation. Must lie in (0, 1). |
keep |
Retain the input matrices and projections in the result. |
Details
curvature and score_covariance default to NULL, meaning each test picks
the convention appropriate to the null it evaluates. Goodness of fit assumes
the model holds, since that is its hypothesis, and uses expected curvature
with uncentered score products. Nested restriction tests allow the baseline
model to be wrong and use observed curvature with centered score products.
Supplying a value overrides the choice everywhere it applies.
The resolved settings are recorded in the returned test's provenance, so a result always reports the conventions that produced it.
Value
An object of class semTests_control.
Examples
inference_control(curvature = "observed")
inference_control(score_covariance = "centered", keep = TRUE)
Is this the classical normal-theory, complete-data, random-x ML case?
Description
The Du-Bentler unbiased gamma and the RLS (browne.residual.nt.model)
statistic are defined here. Other families use the biased gamma and the
estimator's own uncorrected statistic.
Usage
is_classic_nt(fit)
Is this a continuous FIML/missing-data lavaan fit?
Description
Is this a continuous FIML/missing-data lavaan fit?
Usage
is_fiml(fit)
Reference spectrum of the nested test, without forming the full UGamma.
Description
For Satorra's (2000) method the nonzero eigenvalues are those of the m x m
matrix C^{-1} D' Gamma D (see nested_factor_2000). This avoids the
q x q UGamma and its eigendecomposition.
Usage
lambdas_nested(m0, m1, unbiased = 1, df, A.method = "weighted")
Arguments
m0, m1 |
Two nested |
unbiased |
Biased (1), unbiased (2), or both (3) gamma. |
df |
Number of restrictions (degrees-of-freedom difference). |
A.method |
|
Value
A list of eigenvalue vectors, one per gamma estimate.
Calculate nested ugamma.
Description
This can also be used with restrictions.
Usage
lav_ugamma_nested_2000(m0, m1, gamma_matrix, a = NULL, A.method = "weighted")
Arguments
m0, m1 |
Two nested |
gamma_matrix |
Gamma weighted by groups. |
a |
The |
A.method |
|
Value
Ugamma for nested object.
Biased single-model spectrum exposed by lavaan.
Description
Biased single-model spectrum exposed by lavaan.
Usage
lavaan_lambdas(object, df)
Calculate the scaled and shifted / the mean-variance adjusted p-value
Description
Calculate the scaled and shifted / the mean-variance adjusted p-value
Usage
scaled_and_shifted(chisq, lambdas)
Arguments
chisq |
Chi-square fit value from a lavaan object. |
lambdas |
Eigenvalues of UG matrix. |
Value
The scaled and shifted p-value or the mean-variance adjusted p-value.
Stack lavaan's per-group moment derivatives.
Description
Stack lavaan's per-group moment derivatives.
Usage
model_delta_matrix(fit)
Moment derivatives with respect to effective model parameters.
Description
Moment derivatives with respect to effective model parameters.
Usage
model_effective_delta(fit)
Map effective model parameters to lavaan's full free-parameter space.
Description
Handles explicit equality-constraint bases, simple equality constraints, and equality constraints combined with inequalities or bounds.
Usage
model_parameter_basis(fit)
Gamma-free factors of the reduced nested spectrum (Satorra 2000).
Description
Returns the restriction-space factor D and companion C such that the m
nonzero eigenvalues of the full q x q UGamma equal those of
C^{-1} D' Gamma D, an m x m problem with m the number of restrictions.
This is the materialised reduction of Moss (2026): the full q x q U matrix
and its eigendecomposition are never formed. With U = D C^+ D' one has
D = V Delta P^+ A' and C = A P^+ A', where V is the (group-weighted)
weight, Delta the Jacobian, P^+ the inverted information, and A the
restriction matrix.
Usage
nested_factor_2000(m0, m1, a = NULL, A.method = "weighted")
Analytic per-case influence of the ordinal first stage.
Description
Returns the n by m influence function of the moment vector
[thresholds; lower-triangle polychorics], groupwise centered, whose
empirical covariance is the first-stage Gamma.
Usage
ordinal_moment_influence(X, thresholds, rho, parts = FALSE)
Calculate the jth pall pvalue.
Description
Calculate the jth pall pvalue.
Usage
pall(chisq, lambdas)
Parse and validate public test specifications.
Description
Parse and validate public test specifications.
Usage
parse_tests(tests)
Calculate the jth eba pvalue.
Description
Calculate the jth eba pvalue.
Usage
peba_pvalue(chisq, lambdas, j)
Calculate penalized OLS pvalue.
Description
Calculate penalized OLS pvalue.
Usage
pols_pvalue(chisq, lambdas, gamma)
Positive scale factors: square roots, with zero or non-finite ones set to 1.
Description
Positive scale factors: square roots, with zero or non-finite ones set to 1.
Usage
positive_scale(x)
Print method for p-values from pvalues() / pvalues_nested().
Description
Prints the p-values, then a one-line provenance footer (estimator, data type, information, df) recording the options used.
Usage
## S3 method for class 'semTests_pvalues'
print(x, ...)
Arguments
x |
A |
... |
Passed to the default print method. |
Value
x, invisibly.
Profile a score over nuisance directions
Description
All inputs use summed criterion units. Sensitivity is the negative derivative of the estimating score, including residual/model curvature when applicable. Covariance must include all first-stage contributions for an estimated criterion. This function removes nuisance estimation before applying the score quadratic; it does not estimate any of these inputs.
Usage
profile_score_test_matrices(
score,
curvature,
score_covariance,
nuisance,
metric = curvature,
nobs = NULL,
hypothesis = "Supplied restricted pseudo-target",
keep = FALSE,
tolerance = 1e-10
)
Arguments
score |
Score vector at the restricted estimate. |
curvature |
Symmetric sensitivity matrix in the alternative space. |
score_covariance |
Covariance of the summed score in that space. |
nuisance |
Full-column-rank basis for the null tangent, with zero columns when there are no nuisance parameters. |
metric |
Positive metric in the alternative space, defaulting to
sensitivity; |
nobs |
Total number of independent observations, for provenance. |
hypothesis |
Description of the null and its population target. |
keep |
Retain inputs and nuisance projection. |
tolerance |
Matrix validation tolerance. |
Value
A semTests_test, usable with pvalues().
Calculate the jth all pvalue.
Description
Calculate the jth all pvalue.
Usage
pvalue_all(chisq, lambdas)
Compute robust p-values for fitted models and test objects
Description
Compute one or several p-values for a fitted lavaan model. Available
methods include penalized eigenvalue block averaging, penalized regression,
and familiar robust corrections. The defaults select the recommended method
for the fitted model.
Usage
pvalues(object, tests, fiml.convention = c("observed", "lavaan"))
## S3 method for class 'lavaan'
pvalues(
object,
tests = if (is_classic_nt(object)) "pEBA4_RLS" else "pEBA4",
fiml.convention = c("observed", "lavaan")
)
pvalues_nested(
m0,
m1,
method = c("2000", "2001"),
tests = if (is_classic_nt(m0)) "PALL_UG_ML" else "PALL",
A.method = c("weighted", "delta", "exact"),
fiml.convention = c("observed", "lavaan")
)
## S3 method for class 'semTests_test'
pvalues(
object,
tests = if (object$reference == "chisq") "STD" else "ALL",
fiml.convention = c("observed", "lavaan")
)
Arguments
object, m0, m1 |
One or two |
tests |
A non-empty character vector of tests. Each element uses one of
|
fiml.convention |
Deprecated, and will be removed in a future release.
For FIML fits, use the fully observed-information convention
( |
method |
Nested reduction method. Only Satorra's |
A.method |
The restriction matrix of the nested test. |
Details
pvalues() also accepts the test objects returned by semtest(). Tests
with a weighted chi-square reference use "ALL" by default; fully
studentized tests (weight = "score_covariance") have a chi-square
reference and accept only "STD". Test objects accept calibration names
without UG, ML, or RLS suffixes, and do not accept fiml.convention.
The lavaan methods retain their existing defaults and output names.
The tests argument is a character vector. Each element has one of the forms
TEST, TEST_UG, TEST_ML, TEST_RLS, TEST_UG_ML, or TEST_UG_RLS.
For example, SB_UG_RLS.
The first part names the test. The available names are listed below.
Add
UGto use the unbiased estimator of the fourth-order moment matrix from Du and Bentler (2022). Leave it out to use the standard biased matrix. Performance depends on the data-generating process, so neither gamma choice dominates in every setting.The final part chooses the chi-square statistic.
MLuses the normal-discrepancy statistic (Bollen, 1989).RLSuses Browne's (1974) reweighted least squares statistic.
The peba method is the recommended default. It partitions the eigenvalues
into j equally sized sets (if not possible, the smallest set is incomplete),
shrinks them towards their common mean, and averages within each set. Provide
a positive integer j no greater than the test df. Values from 2 through
6 are usually good candidates. The method was introduced by Foldnes, Moss,
and Grønneberg
(2025).
pols is a penalized regression method with a finite positive penalization
term. Foldnes, Moss, and Grønneberg (2025) studied pols=2, which has
good performance in a variety of contexts.
pall penalizes all eigenvalues in ugamma, while all uses all eigenvalues
without penalization. pall is the recommended option for nested models, for
which the penalized methods were extended and evaluated by Foldnes,
Grønneberg, and Moss (2026).
The eba method is the unpenalized predecessor of peba (Foldnes and
Grønneberg, 2018). It averages within the eigenvalue blocks without
shrinkage. peba usually performs better. eba remains available for
comparisons, and values from j=2 through j=4 tend to work best.
Familiar corrections are available too:
-
stduses the ordinary chi-square reference distribution. -
sbgives the Satorra–Bentler p-value (Satorra and Bentler, 1994). -
ssgives the scaled and shifted p-value (Asparouhov and Muthén, 2010). -
sfgives the scaled F p-value (Wu and Lin, 2016).
Estimators and data types
semTests-support (?semTests-support) gives the complete matrix of
supported estimators, data types, and configurations. Here is the short
version.
The limiting null law of the test statistic is a weighted sum of
chi-squares for any minimum-discrepancy estimator. pvalues() supports
ML/MLM/MLR, GLS, ULS,
FIML (missing data), and categorical DWLS/ULS families, with single- and
multi-group continuous, ordered, and mixed-indicator fits.
pvalues_nested() supports continuous estimators and categorical
Satorra-2000 comparisons with a moment-space restriction map. The fitted model must
expose the asymptotic moment covariance. Robust choices such as
test = "satorra.bentler" or estimator = "MLM", "MLR", or "DWLS"
provide it. The RLS statistic (browne.residual.nt.model) and the unbiased
(UG) Du-Bentler gamma are defined for the classical continuous,
complete-data, random-x ML case. Other families use the standard statistic
and biased gamma. Fixed or conditional observed exogenous predictors are
currently refused. Full WLS/ADF is refused outright: its weight is already
the inverse moment covariance, so the correction is exactly the identity and
every test would equal the ordinary chi-square.
GLS, ULS, categorical DWLS/ULS, FIML missing data, and nested FIML or categorical comparison are validated to numerical tolerance against an independent implementation and are marked stable; see the Stability section in semTests-support.
Both entry points require a converged fit and warn if lavaan reports an
inadmissible solution. Nested comparisons require the same requested
estimator, fitting conventions, variables, groups, sample sizes, raw data,
and missingness mask. semTests checks comparability. The substantive
nesting argument remains part of the analysis.
For FIML, semTests uses observed saturated and model information
throughout. An independent implementation validates this construction.
The deprecated fiml.convention argument can instead select "lavaan",
which reproduces lavaan's robust-test construction. For a single model it uses lavaan's
inspected UGamma. For nested models it uses lavaan's H1 weight convention
and selected model information. The returned object records the convention,
which keeps this inferential choice visible in saved results.
For a single FIML model, "lavaan" means the eigenvalue spectrum returned by
lavInspect(fit, "UGamma"). The scalar Yuan–Bentler–Mplus test stored by a
default MLR fit is a different correction and may give a different result.
For nested FIML models, "lavaan" with A.method = "delta" reproduces
lavTestLRT(..., method = "satorra.2000").
Value
A named numeric vector of p-values, of class semTests_pvalues,
carrying an "semtests" attribute that records the requested tests,
requested and base estimator, base-statistic and gamma choices,
information type, data type, parameterization where applicable, nested
method and restriction map where applicable, and degrees of freedom.
For matrix results, the attribute instead records test type, reference law,
hypothesis, normalization, rank/df, sample size when supplied, and provenance.
References
Foldnes, N., Moss, J., & Grønneberg, S. (2025). Improved goodness of fit procedures for structural equation models. Structural Equation Modeling: A Multidisciplinary Journal, 32(1), 1–13. doi:10.1080/10705511.2024.2372028
Foldnes, N., Grønneberg, S., & Moss, J. (2026). Penalized eigenvalue block averaging: Extension to nested model comparison and Monte Carlo evaluations. Behavior Research Methods, 58, article 107. doi:10.3758/s13428-026-02968-4
Satorra, A. (2000). Scaled and adjusted restricted tests in multi-sample analysis of moment structures. In R. D. H. Heijmans, D. S. G. Pollock, & A. Satorra (Eds.), Innovations in Multivariate Statistical Analysis (pp. 233–247). Kluwer Academic. doi:10.1007/978-1-4615-4603-0_17
Satorra, A., & Bentler, P. M. (2001). A scaled difference chi-square test statistic for moment structure analysis. Psychometrika, 66(4), 507–514. doi:10.1007/BF02296192
Satorra, A., & Bentler, P. M. (1994). Corrections to test statistics and standard errors in covariance structure analysis. In A. von Eye & C. C. Clogg (Eds.), Latent Variables Analysis: Applications for Developmental Research (pp. 399–419). Sage.
Asparouhov, T., & Muthén, B. O. (2010). Simple second order chi-square correction. Mplus Technical Appendix. https://www.statmodel.com/download/WLSMV_new_chi21.pdf
Wu, H., & Lin, J. (2016). A Scaled F Distribution as an Approximation to the Distribution of Test Statistics in Covariance Structure Analysis. Structural Equation Modeling. doi:10.1080/10705511.2015.1057733
Foldnes, N., & Grønneberg, S. (2018). Approximating Test Statistics Using Eigenvalue Block Averaging. Structural Equation Modeling, 25(1), 101–114. doi:10.1080/10705511.2017.1373021
Du, H., & Bentler, P. M. (2022). 40-Year Old Unbiased Distribution Free Estimator Reliably Improves SEM Statistics for Nonnormal Data. Structural Equation Modeling: A Multidisciplinary Journal, 29(6), 872–887. doi:10.1080/10705511.2022.2063870
Kenward, M. G., & Molenberghs, G. (1998). Likelihood based frequentist inference when data are missing at random. Statistical Science, 13(3), 236–247. doi:10.1214/ss/1028905886
Bollen, K. A. (1989). Structural Equations with Latent Variables. John Wiley & Sons. doi:10.1002/9781118619179
Browne, M. W. (1974). Generalized least squares estimators in the analysis of covariance structures. South African Statistical Journal, 8, 1–24.
See Also
semTests-support for the full list of supported configurations.
Examples
library("semTests")
library("lavaan")
model <- "visual =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9"
object <- cfa(model, HolzingerSwineford1939, estimator = "MLM")
pvalues(object)
# For the pEBA6 method with biased gamma and ML chisq statistic:
pvalues(object, "pEBA6_ML")
# Nested model comparison (constrain the textual loadings to be equal):
constrained <- "visual =~ x1 + x2 + x3
textual =~ a*x4 + a*x5 + a*x6
speed =~ x7 + x8 + x9"
m1 <- cfa(model, HolzingerSwineford1939, estimator = "MLM")
m0 <- cfa(constrained, HolzingerSwineford1939, estimator = "MLM")
pvalues_nested(m0, m1)
Requested lavaan estimator, before shortcut normalization.
Description
Requested lavaan estimator, before shortcut normalization.
Usage
requested_estimator(fit)
Moment-space weight of the weighted restriction map.
Description
The group-weighted WLS.V for complete data, as in nested_factor_2000(),
and the observed saturated information for FIML, as in the FIML nested
spectrum.
Usage
restriction_weight(fit)
Calculate the scaled_f p-value.
Description
Calculate the scaled_f p-value.
Usage
scaled_f(chisq, eig)
Arguments
chisq |
Chi-square fit value from a lavaan object. |
eig |
eig of UG matrix. |
Value
scaled f p-value.
Global score test for an ML or FIML lavaan model
Description
Test exact fit against saturated means and covariances. Gaussian likelihood scores include the fitted-mean residual and are projected over the model tangent. FIML contributions use each observed missingness pattern, with scores projected before their cross-products are accumulated.
Usage
score_test(
object,
weight = c("curvature", "expected_curvature", "score_covariance"),
score_covariance = c("uncentered", "centered"),
keep = FALSE,
tolerance = 1e-10,
curvature = c("expected", "observed")
)
Arguments
object |
A converged |
weight |
The matrix in the quadratic form, as in |
score_covariance |
|
keep |
Retain normalized matrices, tangent and projection. |
tolerance |
Matrix validation tolerance. |
curvature |
Expected or observed saturated curvature for projection. |
Details
By default the quadratic uses expected saturated Fisher information. curvature
selects expected or observed saturated curvature for nuisance projection,
matching magmaan's global-score convention. This is an exact-fit null.
For full model curvature and restricted pseudo-target inference under fixed
misspecification, use score_test_nested().
Supports normal-likelihood ML/MLM/MLR and FIML, one or several groups, affine equalities, unweighted raw data, and joint random-x inference. Categorical data, sampling weights, clusters, bounds and nonlinear constraints are excluded. A fully studentized score uses a chi-square reference. Other metrics use the full eigenvalue mixture by default.
Value
A semTests_test recording the hypothesis, sensitivity, covariance
convention, group sizes, source version and nuisance stationarity diagnostic.
Examples
fit <- lavaan::cfa("f =~ x1 + x2 + x3 + x4",
lavaan::HolzingerSwineford1939, estimator = "ML")
s <- semTests:::score_test(fit)
pvalues(s, c("SB", "ALL", "PEBA2"))
Score test from efficient-score matrices
Description
Construct a quadratic score test from an already nuisance-adjusted score, metric, and covariance. No model fitting or nuisance projection is performed. The caller must establish the target hypothesis, correct derivatives, and covariance estimator, including estimated-weight effects where applicable.
Usage
score_test_matrices(
score,
metric = NULL,
score_covariance,
normalization = c("sum", "mean"),
nobs = NULL,
hypothesis = "Supplied efficient-score hypothesis",
keep = FALSE,
tolerance = 1e-10
)
Arguments
score |
Nonempty numeric efficient-score vector in tested coordinates. |
metric |
Positive-definite quadratic metric, or |
score_covariance |
Covariance of the summed score (summed inputs), or per-observation score covariance (mean inputs). |
normalization |
Either |
nobs |
Total sample size. Required for mean inputs, optional for sums. |
hypothesis |
Description of the hypothesis represented by the inputs. |
keep |
Keep the normalized input matrices in the result for inspection. |
tolerance |
Relative tolerance for matrix symmetry and PSD validation. |
Details
With summed inputs, the statistic is score' solve(metric, score) and the
reference weights are the eigenvalues of the covariance whitened by the
metric. Set metric = NULL to use the covariance itself, giving a fully
studentized score test with a chi-square reference. All matrices must be
positive definite; this initial interface rejects singular inference.
For normalization = "mean", supply the average score and per-observation
metric and score covariance. The covariance is not the covariance of the
average score. nobs scales all three inputs to summed units. Centering the
score covariance is the caller's choice and must match the intended method.
pvalues() applies existing eigenvalue calibrations to a supplied metric
score test. Its default here is "ALL", the unpenalized mixture law.
Penalized calibrations are available for research comparisons; numerical
agreement does not establish their calibration for a new score procedure.
Fully studentized score results accept only "STD".
Value
A semTests_test list containing statistic, df, rank, eigenvalues,
reference law, default p-value, hypothesis, normalization, diagnostics,
provenance and optional ingredients. Degrees of freedom are the dimension
of the supplied tested coordinates. No misspecification-validity claim is
inferred from the supplied matrices.
Examples
s <- semTests:::score_test_matrices(c(1, 2), diag(2), diag(c(1, 2)))
pvalues(s, c("SB", "ALL", "PEBA2"))
as.data.frame(s)
Joint nested profile-score test at a restricted fit
Description
Tests the common pseudo-target restriction under one shared criterion.
The observed sensitivity retains full model curvature; the score covariance
includes fitted-mean effects for ML and joint moment/weight effects for LS.
The alternative supplies the parameterization and may be created with
do.fit = FALSE: it is evaluated at the restricted estimates without refitting.
Use the same latent-variable scaling and include released paths explicitly
as fixed parameters in the restricted model. Only affine constraints and
exactly aligned parameter tables are supported.
Usage
score_test_nested(
object,
alternative,
weight = c("curvature", "expected_curvature", "score_covariance"),
curvature = c("observed", "expected"),
score_covariance = c("centered", "uncentered"),
weight_effect = c("estimated", "fixed"),
derivative_step = 1e-04,
hypothesis = "Common criterion pseudo-target satisfies the restricted model",
keep = FALSE,
tolerance = 1e-10
)
Arguments
object |
Converged restricted lavaan fit. |
alternative |
Nested alternative lavaan fit or unoptimized template, using the same observations, estimator and moment conventions. |
weight |
The matrix in the quadratic form, as in |
curvature |
|
score_covariance |
Group-centered or uncentered Gaussian score products.
LS influence functions are centered by definition and require |
weight_effect |
|
derivative_step |
Relative central-difference step for full curvature. Ordinal frequency perturbations use its square root times pattern frequency with Richardson extrapolation. |
hypothesis |
Description of the common pseudo-target null. |
keep |
Retain profile matrices and estimating-equation ingredients. |
tolerance |
Matrix validation tolerance. |
Value
A semTests_test. Expected curvature or fixed weights alone do not
establish validity under fixed structural misspecification.
Supported estimators, data types, and configurations
Description
Use this page to check what pvalues() and pvalues_nested() support.
The eigenvalue-based p-values target a limiting null law that is a weighted
sum of chi-squares. This result holds for any minimum-discrepancy estimator
and therefore includes estimators beyond normal-theory ML. The tables below
give the supported combinations. Configurations outside them are refused at
the entry point (see check_supported()), and the test suite follows the
same boundary.
The score and criterion tests built by semtest() have the narrower scope
described separately below; the fit-test tables do not establish their
support.
Details
Single-model (pvalues())
| Estimator | Data | Groups | Missing | Availability | Stability |
| ML / MLM / MLR | continuous | single or multi | complete | available | stable |
| GLS | continuous | single or multi | complete | available | stable |
| ULS | continuous | single or multi | complete | available | stable |
| ML / MLR (FIML) | continuous | single or multi | FIML | available | stable |
| DWLS family | ordered/mixed | single or multi | listwise/pairwise | available | stable |
| ULS family | ordered/mixed | single or multi | listwise/pairwise | available | stable |
| WLS (ADF) | continuous | single or multi | complete | rejected | -- |
| WLS (ADF) | ordered/mixed | single or multi | listwise/pairwise | rejected | -- |
Nested (pvalues_nested())
| Estimators | Data | Groups | Missing | Method | A.method | Availability | Stability |
| ML/MLM/MLR | continuous | single or multi | complete | 2000 | weighted, delta, or exact | available | stable |
| GLS, ULS | continuous | single or multi | complete | 2000 | weighted, delta, or exact | available | stable |
| ML / MLR (FIML) | continuous | single or multi | FIML (both fits) | 2000 only | weighted, delta, or exact | available | stable |
| DWLS/ULS families | ordered/mixed | single or multi | listwise/pairwise | 2000 only | weighted or delta | available | stable |
| any | continuous | -- | mixed / non-FIML | -- | -- | rejected | -- |
Stability
The classical normal-theory ML path (continuous, complete data) is the mature,
paper-backed core. The other supported estimators – GLS, ULS, categorical
DWLS/ULS fits, FIML missing-data fits, and their nested comparisons – are
also marked stable: each is validated to numerical tolerance against an
independent implementation (magmaan) across a simulation battery, in addition
to the deterministic implementation tests every available row carries. The
deprecated fiml.convention = "lavaan" option reproduces lavaan's own
spectrum for compatibility rather than as an independently validated
construction.
Configurations outside the tables are refused at the entry point.
Observed exogenous covariates
Observed exogenous predictors are supported when they are modeled jointly
with the other variables. In lavaan, request this random-x analysis with
fixed.x = FALSE and conditional.x = FALSE. The independent validation
suite covers continuous ML, GLS, ULS, FIML, and mixed categorical DWLS in
this setting, for single models and nested comparisons.
Fixed or conditional observed exogenous predictors are currently refused. Their reference distribution conditions on the realized covariate design and needs a separate saturated-model projection. If a covariate is intended to be fixed, keep that scientific choice and do not silently change it to random merely to pass the software check.
Fit quality and nested comparability
Both entry points require converged lavaan fits and warn when lavaan's post-estimation check reports an inadmissible solution. Nested comparisons additionally require the same requested estimator, fitting conventions, observed variables, groups, sample sizes, raw data, and missingness mask. These checks establish comparability. The scientific argument that one model is genuinely nested within the other still belongs in the analysis.
The constrained model belongs in m0. If the models are supplied in reverse
df order, semTests warns and swaps them. Only the Satorra-2000 reduction is
available. method = "2001" has been withdrawn because it performs poorly.
Statistic and gamma options
Test names use one of TEST, TEST_UG, TEST_ML, TEST_RLS,
TEST_UG_ML, or TEST_UG_RLS (e.g. "SB_UG_RLS"). See pvalues() for the
test families. Two of the options are defined only for the classical case:
The RLS statistic (
browne.residual.nt.model, Browne 1974) and theUG(Du-Bentler) unbiased gamma are available only for classical normal-theory ML with continuous, complete data,estimator = "ML",fixed.x = FALSE, andconditional.x = FALSE. lavaan degrades RLS to ADF elsewhere, and the Du-Bentler correction has no derivation for the other families or a fixed covariate design.semTestsrefuses either request and points you to the standard statistic and biased gamma.For complete-data normal-likelihood ML, biased spectra can be computed from tiled empirical moment influences when Gamma is not cached. The calculation includes mean/covariance cross terms and group proportions. Cached or supplied NACOV is retained; sampling weights, alternative Gamma normalizations, and other first-stage conventions keep their existing paths.
-
Categorical and mixed-indicator fits use the spectrum equivalent to lavaan's biased
UGammaand its unscaled estimator statistic. Expected- information fits compute the spectrum in residual space. Supported estimator families are DWLS (including WLSMV/WLSM/WLSMVS) and ULS (including ULSMV). Nested comparison is restricted tomethod = "2000", withA.method = "weighted"or"delta". -
Pairwise categorical missingness means support for lavaan's pairwise sample-statistic and
UGammacalculation. Pairwise deletion has its own missingness assumptions and does not provide FIML or generally MAR-valid inference. -
FIML (missing data) uses the biased gamma and the standard statistic only.
UGandRLSare refused. FIML supports one or several groups with continuous data. Observed exogenous predictors are supported under joint random-x inference, usingfixed.x = FALSEandconditional.x = FALSE. semTests uses observed saturated and model information, following the recommendation of Kenward and Molenberghs (1998), and is independently validated against magmaan. The deprecatedfiml.convention = "lavaan"reproduces lavaan's inspected robust-test spectrum, including its expected H1 weight.
Why full WLS/ADF is refused
For full WLS (ADF), with continuous or categorical sample statistics, the
fitting weight is already the inverse of the asymptotic moment covariance, so
UGamma is a projector: its nonzero eigenvalues are all exactly one and the
eigenvalue correction collapses to the identity. Every robust p-value would
therefore equal the ordinary 1 - pchisq(chisq, df). Because the correction
adds nothing, full WLS is refused at the entry point. Fit a DWLS/ULS family
for a non-degenerate robust test, or read the standard chi-square directly.
Score and criterion tests (semtest())
Without an alternative, semtest() builds a global exact-fit score test
from Gaussian likelihood scores. It supports ML/MLM/MLR and FIML with
continuous indicators, one or several groups. Least-squares estimators and
categorical data are not supported for overall fit.
With an alternative, semtest() builds nested score and criterion-difference
tests of affine releases at the restricted fit. These support ML/FIML,
continuous GLS/WLS/DWLS/ULS, and complete all-ordered DWLS/WLS/ULS, with one
or several groups. By default they use full observed curvature and the joint
influence of the sample moments and the estimated fitting weights. Expected
curvature and fixed weights, selected through inference_control(), are
comparators rather than complete corrections under misspecification.
Both require unweighted single-level raw observations, joint random-x
inference and affine equality constraints. Ordinal inference requires
nonempty pairwise cells. Its first-stage influence and the derivative of the
estimated weight are computed in closed form. Mixed indicators, pairwise
missingness, case
weights, clusters, bounds and nonlinear constraints are excluded. Full WLS
is admitted for nested inference under misspecification; its exact-fit
correction refusal in pvalues() is unchanged.
Every result is an inspectable semTests_test usable with pvalues().
Fully studentized results accept only their chi-square calibration.
Numerical parity with an independent implementation does not establish the
finite-sample calibration of penalized score procedures.
References
Foldnes, N., Moss, J., & Grønneberg, S. (2025). Improved goodness of fit procedures for structural equation models. Structural Equation Modeling: A Multidisciplinary Journal, 32(1), 1–13. doi:10.1080/10705511.2024.2372028
Foldnes, N., Grønneberg, S., & Moss, J. (2026). Penalized eigenvalue block averaging: Extension to nested model comparison and Monte Carlo evaluations. Behavior Research Methods, 58, article 107. doi:10.3758/s13428-026-02968-4
Kenward, M. G., & Molenberghs, G. (1998). Likelihood based frequentist inference when data are missing at random. Statistical Science, 13(3), 236–247. doi:10.1214/ss/1028905886
Satorra, A. (2000). Scaled and adjusted restricted tests in multi-sample analysis of moment structures. In R. D. H. Heijmans, D. S. G. Pollock, & A. Satorra (Eds.), Innovations in Multivariate Statistical Analysis (pp. 233–247). Kluwer Academic. doi:10.1007/978-1-4615-4603-0_17
See Also
Build a score or criterion test
Description
Constructs an inspectable test object for overall fit or for a nested
restriction. Pass the result to pvalues() for calibrated p-values.
Usage
semtest(
object,
alternative = NULL,
statistic = c("score", "criterion"),
weight = c("curvature", "expected_curvature", "score_covariance"),
control = inference_control(),
...
)
Arguments
object |
A converged |
alternative |
A nested alternative fit or unoptimized template, using
the same observations, estimator and moment conventions. |
statistic |
|
weight |
Which matrix weights the quadratic form, and therefore which
statistic is computed. This is a separate decision from
The first two give a weighted chi-square reference, so the calibrations in
|
control |
Conventions from |
... |
Individual |
Details
Supply alternative to test a restriction, or leave it NULL to test
overall fit against saturated means and covariances. The restricted model
comes first, as in pvalues_nested(). The alternative may be created with
do.fit = FALSE when statistic = "score": it supplies the
parameterization and is evaluated at the restricted estimates without
refitting.
statistic = "score" evaluates the score at the restricted fit and needs
only that fit to be optimized. statistic = "criterion" uses the actual
difference of the summed fitting criteria and needs both fits. Their null is
a common population minimizer under the shared criterion, which allows the
baseline model to be misspecified. That is a different null from
pvalues_nested(), which tests exact fit of both models using Satorra's
2000 construction, so the two need not agree.
Overall fit with statistic = "criterion" is the classical discrepancy
statistic, which is what pvalues() computes; semtest() does not duplicate
it.
Value
A semTests_test, for use with pvalues(), print() and
as.data.frame().
See Also
pvalues() for calibrated p-values and for the classical
discrepancy statistics, inference_control() for the conventions.
Examples
model <- "f =~ x1 + a*x2 + b*x3 + x4"
d <- lavaan::HolzingerSwineford1939
fit <- lavaan::cfa(model, d, meanstructure = TRUE)
# Overall fit, score statistic.
pvalues(semtest(fit), c("SB", "ALL"))
# Can the equality be released?
restricted <- lavaan::cfa(paste(model, "a == b", sep = "\n"), d,
meanstructure = TRUE)
semtest(restricted, fit, statistic = "score", weight = "score_covariance")
semtest(restricted, fit, statistic = "criterion")
Signal a typed semTests error.
Description
Signal a typed semTests error.
Usage
semtests_abort(message, subclass = "semTests_error")
Signal a typed semTests warning.
Description
Signal a typed semTests warning.
Usage
semtests_warn(message, subclass = "semTests_warning")
Split string into options.
Description
Split string into options.
Usage
split_input(string)
Arguments
string |
Input string |
Calculate traditional pvalues.
Description
Calculate traditional pvalues.
Usage
trad_pvalue(
df,
chisq,
lambdas,
type = c("std", "sf", "ss", "sb", "pall", "all")
)
Arguments
df, chisq, lambdas, type |
Parameters needed to calculate the p-values. |
Value
Traditional p-values.
Calculate non-nested gamma
Description
Calculate non-nested gamma
Usage
ugamma(object, unbiased = 1)
Extract a stable leading UGamma spectrum.
Description
The theoretical spectrum is real and non-negative. Small negative or imaginary components arise from the nonsymmetric numerical representation of a matrix that is similar to a symmetric positive-semidefinite product. Numerical negatives are truncated; materially negative values are rejected.
Usage
ugamma_eigenvalues(ugamma, df, context = "UGamma")
Full nested UGamma reference used to validate the reduced implementation.
Description
Full nested UGamma reference used to validate the reduced implementation.
Usage
ugamma_nested_reference(m0, m1, unbiased = 1, A.method = "weighted")
Validate public test specifications.
Description
Validate public test specifications.
Usage
validate_tests(tests)
Arguments
tests |
Character vector supplied to the public |
Value
tests, invisibly.