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.

Note

The CTMM endpoint requires the markov cargo feature (cargo build --features markov). It is opt-in while maturing; see the plan.

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,0

An 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 an init occupancy 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, and imp. Gauss–Newton (gn/gn_hybrid) is rejected (its gradient is Gaussian-specific).