API reference

Configuration

class markovmodus.config.SimulationParameters(*, num_states: int, transition_rates: TransitionRateSpec | None = None, proliferation_model: ProliferationModelSpec | None = None, num_genes: int, markers_per_state: int = 150, marker_overlap: MarkerOverlapSpec = 0, marker_reuse_cap: int = 2, baseline_expression: float = 2.0, marker_expression: float = 10.0, state_expression: np.ndarray | None = None, splicing_rate: float = 0.3, decay_rate: float = 0.3, dispersion: float | None = None, gene_ids: Sequence[str] | None = None, initial_state_probs: Sequence[float] | None = None, num_cells: int, t_final: float, dt: float = 1.0, rng_seed: int | None = None)[source]

Bases: object

Container for configuring a markovmodus simulation.

num_states

Number of latent states (nodes) in the hidden Markov graph.

Type:

int

transition_rates

Continuous-time rate matrix or callable returning transition rates for the current simulation state. Static matrices must have strictly non-negative off-diagonals and a zero diagonal. Callable outputs may be a global matrix with shape (num_states, num_states) or a per-cell tensor with shape (current_num_cells, num_states, num_states). When omitted, a dense complete graph with a fixed internal fallback rate is used.

Type:

numpy.ndarray | Callable[[Any], numpy.ndarray] | None

proliferation_model

Optional callable returning division rates and daughter-state probabilities for the current simulation state. When a cell divides, its existing row becomes one daughter and a second daughter row is appended, so num_cells is the initial population size. Dividing cells skip ordinary latent transitions in that same time step.

Type:

Callable[[Any], tuple[numpy.ndarray, numpy.ndarray]] | None

num_genes

Number of genes (each contributes an unspliced/spliced pair of counts).

Type:

int

markers_per_state

Number of marker genes to emphasise in each state.

Type:

int

marker_overlap

Either a scalar number of marker genes shared between every pair of states connected by a static non-zero transition rate, or a mapping from exact state groups to the number of marker genes shared by those states.

Type:

int | collections.abc.Mapping[tuple[int, …], int]

marker_reuse_cap

Upper bound on how many distinct states may share the same gene marker.

Type:

int

baseline_expression

Target steady-state spliced count for non-marker genes.

Type:

float

marker_expression

Target steady-state spliced count for marker genes.

Type:

float

state_expression

Optional state-by-gene steady-state spliced-count matrix overriding the automatically generated markers.

Type:

numpy.ndarray | None

splicing_rate

Rate at which unspliced RNA converts to spliced RNA.

Type:

float

decay_rate

Decay rate for spliced RNA.

Type:

float

dispersion

Optional negative-binomial dispersion parameter for adding measurement noise.

Type:

float | None

gene_ids

Optional gene name list. When omitted defaults to gene_{i}.

Type:

Sequence[str] | None

initial_state_probs

Optional categorical distribution over initial states. Defaults to uniform.

Type:

Sequence[float] | None

num_cells

Initial number of cells to simulate. The final row count may be larger when proliferation_model is configured.

Type:

int

t_final

Duration of the simulation window.

Type:

float

dt

Fixed time step for stochastic U/S, transition and division updates.

Type:

float

rng_seed

Optional integer seed for reproducible simulations.

Type:

int | None

baseline_expression: float
decay_rate: float
dispersion: float | None
dt: float
gene_ids: Sequence[str] | None
property gene_names: ndarray

Return gene identifiers as a NumPy array.

property initial_state_distribution: ndarray

Return the cached initial state distribution.

initial_state_probs: Sequence[float] | None
marker_expression: float
marker_overlap: int | Mapping[tuple[int, ...], int]
marker_reuse_cap: int
markers_per_state: int
num_cells: int
num_genes: int
num_states: int
proliferation_model: Callable[[Any], tuple[ndarray, ndarray]] | None
resolve_state_expression(rng: Generator) → ndarray[source]

Return a state-by-gene steady-state expression matrix.

resolve_transition_rates() → ndarray | Callable[[Any], ndarray][source]

Return the configured transition rates.

rng_seed: int | None
splicing_rate: float
state_expression: ndarray | None
t_final: float
to_metadata() → Dict[str, Any][source]

Convert parameters into a JSON-serialisable dictionary.

transition_rates: ndarray | Callable[[Any], ndarray] | None

Simulation engine

class markovmodus.simulation.Simulation(params: SimulationParameters)[source]

