% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/markov_order.R
\name{markov_order_test}
\alias{markov_order_test}
\title{Test the Markov order of a sequential process}
\usage{
markov_order_test(
  data,
  max_order = 3L,
  n_perm = 500L,
  alpha = 0.05,
  parallel = FALSE,
  n_cores = 2L,
  seed = NULL
)
}
\arguments{
\item{data}{A data.frame (wide format, one sequence per row) or list
of character vectors (one per trajectory). NAs are treated as end
of sequence.}

\item{max_order}{Integer. Highest Markov order to test. Default 3.}

\item{n_perm}{Integer. Number of within-\eqn{w} permutations per order.
Default 500.}

\item{alpha}{Numeric. Significance level for order selection. Default 0.05.}

\item{parallel}{Logical. Use \code{parallel::mclapply} for permutations.
Default \code{FALSE} (set \code{TRUE} only on Unix-like systems).}

\item{n_cores}{Integer. Cores for parallel execution. Default 2.}

\item{seed}{Optional integer seed for reproducibility.}
}
\value{
An object of class \code{net_markov_order} with elements:
\describe{
\item{optimal_order}{Integer. Selected order via sequential permutation test.}
\item{bic_order}{Integer. Order minimising BIC (reported by
\code{print}/\code{plot}; not used in the permutation selection).}
\item{aic_order}{Integer. Order minimising AIC (reported by
\code{print}/\code{plot}; not used in the permutation selection).}
\item{test_table}{Tidy data.frame, one row per order tested with
columns \code{order}, \code{loglik}, \code{AIC}, \code{BIC},
\code{df}, \code{g2}, \code{p_permutation}, \code{p_asymptotic},
\code{significant}. \code{AIC}/\code{BIC} are the
information-criterion values used for the \code{ic} plot panel and
to derive \code{aic_order}/\code{bic_order}; the order-0 row has
\code{NA} for the test columns (\code{df}, \code{g2},
\code{p_permutation}, \code{p_asymptotic}, \code{significant}).}
\item{permutation_null}{List of numeric vectors (length \code{max_order}),
one empirical null \eqn{G^2} distribution per order.}
\item{logliks}{Named numeric vector of log-likelihoods per order
(for AIC / BIC panel only, not used in the test).}
\item{layer_dofs}{Named integer vector of model degrees of freedom per
order (free parameters added at each layer), used to compute the
AIC / BIC columns.}
\item{transition_matrices}{List of fitted transition matrices.}
\item{states}{Character vector of observed state labels.}
\item{n_sequences, n_observations}{Data summary.}
\item{n_perm, alpha, max_order}{Call settings.}
}
}
\description{
Principled test of whether a categorical sequence is best described
as a \eqn{k}-th order Markov chain. At each order
\eqn{k = 1, \ldots,} \code{max_order}, the function computes the
classical likelihood-ratio statistic (\eqn{G^2}) for the conditional
independence \eqn{s \perp x \mid w}, where \eqn{w} is the
\eqn{(k-1)}-gram context, \eqn{x} is the extra (k-th-back) state
added at order \eqn{k}, and \eqn{s} is the next state. Under
\eqn{H_0} (order-\eqn{(k-1)} is correct), \eqn{s} is independent of
\eqn{x} given \eqn{w}.

The null distribution is obtained by an \strong{exact within-\eqn{w}
permutation test}: for each context \eqn{w} the successor labels are
exchangeable under \eqn{H_0}, so shuffling \eqn{s} within each
\eqn{w}-group yields an exact reference distribution for \eqn{G^2}.
No plug-in MLE bias and no refitting per replicate. An asymptotic
\eqn{\chi^2} p-value is reported alongside for reference.

The optimal order is the smallest \eqn{k} that is \strong{not}
significantly better than \eqn{k - 1} at level \code{alpha}: we
keep raising the order while the test rejects, and stop at the first
non-rejection.
}
\examples{
\donttest{
# First-order Markov data: test should select order 1
set.seed(1)
states <- letters[1:4]
tm <- matrix(runif(16), 4, 4, dimnames = list(states, states))
tm <- tm / rowSums(tm)
seqs <- lapply(1:30, function(.) {
  s <- character(50); s[1] <- sample(states, 1)
  for (i in 2:50) s[i] <- sample(states, 1, prob = tm[s[i - 1], ])
  s
})
res <- markov_order_test(seqs, max_order = 3, n_perm = 300, seed = 1)
res$optimal_order
summary(res)
plot(res)
}
}
