`PROCRUSTES()` aligns one loading matrix to a target loading matrix with the same dimensions. It is used internally by `EFA_POOLED()`, but can also be used directly when factor columns must be brought into a common orientation before averaging or comparing solutions.
PROCRUSTES(
A,
Target,
rotation = c("orthogonal", "oblique"),
S = NULL,
T_init = NULL,
oblique_eps = 1e-05,
oblique_maxit = 1000,
oblique_max_line_search = 10,
oblique_step0 = 1,
oblique_normalize = FALSE,
oblique_random_starts = 0,
oblique_screen_keep = 2,
oblique_triage_maxit = 25,
oblique_triage_improve_tol = 0
)A list containing aligned `loadings`, transformation matrix `T`, factor intercorrelation matrix `Phi`, target criterion `value`, convergence diagnostics, line-search diagnostics, and multi-start summaries. Row and column names are preserved where possible.
Numeric loading matrix to be aligned.
Numeric target matrix with the same dimensions as `A`.
Character string, either `"orthogonal"` or `"oblique"`.
Optional `k x k` cross-product matrix `crossprod(A)`. Supplying this is useful when the same `A` is rotated repeatedly. `S` is used only when `oblique_normalize = FALSE`; if Kaiser normalization is requested, the cross-product must be recomputed on the normalized matrix.
Optional `k x k` nonsingular starting transformation matrix for the oblique solver. Its columns are normalized internally.
Positive convergence tolerance for the projected-gradient norm in the oblique solver.
Non-negative integer. Maximum number of projected-gradient updates in the full oblique solver.
Non-negative integer. Maximum number of step-halving attempts after the initial line-search step.
Positive initial step size for the oblique solver.
Logical; if `TRUE`, apply Kaiser row normalization in the oblique solver and back-transform the aligned loadings afterwards.
Non-negative integer. Number of additional random starts used by the oblique solver.
Non-negative integer. Number of random starts retained after cheap objective screening and sent to triage optimization.
Non-negative integer. Number of short optimization iterations used in the triage stage.
Non-negative scalar. Relative improvement required for a triaged start to be promoted to full optimization.
For `rotation = "orthogonal"`, the function solves the closed-form orthogonal Procrustes problem
$$\min_T \frac{1}{2}\|A T - B\|_F^2 \quad \textrm{subject to}\quad T'T = I,$$
where `A` is the loading matrix and `B` is `Target`.
For `rotation = "oblique"`, the function calls the compiled `.oblique_procrustes()` optimizer. The oblique convention is the same as in `GPArotation::targetQ()`:
$$L = A T^{-T}, \qquad \Phi = T'T, \qquad diag(\Phi) = 1.$$
Random starts are only used for oblique alignment. For one-factor models, oblique and orthogonal alignment are equivalent, so the function uses the stable one-factor orthogonal solution instead of calling the oblique optimizer.