Qualitative structure of a discrete-time Markov chain
Source:R/chain_structure.R
chain_structure.RdComputes properties that depend only on the transition matrix support, not on any starting distribution: state classification, communicating classes, periods, irreducibility / aperiodicity / regularity / reversibility, hitting probabilities, and absorption analysis when absorbing states exist.
Usage
chain_structure(x, normalize = TRUE, tol = 1e-10)
# S3 method for class 'chain_structure'
print(x, ...)
# S3 method for class 'chain_structure'
plot(x, show_values = TRUE, digits = 2L, ...)
# S3 method for class 'chain_structure'
summary(object, ...)
# S3 method for class 'chain_structure_group'
print(x, ...)
# S3 method for class 'chain_structure_group'
summary(object, ...)
# S3 method for class 'summary_chain_structure'
print(x, ...)Arguments
- x
A
netobject,cograph_network,tnamodel, transition matrix, or sequence data.frame (passed throughbuild_network()withmethod = "relative"). Anetobject_groupis also accepted and analysed constituent by constituent. For theprint()andplot()methods: an object of classchain_structure,chain_structure_grouporsummary_chain_structure.- normalize
Logical. If
TRUE(default), rows of the transition matrix are renormalized to sum to 1 before analysis (seepassage_time()for the same convention).- tol
Numerical tolerance for the reversibility check (detailed balance) and for treating near-zero entries as zero when building the support graph (which drives
classification,communicating_classes,period, andhitting_probabilities). It does not govern the absorbing-state test: a state is absorbing only whenP[i, i]equals 1 to an internal fixed tolerance of.Machine$double.eps^0.5, independent oftol(so raisingtolto ignore tiny transition probabilities never reclassifies a near-deterministic state as absorbing). Default1e-10.- ...
In
plot.chain_structure(),print.chain_structure(),summary.chain_structure()andsummary.chain_structure_group(): Ignored. Inprint.chain_structure_group(): Forwarded toprint.chain_structure. Inprint.summary_chain_structure(): Forwarded toprint.data.frame.- show_values
Logical. If
TRUE(default), prints the numeric probability inside each cell. SetFALSEfor large state spaces (n > 10) where labels overlap.- digits
Integer. Decimal places for in-cell labels.
- object
For the
summary()method: an object of classchain_structureorchain_structure_group.
Value
For a netobject_group, a c("chain_structure_group", "list"):
a named list holding one chain_structure per constituent network,
with its own print() and summary() methods.
Otherwise a chain_structure object: a list with elements
statesCharacter vector of state names.
classificationNamed character vector. One of
"absorbing","recurrent","transient"per state.communicating_classesList of state-name vectors. Each sublist is a strongly connected component of the support graph.
recurrent_classesSubset of
communicating_classesthat are closed (no transitions leaving the class).transient_classesSubset that are not closed.
absorbing_statesCharacter vector of states with
P[i, i] = 1(tested exactly, to within.Machine$double.eps^0.5; the user-facingtoldoes not relax this).periodNamed integer vector. Period of each recurrent state;
NAfor transient states.is_irreducibleLogical.
TRUEiff there is exactly one communicating class.is_aperiodicLogical.
TRUEiff every recurrent state has period 1.is_regularLogical.
is_irreducible && is_aperiodic.is_reversibleLogical or
NA.TRUEiff the chain satisfies detailed balance against its stationary distribution.NAfor non-irreducible chains (no unique stationary).hitting_probabilitiesn x nmatrix.[i, j] = P(ever reach j starting from i), computed over the sametol-thresholded support graph that drivesclassificationso the two are mutually consistent (a state classified"absorbing"/closed never shows hitting probability to states outside its class).absorption_probabilitiesn_transient x n_absorbingmatrix orNULLif no transient -> absorbing pathway exists.[i, j] = P(eventual absorption in j | start in i).mean_absorption_timeNamed numeric vector or
NULL. Expected number of steps until absorption from each transient state.PThe (possibly normalized) transition matrix used.
In print.chain_structure(), print.chain_structure_group() and print.summary_chain_structure(): x invisibly.
In plot.chain_structure(): A ggplot object.
In summary.chain_structure(): A data.frame with one row per state, of class c("summary_chain_structure", "data.frame"), carrying the chain-level flags (is_regular, is_irreducible, is_aperiodic, is_reversible, n_classes, absorbing_states) as attributes, which its print() method shows as a header. Columns as described above.
In summary.chain_structure_group(): A data.frame with columns group, state, classification, period, persistence, return_probability, sojourn_steps, plus stationary_probability if all groups are irreducible and mean_absorption_time if any group has absorbing states.
Details
Built specifically as a diagnostic to run before trusting the output
of passage_time() or markov_stability(). Both implicitly assume a
regular chain (irreducible + aperiodic) so that the stationary
distribution is unique and meaningful. Use is_regular to check.
The fundamental-matrix absorption math follows Kemeny & Snell (1976); the hitting-probability linear system follows Norris (1997).
Methods
plot.chain_structure(): Renders the hitting-probability matrix as a heatmap, with rows and columns ordered by communicating class so the block structure is visible at a glance. State labels along both axes are coloured by classification (absorbing / recurrent / transient). The subtitle summarises the chain-level properties (regular, reversible).print.chain_structure(): Prints a compact chain-level header. For the full per-state table, callsummary()on the same object.print.chain_structure_group(): One header line per group, followed by each group's per-state table (viasummary.chain_structure).print.summary_chain_structure(): Prints a one-line chain header followed by the tidy per-state table.summary.chain_structure(): Returns a single data.frame with one row per state, combining every per-state metricchain_structure()computes. Always includesstate,classification,period,persistence(the diagonal of the transition matrix),return_probability(the diagonal of the hitting matrix) andsojourn_steps(1 / (1 - persistence), which isInffor an absorbing state). Adds the chain'sstationary_probabilitywhen the chain is irreducible, and absorption columns when it has any absorbing states:absorption_probabilityfor a single absorbing state or oneabsorbed_in_<state>column per state when there are several, plusmean_absorption_time.summary.chain_structure_group(): Produces a single tidy data.frame with one row per (group, state) combination, combining classification, persistence, sojourn, and – when applicable – stationary or mean-absorption-time columns. Useful for side-by-side reporting ofchain_structure()across the members of anetobject_group.
Plot colours
Cell colour encodes P(ever reach j | start at i). The diagonal
uses the return-time convention (P(return to j in >= 1 steps)),
matching markovchain::hittingProbabilities. A non-irreducible chain
shows zero off-block entries – visual evidence of one-way doors
between behavioural phases. An absorbing chain shows a column of 1's
for the absorbing state.
Summary columns
Columns are ordered for readability: identifiers first, classification second, dynamic per-state metrics last.
References
Kemeny, J. G. and Snell, J. L. (1976). Finite Markov Chains. Springer-Verlag.
Norris, J. R. (1997). Markov Chains. Cambridge University Press.
Examples
net <- build_network(as.data.frame(trajectories), method = "relative")
cs <- chain_structure(net)
print(cs)
#> Chain structure [3 states, 1 communicating classes]
#> irreducible: TRUE aperiodic: TRUE regular: TRUE reversible: FALSE
#> recurrent classes: 1 transient classes: 0
#>
#> Use summary(x) for the per-state table, plot(x) for the heatmap.
# \donttest{
summary(cs)
#> Chain structure summary [3 states, 1 classes]
#> irreducible: TRUE aperiodic: TRUE regular: TRUE reversible: FALSE
#>
#> state classification period persistence return_probability sojourn_steps
#> Active recurrent 1 0.6976 1 3.31
#> Average recurrent 1 0.6099 1 2.56
#> Disengaged recurrent 1 0.4831 1 1.93
#> stationary_probability
#> 0.3719
#> 0.4431
#> 0.1850
# }