% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/api-simulation.R
\name{simulate_mfrm_data}
\alias{simulate_mfrm_data}
\title{Simulate long-format ordered many-facet data for design studies}
\usage{
simulate_mfrm_data(
  n_person = 50,
  n_rater = 4,
  n_criterion = 4,
  raters_per_person = n_rater,
  design = NULL,
  score_levels = 4,
  theta_sd = 1,
  rater_sd = 0.35,
  criterion_sd = 0.25,
  noise_sd = 0,
  step_span = 1.4,
  group_levels = NULL,
  dif_effects = NULL,
  interaction_effects = NULL,
  seed = NULL,
  model = c("RSM", "PCM", "GPCM"),
  step_facet = "Criterion",
  slope_facet = NULL,
  thresholds = NULL,
  slopes = NULL,
  assignment = NULL,
  sparse_controls = NULL,
  sim_spec = NULL
)
}
\arguments{
\item{n_person}{Number of persons/respondents.}

\item{n_rater}{Number of rater facet levels.}

\item{n_criterion}{Number of criterion/item facet levels.}

\item{raters_per_person}{Number of raters assigned to each person.}

\item{design}{Optional named design override supplied as a named list,
named vector, or one-row data frame. When \code{sim_spec = NULL}, names may use
canonical variables (\code{n_person}, \code{n_rater}, \code{n_criterion},
\code{raters_per_person}) or role keywords (\code{person}, \code{rater}, \code{criterion},
\code{assignment}). For the currently exposed facet keys, the schema-only
future branch input \code{design$facets = c(person = ..., rater = ..., criterion = ...)} is also accepted. Do not specify the same variable
through both \code{design} and the scalar count arguments.}

\item{score_levels}{Number of ordered score categories.}

\item{theta_sd}{Standard deviation of simulated person measures.}

\item{rater_sd}{Standard deviation of simulated rater severities.}

\item{criterion_sd}{Standard deviation of simulated criterion difficulties.}

\item{noise_sd}{Optional observation-level noise added to the linear predictor.}

\item{step_span}{Spread of step thresholds on the logit scale.}

\item{group_levels}{Optional character vector of group labels. When supplied,
a balanced \code{Group} column is added to the simulated data.}

\item{dif_effects}{Optional data.frame describing true group-linked DIF
effects. Must include \code{Group}, at least one design column such as
\code{Criterion}, and numeric \code{Effect}.}

\item{interaction_effects}{Optional data.frame describing true non-group
interaction effects. Must include at least one design column such as
\code{Rater} or \code{Criterion}, plus numeric \code{Effect}.}

\item{seed}{Optional random seed.}

\item{model}{Measurement model recorded in the simulation setup. The current
public generator supports \code{RSM}, \code{PCM}, and bounded \code{GPCM}.}

\item{step_facet}{Step facet used when \code{model = "PCM"} and threshold values
vary across levels. Currently \code{"Criterion"} and \code{"Rater"} are supported.}

\item{slope_facet}{Slope facet used when \code{model = "GPCM"}. The current
bounded \code{GPCM} branch requires \code{slope_facet == step_facet}.}

\item{thresholds}{Optional threshold specification. Use a numeric vector of
common thresholds; a named list such as \code{list(C01 = c(-1, 0, 1))}; a
numeric matrix with one row per \code{StepFacet} and one column per step; or a
long data frame with columns \code{StepFacet}, \code{Step}/\code{StepIndex}, and
\code{Estimate}.}

\item{slopes}{Optional slope specification used when \code{model = "GPCM"}.
Use either a numeric vector aligned to the generated slope-facet levels or
a data frame with columns \code{SlopeFacet} and \code{Estimate}. Supplied slopes are
treated as relative discriminations and normalized to the package's
geometric-mean-one identification convention on the log scale. When
omitted, slopes default to 1 for every slope-facet level, giving an exact
\code{PCM} reduction.}

\item{assignment}{Assignment design. \code{"crossed"} means every person sees
every rater; \code{"rotating"} uses a balanced rotating subset; \code{"resampled"}
reuses person-level rater-assignment profiles stored in \code{sim_spec};
\code{"sparse_linked"} uses an incomplete rating design with optional linking
persons; \code{"skeleton"} reuses an observed response skeleton stored in
\code{sim_spec}, including optional \code{Group}/\code{Weight} columns when available.
When omitted, the function chooses \code{"crossed"} if
\code{raters_per_person == n_rater}, otherwise \code{"rotating"}.}

\item{sparse_controls}{Optional named list used when
\code{assignment = "sparse_linked"}. Supported entries are \code{link_fraction},
\code{link_persons}, \code{link_raters_per_person}, \code{assignment_mode}, and
\code{min_common_persons_per_rater_pair}. See \code{\link[=build_mfrm_sim_spec]{build_mfrm_sim_spec()}} for the
same contract.}

\item{sim_spec}{Optional output from \code{\link[=build_mfrm_sim_spec]{build_mfrm_sim_spec()}} or
\code{\link[=extract_mfrm_sim_spec]{extract_mfrm_sim_spec()}}. When supplied, it defines the generator setup;
direct scalar arguments are treated as legacy inputs and should generally
be left at their defaults except for \code{seed}. Any custom public two-facet
names recorded in \code{sim_spec$facet_names} are also carried into the
simulated output and downstream planning helpers. If \code{sim_spec} stores an
active latent-regression population generator, the returned object also
carries the generated one-row-per-person background-data table needed to
refit that population model later.}
}
\value{
A long-format \code{data.frame} with core columns \code{Study}, \code{Person},
two simulated non-person facet columns, and \code{Score}. By default those
facet columns are \code{Rater} and \code{Criterion}; when \code{sim_spec} records custom
public names, those names are used instead. If group labels are simulated
or reused from an observed response skeleton, a \code{Group} column is
included. If a weighted response skeleton is reused, a \code{Weight} column is
also included.
}
\description{
Simulate long-format ordered many-facet data for design studies
}
\details{
This function generates synthetic ordered many-facet data under \code{RSM},
\code{PCM}, or the package's bounded \code{GPCM} branch.
The data-generating process is:
\enumerate{
\item Draw person abilities: \eqn{\theta_n \sim N(0, \texttt{theta\_sd}^2)}
\item Draw rater severities: \eqn{\delta_j \sim N(0, \texttt{rater\_sd}^2)}
\item Draw criterion difficulties: \eqn{\beta_i \sim N(0, \texttt{criterion\_sd}^2)}
\item Generate evenly-spaced step thresholds spanning \eqn{\pm}\code{step_span/2}
\item For each observation, compute the linear predictor
\eqn{\eta = \theta_n - \delta_j - \beta_i + \epsilon} where
\eqn{\epsilon \sim N(0, \texttt{noise\_sd}^2)} (optional)
\item Compute category probabilities under the recorded measurement model
(\code{RSM}, \code{PCM}, or bounded \code{GPCM}) and sample the response
}

Latent-value generation is explicit:
\itemize{
\item \code{latent_distribution = "normal"} draws centered normal person/rater/
criterion values using the supplied standard deviations
\item \code{latent_distribution = "empirical"} resamples centered support values
recorded in \code{sim_spec$empirical_support}
\item if \code{sim_spec$population$active = TRUE}, person measures are generated from
the stored latent-regression population model and template person
covariates rather than from \code{theta_sd}
}

When \code{dif_effects} is supplied, the specified logit shift is added to
\eqn{\eta} for the focal group on the target facet level, creating a
known DIF signal.  Similarly, \code{interaction_effects} injects a known
bias into specific facet-level combinations.

The generator targets the common two-facet rating design (persons
\eqn{\times} raters \eqn{\times} criteria).  \code{raters_per_person}
controls the incomplete-block structure: when less than \code{n_rater},
each person is assigned a rotating subset of raters to keep coverage
balanced and reproducible.

Threshold handling is intentionally explicit:
\itemize{
\item if \code{thresholds = NULL}, common equally spaced thresholds are generated
from \code{step_span}
\item if \code{thresholds} is a numeric vector, it is used as one common threshold set
\item if \code{thresholds} is a named list, numeric matrix, or data frame, threshold
values may vary by \code{StepFacet} (currently \code{Criterion} or \code{Rater})
}

For bounded \code{GPCM}, the generator now requires an explicit slope
contract in parallel with the threshold table. The current public branch
keeps \code{slope_facet == step_facet}, normalizes supplied slopes to the same
geometric-mean-one log-slope identification used by \code{\link[=fit_mfrm]{fit_mfrm()}}, and uses
the internal \code{category_prob_gpcm()} helper for response sampling. Broader
arbitrary-facet planning remains restricted until that slope-aware contract
is generalized beyond the current role-based design, population-forecasting,
diagnostic-screening, and signal-detection helpers.

Assignment handling is also explicit:
\itemize{
\item \code{"crossed"} uses the full person x rater x criterion design
\item \code{"rotating"} assigns a deterministic rotating subset of raters per person
\item \code{"sparse_linked"} assigns most persons to an incomplete rater subset and
assigns a configurable set of linking persons to a larger rater set
\item \code{"resampled"} reuses empirical person-level rater profiles stored in
\code{sim_spec$assignment_profiles}, optionally carrying over person-level
\code{Group}
\item \code{"skeleton"} reuses an observed person-by-rater-by-criterion response
skeleton stored in \code{sim_spec$design_skeleton}, optionally carrying over
\code{Group} and \code{Weight}
}

Sparse linked simulation is intended for planned-missing rating designs in
which connectivity is maintained through common linking persons. The
returned \code{mfrm_sparse_design} attribute summarizes design density, planned
missingness, rater coverage, and rater-pair common-person counts. These
summaries are design diagnostics, not model-fit statistics or universal
adequacy thresholds. This branch follows sparse rater-mediated assessment
design work by Wind, Jones, and Grajeda (2023,
doi:10.1177/01466216231182148), Wind and Jones (2018,
doi:10.1177/0013164417703733), and DeMars, Shapovalov, and Hathcoat
(2023).

For more controlled workflows, build a reusable simulation specification
first via \code{\link[=build_mfrm_sim_spec]{build_mfrm_sim_spec()}} or derive one from an observed fit with
\code{\link[=extract_mfrm_sim_spec]{extract_mfrm_sim_spec()}}, then pass it through \code{sim_spec}.

Returned data include attributes:
\itemize{
\item \code{mfrm_truth}: simulated true parameters (for parameter-recovery checks)
\item \code{mfrm_truth$signals}: injected DIF and interaction signal tables
\item \code{mfrm_truth$slope_table}: simulated discrimination table for bounded
\code{GPCM}
\item \code{mfrm_population_data}: generated one-row-per-person background data when
the simulation specification stores an active latent-regression generator,
including model-matrix xlevel and contrast provenance for categorical
covariates
\item \code{mfrm_simulation_spec}: generation settings (for reproducibility)
\item \code{mfrm_sparse_design}: sparse-design diagnostics when
\code{assignment = "sparse_linked"}, including design density, planned missing
rate, rater coverage, and rater-pair common-person counts
}
}
\section{Interpreting output}{

\itemize{
\item Higher \code{theta} values in \code{mfrm_truth$person} indicate higher person measures.
\item Higher values in \code{mfrm_truth$facets$Rater} indicate more severe raters.
\item Higher values in \code{mfrm_truth$facets$Criterion} indicate more difficult criteria.
\item \code{mfrm_truth$signals$dif_effects} and \code{mfrm_truth$signals$interaction_effects}
record any injected detection targets.
}
}

\section{Typical workflow}{

\enumerate{
\item Generate one design with \code{simulate_mfrm_data()}.
\item Fit with \code{\link[=fit_mfrm]{fit_mfrm()}} and diagnose with \code{\link[=diagnose_mfrm]{diagnose_mfrm()}}.
\item For repeated design studies, use \code{\link[=evaluate_mfrm_design]{evaluate_mfrm_design()}}.
}
}

\examples{
sim <- simulate_mfrm_data(
  n_person = 40,
  n_rater = 4,
  n_criterion = 4,
  raters_per_person = 2,
  seed = 123
)
head(sim)
names(attr(sim, "mfrm_truth"))
}
\seealso{
\code{\link[=evaluate_mfrm_design]{evaluate_mfrm_design()}}, \code{\link[=fit_mfrm]{fit_mfrm()}}, \code{\link[=diagnose_mfrm]{diagnose_mfrm()}}
}
