% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/bigexp.R
\name{bigexp_terms}
\alias{bigexp_terms}
\title{Create a deterministic expansion spec for wide polynomial and interaction models}
\usage{
bigexp_terms(
  formula,
  data,
  factorial_order = 3L,
  polynomial_order = 3L,
  include_pc_2way = TRUE,
  include_pc_3way = FALSE,
  intercept = TRUE,
  blocking = NULL,
  discrete_numeric = NULL,
  audit = c("warn", "error", "none"),
  audit_numeric_rate = 0.9,
  audit_unique_ratio = 0.8,
  audit_min_n = 12L,
  report = TRUE
)
}
\arguments{
\item{formula}{Main-effects formula of the form \code{y ~ X1 + X2 + G} or
\code{y ~ .}. The right-hand side should contain main effects only; do not
include \code{:} (interactions), \code{^} (factorial shortcuts),
\code{I()} powers, transformed terms such as \code{log(X1)}, or inline
polynomial expansions. The helper will generate interactions and
polynomial terms automatically. Dot exclusions such as
\code{y ~ . - X1} are honored. Note that with \code{y ~ .} every
non-response column of \code{data} becomes a predictor, including any
other response columns present in the data frame; list the main effects
explicitly (or use exclusions) when the data holds several responses.}

\item{data}{Data frame used to decide types and lock factor levels.}

\item{factorial_order}{Integer >= 1. Maximum order of factorial interactions
among the non-blocking main effects. For example, 1 gives main effects
only, 2 gives up to two-way interactions, 3 gives up to three-way
interactions, and so on.}

\item{polynomial_order}{Integer >= 1. Maximum polynomial degree for continuous
non-blocking predictors. A value of 1 means only linear terms; 2 adds
squares \code{I(X^2)}; 3 adds cubes \code{I(X^3)}; in general, all powers
\code{I(X^k)} for \code{k} from 2 up to \code{polynomial_order} are added.}

\item{include_pc_2way}{Logical. If \code{TRUE} (default) and
\code{polynomial_order >= 2}, include partial-cubic two-way terms of the
form \code{Z:I(X^2)} where \code{X} is continuous and \code{Z} is another
non-blocking predictor.}

\item{include_pc_3way}{Logical. If \code{TRUE} and \code{polynomial_order >= 2},
include partial-cubic three-way terms \code{I(X^2):Z:W} among non-blocking
predictors.}

\item{intercept}{Logical. If \code{TRUE} (default), include an intercept in the
expansion; if \code{FALSE}, the generated RHS drops the intercept.}

\item{blocking}{Optional character vector of column names in \code{data} to
treat as blocking factors. These variables are included in the spec and
typed like other predictors (categorical vs continuous), but they enter the
model only as additive main effects and never appear in interactions,
polynomials, or partial-cubic terms.
\strong{Important:} when using \code{y ~ .}, blocking variables are
automatically excluded from the "non-blocking" predictor set so they do not
trigger a conflict error.
When using an explicit RHS (for example \code{y ~ X1 + X2}), blocking
variables must not also be explicitly listed on the right-hand side.}

\item{discrete_numeric}{Optional specification of "discrete numeric" predictors
for downstream sampling (for example in \code{svem_random_table_multi()}).
These predictors are still treated as numeric for modeling and expansion
(that is, they remain continuous in the design matrix and may participate
in polynomial and interaction terms). This option only records a finite set
of preferred numeric levels to be used when randomly generating recipes.
Supply either:
\itemize{
\item a character vector of predictor names, in which case the allowed
levels are inferred as the sorted unique finite values observed in
\code{data}; or
\item a named list mapping predictor names to numeric vectors of allowed
levels. If an entry is \code{NULL} or length zero, levels are
inferred from \code{data} for that predictor.
}}

\item{audit}{How to handle suspicious typing / high-cardinality issues when
building the spec. One of \code{"warn"} (default), \code{"error"}, or
\code{"none"}. Audits cover numeric-like character/factor columns (including
percent strings like \code{"25\%"}), and very high-cardinality categorical
predictors that are likely IDs or mis-typed numerics.}

\item{audit_numeric_rate}{Numeric in (0,1). If at least this fraction of
non-missing values parse as numeric (after stripping commas and an optional
trailing \code{\%}), the column is flagged as numeric-like when stored as
character/factor.}

\item{audit_unique_ratio}{Numeric in (0, 1). For categorical predictors, warn/error
if \code{unique(non-missing) / n_nonmissing >= audit_unique_ratio}.}

\item{audit_min_n}{Integer >= 1. Minimum number of non-missing values required
before audits are applied.}

\item{report}{Logical. If \code{TRUE} (default), print a compact summary of the
inferred predictor types and settings (via \code{print.bigexp_spec}) when
\code{bigexp_terms()} returns.}
}
\value{
An object of class \code{"bigexp_spec"} with components:
\itemize{
\item \code{formula}: expanded formula of the form \code{y ~ <big expansion>},
using the response from the input formula.
\item \code{rhs}: right-hand side expansion string (reusable for any response).
\item \code{vars}: character vector of predictor names (including blocking
variables) in the order discovered from the formula and data.
\item \code{is_cat}: named logical vector indicating which predictors are
treated as categorical (\code{TRUE}) versus continuous (\code{FALSE}).
\item \code{levels}: list of locked factor levels for categorical predictors.
\item \code{num_range}: 2 x p numeric matrix of ranges for continuous variables
(rows \code{c("min","max")}).
\item \code{settings}: list of expansion settings, including
\code{factorial_order}, \code{polynomial_order},
\code{include_pc_2way},
\code{include_pc_3way}, \code{intercept}, \code{blocking}, and
stored contrast information.
}
}
\description{
\code{bigexp_terms()} builds a specification object that:
\itemize{
\item decides which predictors are treated as continuous or categorical,
\item optionally treats selected variables as blocking factors that enter
the model only additively and never in interactions or polynomials,
\item locks factor levels from the supplied data,
\item records the contrast settings used when the model matrix is first built, and
\item constructs a reusable right-hand side (RHS) expression string for a large
expansion that can be shared across multiple responses and datasets.
}
}
\details{
The expansion for non-blocking predictors can include:
\itemize{
\item full factorial interactions among the listed main effects, up to a
chosen order;
\item polynomial terms \code{I(X^k)} for continuous predictors up to a
chosen degree; and
\item optional partial-cubic interactions of the form \code{Z:I(X^2)} and
\code{I(X^2):Z:W}.
}

Predictor types are inferred from \code{data}:
\itemize{
\item factors, characters, and logicals are treated as categorical;
\item all other numeric predictors are treated as continuous, and their
observed ranges are stored.
}

Variables listed in \code{blocking} are included in the spec and are typed
using the same rules as other predictors (for example, a numeric blocking
variable with many distinct values is treated as continuous). However,
blocking variables enter the model only as additive main effects, without
interactions or polynomial terms, regardless of \code{factorial_order} or
\code{polynomial_order}.

Once built, a \code{"bigexp_spec"} can be reused to create consistent
expansions for new datasets via \code{\link{bigexp_prepare}} and
\code{\link{bigexp_formula}}. The RHS and contrast settings are locked, so
the same spec applied to different data produces design matrices with the
same columns in the same order (up to missing levels for specific batches).
}
\section{Typical workflow}{

In a typical multi-response workflow you:
\enumerate{
\item Call \code{bigexp_terms()} once on your training data to build and
lock the expansion (types, levels, contrasts, RHS).
\item Fit models using \code{spec$formula} and the original data
(for example, \code{SVEMnet(spec$formula, data, ...)} or
\code{lm(spec$formula, data)}).
\item For new batches, call \code{\link{bigexp_prepare}} with the same
\code{spec} so that design matrices have exactly the same columns
and coding.
\item For additional responses on the same factor space, use
\code{\link{bigexp_formula}} to swap the left-hand side while
reusing the locked expansion.
}
}

