Getting Started with semrulesid

library(semrulesid)
#> semrulesid 0.4.1
#> Please report bugs or edge cases at:
#> https://github.com/zacharyvig/semrulesid/issues

Introduction

semrulesid 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.

Basic workflow

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 Rule

The 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.

Interpreting messages

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:

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.

Choosing lav_fun

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

For example, use "cfa" for a confirmatory factor analysis model:

cfa_model <- '
  L1 =~ Y1 + Y2 + Y3
  L2 =~ Y4 + Y5 + Y6
  L1 ~~ L2
'

id(cfa_model, lav_fun = "cfa")

When a parameter table or fit lavaan object is supplied, lav_fun is ignored since the model defaults have already been applied.

Checking latent-variable scaling

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 indicator

For 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.

Working with a fit lavaan model

If 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.

library(lavaan)

fit <- sem(model, data = my_data)

id(fit, lav_fun = NA)
scaling(fit, lav_fun = NA)

Piping identification and scaling checks

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") %>% scaling

The reverse order is also supported:

scaling(model, lav_fun = "sem") |> id()
# or
library(magrittr)
scaling(model, lav_fun = "sem") %>% id

The two-step rule

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 Message

Next steps

For details on individual rules, see:

?id
?scaling
?get_rules

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).