% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/longitudinal_grmtree.R
\name{longitudinal_grmfit}
\alias{longitudinal_grmfit}
\title{Internal Function: Fit Constrained Longitudinal Graded Response Model}
\usage{
longitudinal_grmfit(
  y,
  x = NULL,
  start = NULL,
  weights = NULL,
  offset = NULL,
  ...,
  estfun = FALSE,
  object = FALSE
)
}
\arguments{
\item{y}{A numeric matrix of item responses in wide format. The first
\code{n_items} columns contain responses at Time 1 (T1) and the next
\code{n_items} columns contain responses at Time 2 (T2), for a total of
\code{2 * n_items} columns. Each row represents one individual. The number
of columns must be even and at least 4.}

\item{x}{Optional predictor matrix. Handled internally by the MOB framework
and not used directly in model fitting.}

\item{start}{Optional starting values for model parameters. Passed to
\code{\link[mirt]{mirt}}.}

\item{weights}{Optional case weights. Not currently used.}

\item{offset}{Optional offset. Not currently used.}

\item{...}{Additional arguments passed to \code{\link[mirt]{mirt}}.}

\item{estfun}{Logical indicating whether to compute empirical estimating
(score) functions for the MOB parameter instability tests. When
\code{TRUE}, standard errors are computed during model fitting (SE = TRUE)
and \code{\link[mirt]{estfun.AllModelClass}} is called to extract the score
contributions for each individual. Default is \code{FALSE}.}

\item{object}{Logical indicating whether to return the full
\code{\link[mirt]{mirt}} model object. Default is \code{FALSE}. Set to
\code{TRUE} when the fitted model is needed for post-hoc analyses (e.g., in
\code{\link{rs_characterize}}).}
}
\value{
A list containing:
\item{coefficients}{Item parameter estimates from
\code{mirt::coef(fit, IRTpars = TRUE, simplify = TRUE)}, including
discrimination (\code{a1}, \code{a2}) and threshold (\code{b1}, ...,
\code{bK}) parameters for all \code{2 * n_items} items, plus latent
trait means and covariance matrix.}
\item{objfun}{Negative log-likelihood of the fitted model. Used by MOB
to evaluate splits via partitioned log-likelihood maximization.}
\item{estfun}{Empirical estimating (score) functions if \code{estfun =
    TRUE}; \code{NULL} otherwise. An \code{N x p} matrix where \code{N}
is the number of individuals and \code{p} is the number of model
parameters. Used by MOB for score-based structural change tests.}
\item{object}{The full \code{SingleGroupClass} model object
if \code{object = TRUE}; \code{NULL} otherwise.}
}
\description{
Fits a constrained two-factor longitudinal graded response model (GRM) to
wide-format item response data from two time points. This is an internal
function called by \code{\link{longitudinal_grmtree}} during model-based
recursive partitioning and is not intended to be used directly.
}
\details{
This production version builds the equality constraints directly from the
known parameter structure rather than fitting an unconstrained model first to
discover that structure. Because the function is called hundreds of times
during tree construction, avoiding the extra (unconstrained) model fit at
every node yields a substantial speed-up with no change in results.
\subsection{Constrained Two-Factor Longitudinal GRM}{

The function specifies a two-factor GRM where the latent factors
\eqn{\theta_{T1}} and \eqn{\theta_{T2}} represent the construct at Time 1 and
Time 2, respectively. The model structure is:

\deqn{\theta_{T1} \sim N(0, 1)} \deqn{\theta_{T2} \sim N(\mu_{T2},
\sigma^2_{T2})} \deqn{Cov(\theta_{T1}, \theta_{T2}) = \sigma_{12}}

Items 1 through \eqn{M} load on \eqn{\theta_{T1}} and items \eqn{M+1} through
\eqn{2M} load on \eqn{\theta_{T2}}, where \eqn{M} is the number of items per
time point.

Under the null hypothesis of no response shift, item parameters are
constrained equal across time points. For each item \eqn{m}:
\itemize{
\item Discrimination: \eqn{a_{1,m} = a_{2,m+M}} (the T1 item's loading
on \eqn{\theta_{T1}} equals the T2 item's loading on \eqn{\theta_{T2}})
\item Thresholds: \eqn{b_{k,m} = b_{k,m+M}} for all category thresholds
\eqn{k = 1, \ldots, K_m}
}

The number of threshold constraints per item pair is determined by the
minimum number of observed response categories across T1 and T2 for that item
(minus 1). This handles cases where sparse response categories at one time
point produce fewer estimated thresholds (e.g., category 5 may be empty at T1
but observed at T2).
}

\subsection{Constraint Syntax}{

Constraints are specified using \code{mirt}'s CONSTRAIN syntax:
\itemize{
\item Discrimination: \code{(i, a1, j, a2)} constrains item \code{i}'s
\code{a1} parameter to equal item \code{j}'s \code{a2} parameter
\item Thresholds: \code{(i, j, dk)} constrains the \code{dk} threshold
to be equal between items \code{i} and \code{j}
}

where \code{i} is the T1 item index and \code{j = i + n_items} is the
corresponding T2 item index.
}

\subsection{Technical Details}{

The EM algorithm is run with a maximum of 1000 cycles (\code{technical =
list(NCYCLES = 1000)}) to accommodate the complexity of the constrained
two-factor model. Verbose output from \code{mirt} is suppressed. If the model
fails to converge or encounters an error, the function stops with an
informative error message.
}
}
\seealso{
\code{\link{grmtree}} fits a Graded Response Model Tree,
\code{\link{longitudinal_grmtree}} for the main tree-fitting function that
calls this internally, \code{\link[mirt]{mirt}} for the underlying IRT
estimation engine, \code{\link{rs_characterize}} for post-hoc response
shift testing within terminal nodes
}
\keyword{internal}
