Package {semTests}


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 ORCID iD [aut, cre], Njål Foldnes ORCID iD [ctb], Steffen Grønneberg ORCID iD [ctb]
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. "object", "m0").

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 lavaan object.

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 lavaan objects (canonical order: m0 constrained).

method

The nested reduction method, "2000" or "2001".

A.method

The restriction matrix, "weighted", "delta", or "exact" (see get_a_matrix()). Categorical pairs do not support "exact".

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

"observed" (default) or "expected" comparator.

score_covariance

Group-centered or uncentered Gaussian score products. LS influence functions are centered by definition and require "centered".

weight_effect

"estimated" includes weight estimation; "fixed" supplies a comparator for LS. Ignored for ML.

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 m1 does not work.

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

lavaan object that corresponds to gamma.

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 lavaan fits.

method

"weighted", "delta", or "exact"; see above.


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

"observed" or "expected" sensitivity. NULL defers to the test. Expected and observed agree in probability when the model is correctly specified, and differ otherwise.

score_covariance

"centered" or "uncentered" empirical score covariance. NULL defers to the test. Centered subtracts group score means and stays valid when the score has nonzero mean; uncentered is consistent only at exact fit. The non-robust reference, which assumes the information equality, is pvalues(x, "STD").

weight_effect

"estimated" propagates first-stage weight estimation into the covariance; "fixed" treats the weights as known. Ignored for ML.

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 lavaan objects.

unbiased

Biased (1), unbiased (2), or both (3) gamma.

df

Number of restrictions (degrees-of-freedom difference).

A.method

"weighted", "delta", or "exact"; see get_a_matrix().

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 lavaan objects.

gamma_matrix

Gamma weighted by groups.

a

The A restriction matrix. If NULL, it is built by get_a_matrix() with A.method.

A.method

"weighted", "delta", or "exact"; see get_a_matrix().

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 semTests_pvalues object.

...

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; NULL fully studentizes the profiled score.

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 lavaan objects, or a semTests_test result from semtest() supplied as object to pvalues(). For lavaan fits, pvalues does goodness-of-fit testing on one object, while pvalues_nested does hypothesis testing on two nested models.

tests

A non-empty character vector of tests. Each element uses one of TEST, TEST_UG, TEST_ML, TEST_RLS, TEST_UG_ML, or TEST_UG_RLS. The defaults are the recommended options. EBA and pEBA take a positive integer number of blocks (for example, "pEBA4"), no greater than the test df. pOLS takes a finite positive penalty (for example, "pOLS2").

fiml.convention

Deprecated, and will be removed in a future release. For FIML fits, use the fully observed-information convention ("observed", the default) or reproduce lavaan's inspected robust-test spectrum ("lavaan"). Supplying it, with either value, gives a warning of class semTests_warning_deprecated. The "lavaan" spectrum changes with the fit's information and h1.information options; use lavaan::lavTest() or lavaan::lavTestLRT() to reproduce lavaan's own tests.

method

Nested reduction method. Only Satorra's "2000" construction (the paper-recommended default) is available. The Satorra–Bentler "2001" construction has been withdrawn because it performs poorly, and requesting it points you to "2000".

A.method

The restriction matrix of the nested test. "weighted" (the default) is the moment-tangent map, with each model's Jacobian at its own estimate, projected in the fit's weight metric. It applies to any nesting, including restricted models that drop or fix paths, and does not depend on how the factors are identified or on the units of the observed variables. "delta" is the same map projected in the Euclidean metric, lavaan's default; use it to reproduce lavTestLRT(..., method = "satorra.2000"). Its p-values change with the units of the observed variables. "exact" is lavaan's literal parameter restriction map. It requires the same underlying free parameters in both models, as with equality constraints, and its p-values shift slightly with the identification (for example std.lv = TRUE versus marker loadings). Categorical nested models do not support "exact".

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 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:

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 lavaan fit in the supported scope.

weight

The matrix in the quadratic form, as in semtest(): "curvature" for the selected saturated curvature (an observed one must be positive in the tested directions), "expected_curvature" for expected saturated curvature whatever the curvature used for projection, or "score_covariance" for full efficient-score studentization.

score_covariance

"uncentered" for raw score products, or "centered" for separate within-group centering.

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 NULL for full covariance studentization.

score_covariance

Covariance of the summed score (summed inputs), or per-observation score covariance (mean inputs).

normalization

Either "sum" or "mean".

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 semtest(): "curvature" uses the selected curvature, "expected_curvature" uses Fisher/Gauss–Newton curvature while keeping the selected curvature for the nuisance projection, and "score_covariance" fully studentizes the profile score.

curvature

"observed" (default) or "expected" comparator.

score_covariance

Group-centered or uncentered Gaussian score products. LS influence functions are centered by definition and require "centered".

weight_effect

"estimated" includes weight estimation; "fixed" supplies a comparator for LS. Ignored for ML.

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:

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

pvalues(), pvalues_nested()


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 lavaan fit. For a restriction test this is the restricted model.

alternative

A nested alternative fit or unoptimized template, using the same observations, estimator and moment conventions. NULL tests overall fit.

statistic

"score" or "criterion". "criterion" requires alternative.

weight

Which matrix weights the quadratic form, and therefore which statistic is computed. This is a separate decision from curvature, which selects the sensitivity used to project out nuisance directions and so enters the reference law.

  • "curvature" weights by whichever sensitivity curvature selected.

  • "expected_curvature" weights by expected curvature even when curvature = "observed". This is the combination that keeps observed sensitivity in the projection, which is what the limit requires when the model may be misspecified, while weighting by the more stable expected matrix.

  • "score_covariance" studentizes fully and gives a chi-square reference.

The first two give a weighted chi-square reference, so the calibrations in pvalues() apply. Ignored when statistic = "criterion", which weights by curvature by construction.

control

Conventions from inference_control().

...

Individual inference_control() settings, merged into control. Unknown names are an error.

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 tests argument.

Value

tests, invisibly.