\encoding{UTF-8}
\name{rotations}
\alias{rotations}
\alias{oblimin}
\alias{quartimin}
\alias{targetT}
\alias{targetQ}
\alias{pstT}
\alias{pstQ}
\alias{oblimax}
\alias{entropy}
\alias{quartimax}
\alias{Varimax}
\alias{simplimax}
\alias{bentlerT}
\alias{bentlerQ}
\alias{tandemI}
\alias{tandemII}
\alias{geominT}
\alias{geominQ}
\alias{bigeominT}
\alias{bigeominQ}
\alias{cfT}
\alias{cfQ}
\alias{equamax}
\alias{parsimax}
\alias{infomaxT}
\alias{infomaxQ}
\alias{mccammon}
\alias{varimin}
\alias{bifactorT}
\alias{bifactorQ}
\alias{lpT}
\alias{lpQ}

\title{Rotations Functions Using Gradient Projection Algorithms}
\usage{
    oblimin(A, Tmat=diag(ncol(A)), gam=0, normalize=FALSE, randomStarts=0, ...)
    quartimin(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    targetT(A=NULL, Tmat=diag(ncol(A)), Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    targetQ(A=NULL, Tmat=diag(ncol(A)), Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    pstT(A=NULL, Tmat=diag(ncol(A)), W=NULL, Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    pstQ(A=NULL, Tmat=diag(ncol(A)), W=NULL, Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    oblimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    entropy(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    quartimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    Varimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    simplimax(A, Tmat=diag(ncol(A)), k=nrow(A), normalize=FALSE, randomStarts=0, ...)
    bentlerT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    bentlerQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    tandemI(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    tandemII(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    geominT(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    geominQ(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    bigeominT(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    bigeominQ(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    cfT(A, Tmat=diag(ncol(A)), kappa=0, normalize=FALSE, randomStarts=0, ...)
    cfQ(A, Tmat=diag(ncol(A)), kappa=0, normalize=FALSE, randomStarts=0, ...)
    equamax(A, Tmat=diag(ncol(A)), kappa=ncol(A)/(2*nrow(A)), normalize=FALSE,
        randomStarts=0, ...)
    parsimax(A, Tmat=diag(ncol(A)), kappa=(ncol(A)-1)/(ncol(A)+nrow(A)-2), 
        normalize=FALSE, randomStarts=0, ...)
    infomaxT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    infomaxQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    mccammon(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    varimin(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    bifactorT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    bifactorQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    lpT(A, Tmat=diag(ncol(A)), p=1, normalize=FALSE, eps=1e-05, maxit=1000, 
            randomStarts=0, gpaiter=5) 
    lpQ(A, Tmat=diag(ncol(A)), p=1, normalize=FALSE, eps=1e-05, maxit=1000, 
        randomStarts=0, gpaiter=5)
    }
    
\arguments{
    \item{A}{an initial loadings matrix to be rotated.}
    \item{Tmat}{initial rotation matrix.}
    \item{gam}{Obliqueness parameter (\eqn{\gamma} in the mathematical definition).
          0=Quartimin, .5=Biquartimin, 1=Covarimin.}
    \item{Target}{rotation target for objective calculation.}
    \item{W}{weighting of each element in target.}
    \item{k}{number of close to zero loadings.}
    \item{delta}{constant added to \eqn{\Lambda^2}{Lambda^2} in the objective calculation.}
    \item{kappa}{see details.}
    \item{normalize}{parameter passed to optimization routine (GPForth or GPFoblq).}
    \item{eps}{convergence tolerance passed to \code{GPForth} or \code{GPFoblq} via \code{...}.
         Convergence is assumed when the norm of the gradient is smaller than \code{eps}.
         Default is \code{1e-5}.}
    \item{maxit}{maximum number of iterations passed to \code{GPForth} or \code{GPFoblq} 
         via \code{...}. Default is \code{1000}.}
    \item{...}{additional arguments passed to \code{GPForth} or \code{GPFoblq}, 
         including \code{eps} and \code{maxit}.}
    \item{randomStarts}{parameter passed to optimization routine (GPFRSorth or GPFRSoblq).}
    \item{L}{provided for backward compatibility in target rotations only. Use A going forward.}
    \item{p}{Component-wise \eqn{L^p}{Lp}, where 0 < p \eqn{=<}{=<} 1. }
	  \item{gpaiter}{Maximum iterations for GPA rotation loop in \eqn{L^p}{Lp} rotation.}
}

\value{
  A \code{GPArotation} object which is a list with elements:
  \item{loadings}{The rotated loadings matrix, one column per factor.
       If random starts were requested, this is the solution with the
       lowest criterion value.}
  \item{Th}{The rotation matrix, satisfying
       \code{loadings \%*\% t(Th) = A} for orthogonal rotation and
       \code{loadings = A \%*\% solve(t(Th))} for oblique rotation.}
  \item{Table}{A matrix recording the iteration history: iteration
       number, criterion value, log10 of the gradient norm, and step
       size (alpha).}
  \item{method}{A string indicating the rotation criterion.}
  \item{orthogonal}{A logical indicating if the rotation is orthogonal.}
  \item{convergence}{A logical indicating if convergence was obtained.}
  \item{Phi}{\code{t(Th) \%*\% Th}, the covariance matrix of the rotated
       factors. Omitted (\code{NULL}) for orthogonal rotations.}
  \item{Gq}{The gradient of the criterion at the rotated loadings.}
  \item{randStartChar}{A named vector summarising random start results:
       \code{randomStarts}, \code{Converged}, \code{atMinimum},
       \code{localMins}. Only present when \code{randomStarts > 1}.}
}
\description{
   Optimize factor loading rotation objective.
}

\details{
These functions optimize a rotation objective. They can be used directly or the
function name can be passed to factor analysis functions like \code{factanal}.
Several of the function names end in T or Q, which indicates if they are
orthogonal or oblique rotations (using \code{GPFRSorth} or \code{GPFRSoblq}
respectively). The gradient projection algorithms are described in
Bernaards and Jennrich (2005).
    \tabular{lll}{
 \code{oblimin}   \tab oblique    \tab oblimin family; \code{gam} controls obliqueness \cr
 \code{quartimin} \tab oblique    \tab oblimin with \code{gam = 0} \cr
 \code{targetT}   \tab orthogonal \tab rotation towards a target matrix \cr
 \code{targetQ}   \tab oblique    \tab rotation towards a target matrix \cr
 \code{pstT}      \tab orthogonal \tab partially specified target rotation \cr
 \code{pstQ}      \tab oblique    \tab partially specified target rotation \cr
 \code{oblimax}   \tab oblique    \tab maximizes overall kurtosis of loadings \cr
 \code{entropy}   \tab orthogonal \tab minimizes entropy of squared loadings \cr
 \code{quartimax} \tab orthogonal \tab maximizes variance of squared loadings within variables \cr
 \code{Varimax}   \tab orthogonal \tab maximizes variance of squared loadings within factors \cr
 \code{simplimax} \tab oblique    \tab minimizes the k smallest squared loadings \cr
 \code{bentlerT}  \tab orthogonal \tab invariant pattern simplicity \cr
 \code{bentlerQ}  \tab oblique    \tab invariant pattern simplicity \cr
 \code{tandemI}   \tab orthogonal \tab factors share high loadings on same variables \cr
 \code{tandemII}  \tab orthogonal \tab factors do not share high loadings on same variables \cr
 \code{geominT}   \tab orthogonal \tab minimizes geometric mean of squared loadings \cr
 \code{geominQ}   \tab oblique    \tab minimizes geometric mean of squared loadings \cr
 \code{bigeominT} \tab orthogonal \tab geomin with a general factor in column 1 \cr
 \code{bigeominQ} \tab oblique    \tab geomin with a general factor in column 1 \cr
 \code{cfT}       \tab orthogonal \tab Crawford-Ferguson family; \code{kappa} controls complexity \cr
 \code{cfQ}       \tab oblique    \tab Crawford-Ferguson family; \code{kappa} controls complexity \cr
 \code{equamax}   \tab orthogonal \tab Crawford-Ferguson with \code{kappa = m/(2p)} \cr
 \code{parsimax}  \tab orthogonal \tab Crawford-Ferguson with \code{kappa = (m-1)/(p+m-2)} \cr
 \code{infomaxT}  \tab orthogonal \tab infomax information criterion \cr
 \code{infomaxQ}  \tab oblique    \tab infomax information criterion \cr
 \code{mccammon}  \tab orthogonal \tab minimizes entropy ratio across factors \cr
 \code{varimin}   \tab orthogonal \tab minimizes variance of squared loadings within factors \cr
 \code{bifactorT} \tab orthogonal \tab bifactor; general factor in column 1 \cr
 \code{bifactorQ} \tab oblique    \tab biquartimin; general factor in column 1 \cr
 \code{lpT}       \tab orthogonal \tab \eqn{L^p}{Lp} sparsity rotation \cr
 \code{lpQ}       \tab oblique    \tab \eqn{L^p}{Lp} sparsity rotation \cr
 }
 
 The \code{Varimax} implementation in the list uses the gradient projection algorithm 
 applied to \code{vgQ.varimax}. This implementation is different that the 
 \code{varimax} rotation defined in the \code{stats} package. Additionally, 
 \code{varimax} does Kaiser normalization by default whereas 
 \code{GPArotation::Varimax} does not.
 
 The argument \code{kappa} parameterizes the family for the Crawford-Ferguson 
 method. If \code{m} is the number of factors and \code{p} is the number of 
 indicators then \code{kappa} values having special names are \eqn{0=}{0=}Quartimax, 
 \eqn{1/p=}{1/p=}Varimax, \eqn{m/(2*p)=}{m/(2*p)=}Equamax, 
 \eqn{(m-1)/(p+m-2)=}{(m-1)/(p+m-2)=}Parsimax, \eqn{1=}{1=}Factor parsimony.
 
 Bifactor rotations, bifactorT and bifactorQ are called bifactor and
 biquartimin in Jennrich and Bentler (2011). For a
  comparison of exploratory bifactor analysis algorithms including
  those implemented here, see Garcia-Garzon, Abad and Garrido (2021).
      
 The argument \code{p} is needed for \eqn{L^p}{Lp} rotation. See 
 \link{Lp rotation} for details on the rotation method.
 
 }  
  \examples{
  # For extended examples see the vignettes:
  # vignette("GPA1guide",    package = "GPArotation")
  # vignette("GPA2local",    package = "GPArotation")
  # vignette("GPA3bifactor", package = "GPArotation")

  # --- Accessing rotated loadings ---
  data("Harman", package = "GPArotation") # 8 physical variables
  qHarman <- quartimax(Harman8)
  loadings(qHarman)                              # via extractor (recommended)
  qHarman$loadings                               # via direct list access
  all.equal(loadings(qHarman), qHarman$loadings) # identical

  # --- Rotating factanal loadings ---
  data("WansbeekMeijer", package = "GPArotation") # Netherlands TV viewership
  fa.unrotated <- factanal(factors = 2, covmat = NetherlandsTV,
                           normalize = TRUE, rotation = "none")
  quartimax(loadings(fa.unrotated), normalize = TRUE)
  geominQ(loadings(fa.unrotated), normalize = TRUE, randomStarts = 100)

  # --- Passing rotation to factanal ---
  # CCAI:Climate-Friendly Purchasing Choices domain of the Climate Change Action Inventory
  data("CCAI", package = "GPArotation") 
  factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT")
  factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT",
           control = list(rotate = list(normalize = TRUE, eps = 1e-6)))
           
  # --- Target rotation ---
  # Orthogonal target rotation of two varimax rotated matrices 
  # towards each other. Data from Fischer and Fontaine (2010).
  # See vignette("GPA1guide", package = "GPArotation") for further analyses.
  trBritain <- matrix(c(.783, -.163, .811, .202, .724, .209, .850, .064,
                       -.031, .592, -.028, .723, .388, .434, .141, .808,
                       .215, .709), byrow = TRUE, ncol = 2)

  trGermany <- matrix(c(.778, -.066, .875, .081, .751, .079, .739, .092,
                       .195, .574, -.030, .807, -.135, .717, .125, .738,
                       .060, .691), byrow = TRUE, ncol = 2)
  trx <- targetT(trGermany, Target = trBritain)
  round(trx$loadings - trBritain, 3)  # difference from target

  # --- Partially specified target rotation ---
  # See vignette("GPA1guide", package = "GPArotation") for full context.
  # Unrotated loadings matrix A and partially specified target SPA
  # NA entries in SPA are unspecified --- rotation is free there
  # Numeric entries are the target values the rotation aims towards
  A <- matrix(c(.664, .688, .492, .837, .705, .82, .661, .457, .765, .322,
                .248, .304, -0.291, -0.314, -0.377, .397, .294, .428,
                -0.075, .192, .224, .037, .155, -.104, .077, -.488, .009), ncol = 3)
  SPA <- matrix(c(rep(NA, 6), .7, .0, .7, rep(0, 3), rep(NA, 7),
                  0, 0, NA, 0, rep(NA, 4)), ncol = 3)
  comparison <- cbind(round(A, 3), rep(NA, nrow(A)), SPA)
  colnames(comparison) <- c("A.F1", "A.F2", "A.F3", "|", "T.F1", "T.F2", "T.F3")
  cat("Unrotated loadings (A) and partially specified target (SPA):\n")
  print(comparison, na.print = "NA")
  targetT(A, Target = SPA)

  # --- Random starts ---
  # CCAI Climate-Friendly Purchasing Choices domain, 14 items, 3 oblique factors.
  # High factor intercorrelations make oblimin the natural choice.
  # Note: factanal uses MLE extraction; results differ somewhat from
  # PCA-based extraction used in Bi and Barchard (2024).
  data("CCAI", package = "GPArotation")
  fa.unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none")
  oblimin(loadings(fa.unrotated), Tmat = Random.Start(3))  # single random start
  oblimin(loadings(fa.unrotated), randomStarts = 1)        # equivalent
  oblimin(loadings(fa.unrotated), randomStarts = 100)      # multiple starts

  # Directly via factanal call 
  factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "oblimin",
      control = list(rotate = list(normalize = TRUE, gam = -0.1, randomStarts = 100)))

  # --- Assessing local minima ---
  # For detailed investigation of local minima across all random starts
  # see vignette("GPA2local", package = "GPArotation").
  data(Thurstone, package = "GPArotation")
  infomaxQ(box26, normalize = TRUE, randomStarts = 150)
  geominQ(box26,  normalize = TRUE, randomStarts = 150)
}
\seealso{
   \code{\link[stats]{factanal}}, 
   \code{\link{GPFRSorth}}, 
   \code{\link{GPFRSoblq}}, 
   \code{\link{vgQ}},
   \code{\link{Harman8}}, 
   \code{\link{NetherlandsTV}}, 
   \code{\link{CCAI}}, 
   \code{\link{box26}} 
}
\references{
  Bernaards, C.A. and Jennrich, R.I. (2005) Gradient Projection Algorithms
    and Software for Arbitrary Rotation Criteria in Factor Analysis.
    \emph{Educational and Psychological Measurement}, \bold{65}, 676--696.
    doi: 10.1177/0013164404272507
  
  Bi, Y. and Barchard, K.A. (2024). Purchasing choices that reduce
  climate change: An exploratory factor analysis.
  \emph{Spectra Undergraduate Research Journal}, \bold{3}(2), 8--14.
  doi: 10.9741/2766-7227.1028.
    
  Fischer, R., & Fontaine, J. (2010). Methods for investigating structural 
    equivalence. In D. Matsumoto & F. van de Vijver (Eds.), 
    Cross-Cultural Research Methods in Psychology (pp. 179--215). 
    Cambridge University Press. doi: 10.1017/CBO9780511779381.010

  Garcia-Garzon, E., Abad, F.J. and Garrido, L.E. (2021). On omega
    hierarchical estimation: A comparison of exploratory bi-factor
    analysis algorithms. \emph{Multivariate Behavioral Research},
    \bold{56}(1), 101--119.
    doi: 10.1080/00273171.2020.1736977

  Jennrich, R.I. and Bentler, P.M. (2011). Exploratory bi-factor analysis.
    \emph{Psychometrika}, \bold{76}(4), 537--549.
    doi: 10.1007/s11336-011-9218-4

For references to individual rotation criteria see
  \code{vignette("GPA1guide", package = "GPArotation")}.  } 
\author{Coen A. Bernaards and Robert I. Jennrich
        with some R modifications by Paul Gilbert.}
\concept{rotation}
\keyword{multivariate}


