semrulesidlibrary(semrulesid)
#> semrulesid 0.4.1
#> Please report bugs or edge cases at:
#> https://github.com/zacharyvig/semrulesid/issuessemrulesid allows the user to check a structural
equation model (SEM) written in lavaan (Rosseel, 2012)
syntax, or supplied as a lavaan parameter table or fit
object, against a number of identification rules from the literature.
Rules are specified as being necessary and/or sufficient and specific
reasons are given when a rule is not satisfied or not applicable. Users
should not treat the package output as the sole determinant of model
identification. Instead, semrulesid should be used as a
quick check for potential identification issues and outstanding
model-specification concerns.
The primary function is id(). Supply a model in
lavaan syntax and specify the lavaan function
whose defaults you intend to use through lav_fun.
model <- '
L1 =~ Y1 + Y2 + Y3
L2 =~ Y4 + Y5 + Y6
L2 ~ L1
'
id(model, lav_fun = "sem")
#> semrulesid 0.4.1 Rule Check
#>
#> Fitting function : lavaan::sem()
#> Model type : General SEM
#>
#> Pass Necessary Sufficient Message
#>
#> Rules not applicable to general SEMs:
#> N_theta Rule (t-Rule), Latent Scaling Rule,
#> Exogenous X Rule, 2+ Emitted Paths Rule, Three
#> Indicator Rule, Two Indicator Rule, Fully Recursive
#> Rule, Null B_YY Rule, Recur/Corr Err RuleThe output table reports whether each implemented rule passes and whether the rule is necessary and/or sufficient (or neither) for the relevant model class, which is printed at the top of the output. Rules not applicable to the model type are printed directly below the table.
The id() function reports rules applicable to the
specified model in the rule-check table. Rules that are not applicable
to the detected model type are listed below the table.
When a rule has an associated message, the table’s
Message column gives the number of the corresponding
message. Messages are grouped into the following sections:
Identification failure: A necessary condition was not met. Under the assumptions of the relevant rule, this indicates that the model is not identified and that re-specification may be necessary.
Sufficient condition not satisfied: A sufficient condition was not met. This does not establish that the model is underidentified; rather, the rule cannot be used to establish identification for the model.
Rule not applicable to this model specification: The rule does not apply to the specified model. This is not an identification failure.
Thus, a rule with Pass = No should be interpreted
together with its Necessary and Sufficient
columns and any corresponding message. A failed necessary
condition indicates an identification problem, whereas an unmet
sufficient condition means only that the corresponding
sufficient rule cannot certify identification.
lav_funWhen a model string is supplied, lav_fun determines
which lavaan defaults are used when the model is converted
to a parameter table. Current options are:
"lavaan""sem""cfa"For example, use "cfa" for a confirmatory factor
analysis model:
When a parameter table or fit lavaan object is supplied,
lav_fun is ignored since the model defaults have already
been applied.
Use scaling() to inspect whether each latent variable is
scaled via a method used in the literature.
scaling(model, lav_fun = "sem")
#> semrulesid 0.4.1 Latent Variable Scaling
#>
#> Fitting function : lavaan::sem()
#>
#> L1
#> LV is scaled : Yes
#> No. of indicators : 3
#> Scaling indicator(s) : Y1
#> Mean structure : No
#>
#> Scaling method(s):
#> - Scaling indicator
#>
#>
#> L2
#> LV is scaled : Yes
#> No. of indicators : 3
#> Scaling indicator(s) : Y4
#> Mean structure : No
#>
#> Scaling method(s):
#> - Scaling indicatorFor models without a mean structure, the package checks whether each latent variable has assigned units through a fixed, nonzero loading (scaling indicator) or a fixed positive latent-variable variance.
For models with a mean structure, the package also checks whether the latent variable has an assigned origin, such as through a fixed latent-variable mean or a fixed intercept for a scaling indicator.
lavaan modelIf a model has already been fit with lavaan, pass the
fit object directly to id() or scaling(). Set
lav_fun = NA to avoid warnings when lav_fun
does not match the fitting function used to estimate the model.
semrulesid supports the use of a pipe operator to chain
together identification and scaling checks, e.g., using the base R pipe
|> or the pipe from the magrittr
package:
id(model, lav_fun = "sem") |> scaling()
# or
library(magrittr)
id(model, lav_fun = "sem") %>% scalingThe reverse order is also supported:
For supported full SEMs (latent variables plus structural paths),
id2() applies the two-step rule of identification (see
Bollen, 2026). It first transforms the model into a confirmatory factor
analysis (CFA) model and evaluates it for identification. It then
transforms the model into a simultaneous equations model, and evaluates
it for identification. If both steps are identified, the
original model is identified. The outputs of both steps are printed via
the id2() function.
id2(model, lav_fun = "sem")
#> semrulesid 0.4.1 Two-Step Rule Check
#>
#> Fitting function : lavaan::sem()
#> Model type : General SEM
#>
#> --------------------------------------------------------
#>
#> Step 1: Measurement Model
#>
#> Pass Necessary Sufficient Message
#> --------------------------------------------------------
#>
#> Step 2: Latent Variable/Structural Model
#>
#> Pass Necessary Sufficient MessageFor details on individual rules, see:
You can retrieve implemented rule functions with
get_rules():
cfa_rules <- get_rules(rule = "*", model_type = "cfa")
names(cfa_rules)
#> [1] "rule_cfa_three_indicator" "rule_cfa_two_indicator"
#> [3] "rule_sem_exogenous_x" "rule_sem_latent_scaling"
#> [5] "rule_sem_ntheta" "rule_sem_two_emitted_paths"For further theoretical background, see Ken Bollen’s book Elements of Structural Equation Models (2026).