Bases: object

Mutable engine implementing fixed-step latent, U/S and division dynamics.

run() → Simulation[source]

Advance the simulation to params.t_final and return self.

For every step, dynamic transition and proliferation callbacks are evaluated from the start-of-step SimulationState. Existing cells update U/S counts, division events are sampled, non-dividing cells sample ordinary latent transitions and dividing cells are replaced by two daughters sampled from the proliferation fate probabilities.

property state: SimulationState

Return a read-only view of the current simulation state.

to_output() → SimulationOutput[source]

Convert the current simulation state into a result container.

class markovmodus.simulation.SimulationOutput(parameters: SimulationParameters, transition_rates: ndarray | None, transition_rate_mode: str, state_expression: ndarray, states: ndarray, unspliced: ndarray, spliced: ndarray, birth_parent: ndarray, birth_time: ndarray, generation: ndarray, last_division_time: ndarray, timepoint: float)[source]

Bases: object

Final simulation result.

unspliced and spliced contain final raw count matrices. birth_parent and birth_time describe appended daughter-row creation, while generation and last_division_time describe division history for both reused and appended daughter rows.

as_arrays() → Tuple[ndarray, ndarray][source]

Return unspliced and spliced matrices for convenience.

birth_parent: ndarray
birth_time: ndarray
generation: ndarray
last_division_time: ndarray
parameters: SimulationParameters
spliced: ndarray
state_expression: ndarray
states: ndarray
timepoint: float
transition_rate_mode: str
transition_rates: ndarray | None
unspliced: ndarray
class markovmodus.simulation.SimulationState(time: float, cell_states: ndarray, unspliced: ndarray, spliced: ndarray, birth_parent: ndarray, birth_time: ndarray, generation: ndarray, last_division_time: ndarray)[source]

Bases: object

Read-only start-of-step population view exposed to dynamic callbacks.

transition_rates and proliferation_model callables receive this object before the current time step updates U/S counts, latent states or divisions. The arrays cover all cells that exist at that time; cells appended by division become visible to callbacks in the next time step.

birth_parent: ndarray
birth_time: ndarray
cell_states: ndarray
generation: ndarray
last_division_time: ndarray
spliced: ndarray
time: float
unspliced: ndarray
markovmodus.simulation.simulate_population(params: SimulationParameters) → SimulationOutput[source]

Run a fixed-step Markov-modulated U/S simulation for a population of cells.

Parameters:

params – Fully configured SimulationParameters instance.

Returns:

Final counts, latent states and lineage metadata for downstream conversion to tabular or AnnData formats.

Return type:

SimulationOutput

Input/output

markovmodus.io.simulation_to_anndata(output: SimulationOutput) → AnnData[source]

Convert a simulation result into an AnnData object.

X contains raw spliced counts for single-cell tooling conventions. Raw paired U/S counts are also stored in layers["unspliced"] and layers["spliced"].

markovmodus.io.simulation_to_dataframe(output: SimulationOutput) → DataFrame[source]

Convert a simulation result into a wide cell-by-feature pandas DataFrame.

markovmodus.io.write_output(output: SimulationOutput, path: Path, *, file_format: Literal['csv', 'parquet', 'h5ad'] | None = None) → Path[source]

Persist a simulation result to disk.

Parameters:
  • output – Simulation result produced by markovmodus.simulation.simulate_population().

  • path – Destination path. The suffix is used to infer the format unless file_format is provided.

  • file_format – Optional explicit format override. Supported values: csv, parquet, h5ad.

Returns:

The path that was written (useful when the underlying library adds suffixes).

Return type:

Path

High-level API

markovmodus.api.simulate_dataset(params: SimulationParameters, *, output: Literal['anndata', 'dataframe', 'both'] = 'anndata', save_path: str | Path | None = None, file_format: Literal['csv', 'parquet', 'h5ad'] | None = None) → ReturnType[source]

Run a simulation and return the requested representation.

The default return type is AnnData with raw spliced counts in X and raw paired U/S counts in layers["unspliced"] and layers["spliced"]. Set output="dataframe" for a wide pandas table or output="both" to receive both views.

Parameters:
  • params – Configuration for the simulator.

  • output – Requested return type. "both" returns (AnnData, DataFrame).

  • save_path – Optional path to persist the generated dataset. The extension selects the storage format unless file_format is provided.

  • file_format – Optional format specifier overriding the suffix of save_path.