% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/altset.test.R
\name{altset.test}
\alias{altset.test}
\alias{print.altset_test}
\alias{as.data.frame.altset_test}
\title{Alternative-set robustness test for QCA solutions}
\usage{
altset.test(
  raw.data,
  calib.data,
  outcome,
  conditions,
  calib_spec,
  test.conditions = conditions,
  test.outcome = FALSE,
  anchors_to_test = NULL,
  solution = "all",
  include = NULL,
  which_M = 1,
  unit_step = NULL,
  unit_step_divisor = 10,
  calib_max_steps = 20,
  incl.cut = 1,
  incl_step = 0.01,
  incl_max_steps = 20,
  n.cut = 1,
  ncut_step = 1,
  ncut_max_steps = 20,
  dir.exp = NULL,
  i_mode = c("all", "C1P1"),
  exclude_mode = c("recompute", "static", "none"),
  exclude_recompute = list(type = 2),
  exclude_static = NULL,
  n_draws = 100,
  fit_tol = 1e-06,
  seed = NULL,
  progress = TRUE,
  verbose = FALSE,
  ...
)

\method{print}{altset_test}(x, row.names = FALSE, ...)

\method{as.data.frame}{altset_test}(x, ...)
}
\arguments{
\item{raw.data}{A data frame object containing the raw, uncalibrated
condition columns, and the raw outcome column when \code{test.outcome = TRUE}.}

\item{calib.data}{A data frame object containing the calibrated outcome
and calibrated condition columns used for the baseline analysis.}

\item{outcome}{Name of the outcome column in \code{calib.data}. This must be a
single non-empty character string.}

\item{conditions}{Character vector of calibrated condition names in
\code{calib.data}.}

\item{calib_spec}{Named list of calibration specifications, one per
condition, plus one for the outcome when \code{test.outcome = TRUE}. Each entry
must contain \code{raw}, \code{type}, and \code{thresholds}, may contain \code{method}, and may
contain \code{calibrate}, a named list of additional \code{\link[QCA:calibrate]{QCA::calibrate()}}
arguments for that set.}

\item{test.conditions}{Subset of \code{conditions} to perturb when generating
random alternative calibration draws. May be \code{NULL} only when
\code{test.outcome = TRUE}, in which case only the outcome calibration is
perturbed.}

\item{test.outcome}{Logical; if \code{TRUE}, also perturb the outcome calibration.
The outcome must be represented in \code{calib_spec}, and must not be included
in \code{conditions}.}

\item{anchors_to_test}{Character vector of anchors eligible for perturbation,
or \code{NULL} to use all anchors implied by each tested set's calibration
method. Crisp sets use \code{"T"}. Fuzzy direct three-threshold sets use
\code{"E"}, \code{"C"}, and \code{"I"}. Fuzzy indirect sets use \code{"T1"},
\code{"T2"}, and so on. Fuzzy direct six-threshold sets use \code{"E1"},
\code{"C1"}, \code{"I1"}, \code{"I2"}, \code{"C2"}, and \code{"E2"}.}

\item{solution}{Solution type to monitor. Accepted values are \code{"all"},
\code{"con"} or \code{"conservative"}, \code{"par"} or \code{"parsimonious"}, and \code{"int"} or
\code{"intermediate"}.}

\item{include}{Optional minimization include setting. Currently, this
argument accepts only \code{NULL}, \code{""}, or \code{"?"}.}

\item{which_M}{Positive integer giving which solution alternative to use
when minimization returns multiple models.}

\item{unit_step}{Numeric step size used to move calibration thresholds when
building candidate alternative draws. Supply either one value applied to
all calibrated sets or one value per condition, plus the outcome when
\code{test.outcome = TRUE}. If \code{NULL}, qcaERT computes scale-aware steps from
each set's threshold spacing.}

\item{unit_step_divisor}{Positive number used to compute \code{unit_step}
automatically when \code{unit_step = NULL}. The default is \code{10}.}

\item{calib_max_steps}{Maximum number of threshold moves away from the
baseline used when building alternative calibration candidates.}

\item{incl.cut}{Baseline inclusion cutoff passed to \code{\link[QCA:truthTable]{QCA::truthTable()}}.}

\item{incl_step}{Positive step size used to build the candidate grid of
inclusion-cutoff values around \code{incl.cut}.}

\item{incl_max_steps}{Maximum number of stepwise moves away from the
baseline \code{incl.cut} used to build the candidate grid.}

\item{n.cut}{Baseline truth table frequency cutoff passed to
\code{\link[QCA:truthTable]{QCA::truthTable()}}.}

\item{ncut_step}{Positive integer step size used to build the candidate grid
of frequency-cutoff values around \code{n.cut}.}

\item{ncut_max_steps}{Maximum number of stepwise moves away from the
baseline \code{n.cut} used to build the candidate grid.}

\item{dir.exp}{Directional expectations used when the monitored solution is
intermediate.}

\item{i_mode}{Character string controlling intermediate-solution selection.
Accepted values are \code{"all"} and \code{"C1P1"}.}

\item{exclude_mode}{Character string controlling how excluded rows are
handled for parsimonious and intermediate minimization. \code{"recompute"}
recalculates exclusions from each drawn truth table using
\code{exclude_recompute}, \code{"static"} reuses \code{exclude_static}, and \code{"none"}
does not use exclusions.}

\item{exclude_recompute}{Named list of arguments passed to \code{\link[QCA:findRows]{QCA::findRows()}}
when \code{exclude_mode = "recompute"}.}

\item{exclude_static}{Already computed exclusion object reused when
\code{exclude_mode = "static"}.}

\item{n_draws}{Number of random alternative draws to run.}

\item{fit_tol}{Non-negative tolerance used when deciding whether fit values
changed.}

\item{seed}{Optional integer seed passed to \code{\link[=set.seed]{set.seed()}} before generating
the random draws.}

\item{progress}{Logical; if \code{TRUE} and the session is interactive, show a
text progress bar.}

\item{verbose}{Logical; if \code{TRUE}, print a completion message after each
draw.}

\item{...}{Additional arguments routed through the QCA workflow. Arguments
matching \code{\link[QCA:truthTable]{QCA::truthTable()}} are forwarded to truth table construction;
remaining minimization arguments are filtered and forwarded to
\code{\link[QCA:minimize]{QCA::minimize()}}. The function also looks in \code{...} for \code{include},
\code{dir.exp}, or \code{direxp} if those arguments were not supplied explicitly.
In \code{\link[=print.altset_test]{print.altset_test()}}, \code{...} is passed to \code{\link[=print.data.frame]{print.data.frame()}}. In
\code{\link[=as.data.frame.altset_test]{as.data.frame.altset_test()}}, \code{...} is ignored.}

\item{x}{An \code{altset_test} object returned by \code{\link[=altset.test]{altset.test()}}.}

\item{row.names}{Logical; passed to \code{\link[=print.data.frame]{print.data.frame()}} by
\code{\link[=print.altset_test]{print.altset_test()}}.}
}
\value{
An object of class \code{altset_test} with the following components:
\describe{
\item{\code{summary}}{A list with summary values named \code{n_draws},
\code{n_same_solution}, \code{n_fit_compared}, \code{n_same_fit},
\code{score_solution}, \code{score_fit}, \code{score_total},
\code{score_solution_by_solution_type}, and \code{score_fit_by_solution_type}.}
\item{\code{baseline}}{A list containing the baseline analysis, baseline draw
metadata, exclusion information, selected solution terms used for
comparison, fit information, and status information.}
\item{\code{diagnostics}}{A detailed data frame with one row per draw. It
includes the sampled \code{incl.cut} and \code{n.cut}, run status,
solution-change information, fit-change information, changed-set
information, and error information when a draw fails.}
\item{\code{results}}{A compact data frame with the columns
\code{draw}, \code{incl.cut}, \code{n.cut}, \code{status}, \code{n_changed_sets},
\code{changed_sets}, \code{changed_roles}, \code{solution_change}, \code{fit_changed_types},
\code{n_fit_deltas}, and \code{max_abs_fit_delta}.}
\item{\code{by_draw}}{A named list with one entry per draw. Each entry stores
the full run result, solution-comparison information, fit-comparison
information, and draw-level fit details.}
\item{\code{settings}}{A list containing the analysis settings used to build
the result object.}
}

\code{print.altset_test()} prints a concise summary, the \code{results} table, and
solution-type-specific match-rate tables. \code{as.data.frame.altset_test()} returns
the \code{results} table.
}
\description{
Repeatedly generates alternative analyses by jointly varying calibration
anchors, the raw consistency threshold, and the frequency cutoff for truth
table rows, then reruns the QCA analysis for each generated specification.
For each specification, the function records whether the solution under
evaluation changes, whether parameters of fit change, which conditions or
outcome were recalibrated, and whether the analysis failed to produce a
solution.
}
\details{
The function first runs a baseline analysis using \code{calib.data},
\code{incl.cut}, and \code{n.cut}. It then generates \code{n_draws} random alternative
draws.

Each draw samples:
\itemize{
\item one admissible inclusion cutoff from the grid defined by
\code{incl.cut}, \code{incl_step}, and \code{incl_max_steps},
\item one admissible frequency cutoff from the grid defined by \code{n.cut},
\code{ncut_step}, and \code{ncut_max_steps}, and
\item one admissible alternative calibration specification sampled from
\code{calib_spec} by moving method-specific anchors for \code{test.conditions}, and
for the outcome when \code{test.outcome = TRUE}, by integer multiples of each
set's \code{unit_step}.
}

The function rejects a sampled draw if it is identical to the baseline on
all three dimensions and resamples until it gets a non-baseline draw or
reaches the internal retry limit.

The shared solution-control, exclusion, calibration-specification, and
returned-object conventions are described in \code{?qcaERT_conventions}.
}
\examples{
\donttest{
library(QCA)
data(LR)

conditions <- c("DEV", "URB", "LIT", "IND", "STB")
outcome <- "SURV"
dir_exp <- rep("1", length(conditions))

thresholds <- list(
  DEV = findTh(LR$DEV, groups = 7),
  URB = findTh(LR$URB, groups = 4),
  LIT = findTh(LR$LIT, groups = 4),
  IND = findTh(LR$IND, groups = 4),
  STB = findTh(LR$STB, groups = 4),
  SURV = findTh(LR$SURV, groups = 4)
)

dat <- LR
dat$DEV <- calibrate(LR$DEV, type = "fuzzy", thresholds = thresholds$DEV)
dat$URB <- calibrate(LR$URB, type = "fuzzy", thresholds = thresholds$URB)
dat$LIT <- calibrate(LR$LIT, type = "fuzzy", thresholds = thresholds$LIT)
dat$IND <- calibrate(LR$IND, type = "fuzzy", thresholds = thresholds$IND)
dat$STB <- calibrate(LR$STB, type = "fuzzy", thresholds = thresholds$STB)
dat$SURV <- calibrate(LR$SURV, type = "fuzzy", thresholds = thresholds$SURV)

calib_spec <- list(
  DEV = list(raw = "DEV", type = "fuzzy", method = "direct", thresholds = thresholds$DEV),
  URB = list(raw = "URB", type = "fuzzy", method = "direct", thresholds = thresholds$URB),
  LIT = list(raw = "LIT", type = "fuzzy", method = "direct", thresholds = thresholds$LIT),
  IND = list(raw = "IND", type = "fuzzy", method = "direct", thresholds = thresholds$IND),
  STB = list(raw = "STB", type = "fuzzy", method = "direct", thresholds = thresholds$STB)
)

calib_spec_outcome <- calib_spec
calib_spec_outcome$SURV <- list(
  raw = "SURV",
  type = "fuzzy",
  method = "direct",
  thresholds = thresholds$SURV
)

# Common use: sample alternative calibration, incl.cut, and n.cut settings.
altset_out <- altset.test(
  raw.data = LR,
  calib.data = dat,
  outcome = outcome,
  conditions = conditions,
  calib_spec = calib_spec,
  test.conditions = c("DEV", "URB"),
  unit_step = NULL,
  unit_step_divisor = 10,
  calib_max_steps = 5,
  incl.cut = 0.8,
  incl_step = 0.02,
  incl_max_steps = 5,
  n.cut = 1,
  ncut_step = 1,
  ncut_max_steps = 2,
  n_draws = 50,
  seed = 123,
  solution = "all",
  dir.exp = dir_exp,
  progress = TRUE
)

altset_out
as.data.frame(altset_out)
altset_out$summary

# Special case: include the calibrated outcome among sampled calibration
# perturbations. The outcome stays out of conditions.
altset_outcome <- altset.test(
  raw.data = LR,
  calib.data = dat,
  outcome = outcome,
  conditions = conditions,
  calib_spec = calib_spec_outcome,
  test.conditions = c("DEV", "URB"),
  test.outcome = TRUE,
  unit_step = NULL,
  unit_step_divisor = 10,
  calib_max_steps = 5,
  incl.cut = 0.8,
  incl_step = 0.02,
  incl_max_steps = 5,
  n.cut = 1,
  ncut_step = 1,
  ncut_max_steps = 2,
  n_draws = 50,
  seed = 456,
  solution = "all",
  dir.exp = dir_exp,
  progress = TRUE
)

as.data.frame(altset_outcome)
}

}
\seealso{
\code{\link[=calib.test]{calib.test()}}, \code{\link[=incl.test]{incl.test()}}, \code{\link[=ncut.test]{ncut.test()}}, \code{\link[=loo.test]{loo.test()}},
\code{\link[=subsample.test]{subsample.test()}}, \code{\link[=theory.test]{theory.test()}}, \code{\link[=cluster.test]{cluster.test()}}, \code{\link[=sol.df]{sol.df()}}
}
