Markov models ([markov_model])
A [markov_model] block declares a continuous-time Markov model (CTMM) endpoint: the observed variable is a discrete state recorded at irregular times, and the dynamics are the transition intensities between states. ferx builds the generator matrix Q, forms the transition-probability matrix P(Δt) = expm(Q·Δt), and scores each consecutive pair of state observations — see Continuous-time Markov models for the estimation side.
The CTMM endpoint requires the markov cargo feature (cargo build --features markov). It is opt-in while maturing; see the plan.
The transition-list form (recommended)
Declare the states — each bound to its integer DV code — and one line per allowed transition with its intensity:
[parameters]
theta LQ01(-0.7, -6.0, 3.0) # log intensity awake -> asleep
theta LQ10(-1.2, -6.0, 3.0) # log intensity asleep -> awake
[markov_model]
type = ctmm # ctmm (only value for now)
cmt = 5 # data-file CMT for the state observations
states = [awake=0, asleep=1] # label = DV integer code (explicit, never positional)
transition awake -> asleep = exp(LQ01) # intensity q_{awake→asleep} ≥ 0
transition asleep -> awake = exp(LQ10)states— a bracketed list oflabel=codeentries.codeis the integer value that appears in theDVcolumn for that state;labelnames the state for thetransitionlines. States may be coded with any non-negative integers (e.g.1/2), not only0…S−1. Codes must be unique.transition A -> B = <expr>— one per allowed transition.<expr>is the intensityq_{A→B} ≥ 0, written as any θ/η/covariate/[individual_parameters]expression (wrap it inexp(...)to keep it positive, as above). The generator’s diagonalq_jj = −Σ_{k≠j} q_jkis filled automatically — you never write it.cmt— the CMT column value carrying the state observations. Rows on this CMT are read as integer states; the same CMT cannot also be a Gaussian ([error_model]) endpoint.type— optional; defaults toctmm, the only family available today. Omitting the line parses as a CTMM.mctmm/dtmmare recognized but rejected as “not yet supported”.
Bare numeric states
Labels are optional. A purely numeric model reads:
[markov_model]
type = ctmm
cmt = 5
states = [0, 1]
transition 0 -> 1 = exp(LQ01)
transition 1 -> 0 = exp(LQ10)Data format
The DV column holds the integer state code for each observation — the same numeric convention as every other ferx endpoint (no string labels). Rows are ordinary observations (EVID = 0, MDV = 0); a missing DV is skipped as MDV = 1. The likelihood conditions on each subject’s first observed state, so no EVID = 3 / occupancy-flag rows are needed (unlike the NONMEM CTMM dataset convention).
ID,TIME,DV,CMT,EVID,MDV
1,0.0,0,5,0,0
1,1.1,0,5,0,0
1,1.8,1,5,0,0
1,4.6,0,5,0,0An observed DV that is not one of the declared states codes is rejected fail-loud at fit setup (naming the CMT and the offending value). Each subject’s CTMM rows must be non-decreasing in TIME — the reader does not reorder observations, so an out-of-order subject is rejected at fit setup rather than silently dropped.
Random effects and covariates
An intensity may carry between-subject variability and covariates:
[parameters]
theta LQ01(-0.7, -6.0, 3.0)
theta LQ10(-1.2, -6.0, 3.0)
theta BAGE(0.0, -3.0, 3.0)
omega ETA_Q ~ 0.1
[covariates]
AGE continuous
[markov_model]
type = ctmm
cmt = 5
states = [awake=0, asleep=1]
transition awake -> asleep = exp(LQ01 + BAGE * AGE + ETA_Q)
transition asleep -> awake = exp(LQ10)The generator is built once per subject from a baseline covariate snapshot (a time-homogeneous generator). A covariate that is time-varying in the data is therefore rejected at fit setup rather than silently frozen. For the same reason a bare TIME in an intensity is rejected at parse (it would silently resolve to 0). Intensities are evaluated with per-subject (BSV) η only, so an inter-occasion ([iov] / κ) reference is rejected.
An intensity is a rate and must evaluate non-negative for every subject: a parameter/covariate regime that drives an off-diagonal negative makes the generator non-stochastic, and that subject’s contribution is treated as degenerate (it repels the optimizer) rather than silently scored. Write intensities on a scale that stays positive — e.g. exp(...) — rather than an unconstrained linear form.
Drug- / PD-driven intensities (time-inhomogeneous Q(t))
An intensity may instead depend on the model state — a drug concentration or a pharmacodynamic response that evolves over time — making the generator time-inhomogeneous, Q(t) = f(state(t)). Reference an ODE state by name in the transition (there is no Cc builtin — write a concentration as central / V, exactly as a drug-driven survival hazard does):
[structural_model]
ode(obs_cmt=central, states=[depot, central])
[odes]
d/dt(depot) = -KA * depot
d/dt(central) = KA * depot - (CL/V) * central
[markov_model]
type = ctmm
cmt = 5
states = [awake=0, asleep=1]
transition awake -> asleep = exp(LQ01 + SLOPE * (central / V))
transition asleep -> awake = exp(LQ10)When an intensity references a state, ferx solves the model’s ODE system for the subject and integrates the occupancy equation dP/dτ = P·Q(state(t)) (forward Kolmogorov, so P(Δt)[from,to] = Pr(to | from)) over each observation gap (there is no closed form once Q varies within the gap), scoring the same −Σ log P(Δt_m)[s_m, s_{m+1}]. Any transform is written inline (e.g. an Emax effect EMAX * R / (EC50 + R) on a response state R); a state reached only through an [individual_parameters] value is rejected — reference the state directly in the transition line. This requires an ODE ([odes]) model; the occupancy integration uses the model’s ODE tolerance (TOL).
A complete runnable model is examples/ctmm_pd_2state.ferx (with data/ctmm_pd_2state.csv): a concentration-driven 2-state process where ferx recovers the transition intensities and the drug effect from the Gillespie-simulated data.
Current limitations
type = mctmm/type = dtmm(minimal-CTMM and discrete-time Markov) — planned.- The matrix (
q12 = …) spelling and aninitoccupancy vector — planned. - Simulation / prediction of a CTMM endpoint — planned.
- A drug/PD-driven intensity requires an ODE model and a state referenced directly in the transition; analytic (closed-form) PK as a driver is planned.
- Estimators:
focei(default),saem, andimp. Gauss–Newton (gn/gn_hybrid) is rejected (its gradient is Gaussian-specific).