\examples{
## Example 1: small design with one factor
set.seed(1)
df <- data.frame(
  y  = rnorm(20),
  X1 = rnorm(20),
  X2 = rnorm(20),
  G  = factor(sample(c("A", "B"), 20, replace = TRUE))
)

## Two-way interactions and up to cubic terms in X1 and X2
spec <- bigexp_terms(
  y ~ X1 + X2 + G,
  data             = df,
  factorial_order  = 2,
  polynomial_order = 3
)

print(spec)

## Example 2: pure main effects (no interactions, no polynomial terms)
spec_main <- bigexp_terms(
  y ~ X1 + X2 + G,
  data             = df,
  factorial_order  = 1,  # main effects only
  polynomial_order = 1   # no I(X^2) or higher
)

## Example 3: blocking factors (categorical and continuous)
set.seed(2)
df_block <- data.frame(
  y           = rnorm(30),
  X1          = rnorm(30),
  X2          = rnorm(30),
  G           = factor(sample(c("A", "B"), 30, replace = TRUE)),
  Operator    = factor(sample(paste0("Op", 1:3), 30, replace = TRUE)),
  AmbientTemp = rnorm(30, mean = 22, sd = 2)  # continuous blocking covariate
)

## Here Operator (categorical) and AmbientTemp (continuous) are blocking factors:
## they enter additively, but do not appear in interactions or polynomials.
spec_block <- bigexp_terms(
  y ~ X1 + X2 + G,
  data             = df_block,
  factorial_order  = 2,
  polynomial_order = 3,
  blocking         = c("Operator", "AmbientTemp")
)

print(spec_block)
spec_block$rhs

## Example 4: discrete numeric predictors (finite numeric support)
## A common case is a numeric process setting that only takes a small set
## of allowed values (e.g., 0.5, 1, 2, 4). Use `discrete_numeric` in
## bigexp_terms() so downstream sampling respects those levels automatically.
\donttest{
set.seed(3)
D_allowed <- c(0.5, 1, 2, 4)
df_disc <- data.frame(
  y  = rnorm(60),
  D  = sample(D_allowed, 60, replace = TRUE),   # numeric with discrete support
  X1 = rnorm(60),
  G  = factor(sample(c("A", "B"), 60, replace = TRUE))
)

# Record that D should be treated as "discrete numeric" for downstream sampling.
# Levels are inferred automatically from the training data.
spec_disc <- bigexp_terms(
  y ~ D + X1 + G,
  data             = df_disc,
  factorial_order  = 2,
  polynomial_order = 2,
  discrete_numeric = "D"
)


# Fit. The discrete support is expected to propagate into fit$sampling_schema
# (assuming the updated SVEMnet implementation that stores sampling_schema).
fit_disc <- SVEMnet(spec_disc, df_disc, nBoot = 20)

# Score random candidates; sampled D values stay in D_allowed
scored <- svem_score_random(
  objects         = list(y = fit_disc),
  goals           = list(y = list(goal = "max", weight = 1)),
  n               = 2000,
  numeric_sampler = "random",
  verbose         = FALSE
)

table(scored$score_table$D)
stopifnot(all(scored$score_table$D \%in\% D_allowed))
}
}
\seealso{
\code{\link{bigexp_prepare}}, \code{\link{bigexp_formula}},
\code{\link{bigexp_train}}
}
