iocrn
RL4CRN.iocrns.iocrn
Input-Output Chemical Reaction Network (IOCRN) representation.
This module defines IOCRN, a representation of an input-output chemical
reaction network with utilities for:
- building and compiling a CRN from a list of reactions,
- mapping between symbolic labels (species/inputs) and numeric indices,
- simulating transient responses (ODE solvers and SSA),
- plotting simulation results,
- exporting the network to a DSL format used by external simulators,
- (optionally) solving dynamics using CVODE via
sksundae.
This modules provides utilities for deterministic simulations of CRNs, while it relies on an external package for stochastic simulation (SSA).
Caching
Simulation results are cached in last_task_info to avoid recomputation
if the same task is requested repeatedly. Adding reactions or calling
reset clears cached task info.
Solver support
'LSODA'usesscipy.integrate.solve_ivp.'CVODE'usessksundae.cvode.CVODE.
SSA support
Stochastic simulation is supported via an external package
StochasticSimulationsNew plus project utilities in :mod:RL4CRN.utils.stochastic.
If the external package is missing, SSA methods raise an ImportError.
IOCRN
Input-Output Chemical Reaction Network.
An IOCRN consists of
- a list of reactions,
- a set of output species labels,
- an implied set of species and inputs gathered from reactions,
- dynamics defined by stoichiometry and propensities.
The network must be compiled after construction or modification to
build internal indices and matrices used for simulation.
| PARAMETER | DESCRIPTION |
|---|---|
reactions
|
List of
and attributes such as:
|
output_labels
|
List of species labels treated as outputs.
|
solver
|
ODE solver identifier. Supported values:
DEFAULT:
|
atol
|
Absolute tolerance for ODE integration.
DEFAULT:
|
rtol
|
Relative tolerance for ODE integration.
DEFAULT:
|
| ATTRIBUTE | DESCRIPTION |
|---|---|
reactions |
List of reaction objects.
|
output_labels |
List of output species labels.
|
num_outputs |
Number of outputs.
|
num_unknown_params |
Total number of unknown parameters across reactions.
|
last_task_info |
Dictionary caching results/metadata of the last evaluated task (e.g., transient response).
|
solver |
Selected solver backend name.
|
atol |
Absolute tolerance.
|
rtol |
Relative tolerance.
|
__init__(reactions, output_labels, solver='CVODE', atol=1e-06, rtol=0.001)
Initialize the IOCRN.
Important
After initialization, call compile to create internal
representations (species/input indices, stoichiometry matrix, etc.).
| PARAMETER | DESCRIPTION |
|---|---|
reactions
|
List of reaction objects.
|
output_labels
|
List of labels for output species.
|
solver
|
ODE solver backend (
DEFAULT:
|
atol
|
Absolute tolerance passed to the solver.
DEFAULT:
|
rtol
|
Relative tolerance passed to the solver.
DEFAULT:
|
clone()
Return a deep copy of the IOCRN.
reset()
Clear cached task information.
This does not modify reactions or parameters; it only clears the cached
last_task_info.
add_reaction(reaction)
Add a reaction and recompile.
Adding a reaction clears cached task info and updates internal
representations by calling compile.
| PARAMETER | DESCRIPTION |
|---|---|
reaction
|
Reaction object to append to the network.
|
retrieve_species()
Collect species labels from reactions and create index mappings.
Side Effects
Sets:
species_labels: sorted list of all species labelsspecies_idx_dict: mapping label -> index
retrieve_input()
Collect input labels from reactions and create index mappings.
Side Effects
Sets:
input_labels: sorted list of all input labelsnum_inputs: number of inputsinput_idx_dict: mapping label -> index
species_label_to_idx(labels)
Map species labels to indices.
| PARAMETER | DESCRIPTION |
|---|---|
labels
|
Species label (str) or list of species labels.
|
| RETURNS | DESCRIPTION |
|---|---|
|
If |
input_label_to_idx(labels)
Map input labels to indices.
| PARAMETER | DESCRIPTION |
|---|---|
labels
|
Input label (str) or list of input labels. Elements may be
|
| RETURNS | DESCRIPTION |
|---|---|
|
If |
set_library_context(reaction_library)
Set a reaction-library context for all reactions.
This is required for some topology comparisons and signatures.
| PARAMETER | DESCRIPTION |
|---|---|
reaction_library
|
Library object passed to
|
Side Effects
Sets self.reaction_library.
get_bool_signature()
Return a boolean signature of present reactions relative to a library.
| RETURNS | DESCRIPTION |
|---|---|
|
Boolean numpy array of length |
| RAISES | DESCRIPTION |
|---|---|
AttributeError
|
If |
is_topologically_equal(other_iocrn)
Check topology equality against another IOCRN.
Assumes both IOCRNs share the same reaction library context.
| PARAMETER | DESCRIPTION |
|---|---|
other_iocrn
|
Another
|
| RETURNS | DESCRIPTION |
|---|---|
|
True if their boolean signatures match, else False. |
get_stoichiometry_matrix()
Construct the stoichiometry matrix \(S\).
| RETURNS | DESCRIPTION |
|---|---|
|
Numpy array |
gather_reaction_IDs()
Return reaction IDs for all reactions in the network.
gather_reaction_params()
Return a list of parameter vectors for all reactions.
compile()
Compile internal IOCRN representations.
This method
- retrieves and indexes species and inputs,
- computes
output_idxfor output species, - builds the stoichiometry matrix
S, - calls
reaction.set_crn_context(self)on each reaction.
Call this after
- initialization,
- adding/removing reactions,
- changing reaction definitions that affect involved species/inputs.
Important
This method should be called after adding all reactions and before simulating the IOCRN.
__str__()
Return a readable string representation of the IOCRN.
Includes
- inputs
- species
- output species
- reactions (sorted by reaction ID if available)
to_reaction_file()
Export the IOCRN to a custom DSL reaction-file format.
The exported text contains
- An
input ...;section (if inputs are present), - A
species ... = 0;section (excluding emptyset/∅), - A reactions section where each reaction contributes one or more
lines via
reaction.to_reaction_format().
| RETURNS | DESCRIPTION |
|---|---|
|
The DSL text as a single string. |
propensity_function(x, u)
Compute propensities \(a(x,u)\) for all reactions.
| PARAMETER | DESCRIPTION |
|---|---|
x
|
Species state vector (array-like of shape
|
u
|
Input vector (array-like of shape
|
| RETURNS | DESCRIPTION |
|---|---|
|
Numpy array of propensities of shape |
rate_function(t, x, u)
Compute time-derivative \(\dot{x} = S a(x,u)\).
| PARAMETER | DESCRIPTION |
|---|---|
t
|
Time (unused for autonomous dynamics, but accepted by solver APIs).
|
x
|
Species state vector of shape
|
u
|
Input vector of shape
|
| RETURNS | DESCRIPTION |
|---|---|
|
Numpy array of shape |
dose_response(u_dose, u_list, initial_guess)
Computes the dose response of the IOCRN given a list of input doses, a list of input scenarios, and an initial guess for the concentrations. If the CRN dose response has been simulated and stored before, it returns the stored results instead of recomputing them. The results are stored in the last_task_info dictionary for future reference. Arguments: - u_dose: numpy array of shape (num_doses,) representing the input doses to the IOCRN. - u_list: A list of numpy arrays, each of shape (p,) representing the constant inputs to the IOCRN for each scenario. The first element of each input array corresponds to the dose, and the rest correspond to other inputs. - initial_guess: numpy array of shape (n,) representing the initial guess for the concentrations of the species. Returns a tupple containing: - x_list: A list of numpy arrays of shape (n, num_doses) representing the state for each input scenario. - y_list: A list of numpy arrays of shape (q, num_doses) representing the output for each input scenario.
transient_response_SSA(u_list, x0_list, time_horizon, n_trajectories=100, max_threads=10000, max_value=1000000.0)
Compute stochastic transient responses via SSA (mean ± std).
This method runs a stochastic simulation algorithm (SSA) backend for the
current IOCRN by first exporting the network to the project DSL
(to_reaction_file) and then invoking the external SSA engine.
For each pair (u, x0) in the Cartesian product u_list × x0_list, the
method performs n_trajectories independent SSA runs and returns the
empirical mean and standard deviation trajectories for all species and
outputs. Results are interpolated onto the requested time_horizon.
The results are cached in last_task_info with
type == 'transient response SSA'.
| PARAMETER | DESCRIPTION |
|---|---|
u_list
|
List of input vectors. Each element is array-like of shape
|
x0_list
|
List of initial condition vectors. Each element is array-like
of shape
|
time_horizon
|
1D array-like of time points at which to return
statistics. The SSA backend is sampled at a step
|
n_trajectories
|
Number of SSA trajectories per
DEFAULT:
|
max_threads
|
Maximum threads/parallelism hint for the SSA backend. (Currently not directly used in this method; kept for API compatibility / future backend control.)
DEFAULT:
|
max_value
|
Divergence threshold passed to the SSA measurement helper. Trajectories exceeding this value may be flagged as diverged.
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple
|
| RAISES | DESCRIPTION |
|---|---|
ImportError
|
If the external SSA package |
ValueError
|
If the network contains unknown parameters
( |
Notes
- This method assumes the SSA helper
RL4CRN.utils.stochastic.quick_measurement_SSAreturns a summary dataframe with columns compatible with the parsing logic in this implementation. last_task_infouses keys:'inputs','initial conditions','time_horizon','trajectories','trajectories_std','outputs','outputs_std','has_diverged'.
transient_response(u_list, x0_list, time_horizon, LARGE_NUMBER=10000.0)
Compute deterministic transient responses (ODE integration).
This method integrates the ODE dynamics:
for each pair (u, x0) in the Cartesian product u_list × x0_list,
where inputs u are treated as constant in time for each scenario.
Results are cached in last_task_info with
type == 'transient response'. If the cache already contains a transient
response, the stored results are returned immediately.
Numerical stability
If the integrator fails or the solution becomes unstable (detected by
an event when max(|x|) exceeds LARGE_NUMBER or becomes non-finite),
the remaining portion of the trajectory is filled with LARGE_NUMBER.
| PARAMETER | DESCRIPTION |
|---|---|
u_list
|
List of constant input vectors, each array-like of shape
|
x0_list
|
List of initial condition vectors, each array-like of shape
|
time_horizon
|
1D array-like of time points of shape
|
LARGE_NUMBER
|
Threshold used both as an instability detection bound and as a fill value when integration fails.
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
ValueError
|
If |
Notes
- For
'LSODA', integration is performed using SciPy'ssolve_ivp. - For
'CVODE', the method delegates tosolve_with_cvodeand interpolates the solver output ontotime_horizon.
transient_response_piecewise(u_nested_list, x0_list, nested_time_horizon, LARGE_NUMBER=10000.0, force=False)
Compute deterministic transient responses with piecewise-constant inputs.
This method generalizes transient_response to input sequences.
Each element of u_nested_list is a sequence of input vectors
[u_0, ..., u_{K-1}] applied consecutively over corresponding time
segments nested_time_horizon = [t_0, ..., t_{K-1}].
For each scenario (u_sequence, x0) in the Cartesian product
u_nested_list × x0_list, the method integrates the dynamics on each time
segment in order, using the final state of segment k as the initial
condition for segment k+1.
Instability handling
If any segment fails or terminates early due to instability, the
remainder of the trajectory (for that scenario) is filled with
LARGE_NUMBER.
Caching
Results are cached in last_task_info with
type == 'transient response' and returned if a matching cache is
detected (currently a heuristic check based on lengths).
| PARAMETER | DESCRIPTION |
|---|---|
u_nested_list
|
List of input sequences. Each entry is a list of input
vectors
|
x0_list
|
List of initial conditions, each array-like of shape
|
nested_time_horizon
|
List of 1D time grids
|
LARGE_NUMBER
|
Instability bound and fill value for failed segments.
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple |
|
|
|
|
|
|
|
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If any input sequence length does not match the number of time segments. |
ValueError
|
If |
ValueError
|
If |
plot_logic_response(*, u_list=None, target_fn=None, title='Truth table', figsize=(2.2, 1.2), silent=False)
Plot a truth-table style view of the CRN's logic behavior.
This expects the CRN to have cached a deterministic multi-scenario simulation in
self.last_task_info (e.g., produced by a reward function that calls
transient_response(...) and stores its results).
| PARAMETER | DESCRIPTION |
|---|---|
u_list
|
Optional list of input vectors used for the scenarios. If None, tries
to read
DEFAULT:
|
target_fn
|
Optional callable mapping u (np.ndarray) -> {0,1} (or bool).
If None, tries to read
DEFAULT:
|
title
|
Plot title.
DEFAULT:
|
figsize
|
Matplotlib figure size.
DEFAULT:
|
silent
|
If True, does not call plt.show().
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
(fig, ax) from plot_truth_table_transposed_nature. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If required cached information is missing. |
plot_transient_response(fig=None, axes=None, alpha=0.1, plot_cfg=None)
Plot cached deterministic transient response trajectories.
This method visualizes trajectories stored by a call that cached
last_task_info['type'] == 'transient response', typically produced by
transient_response(...) or transient_response_piecewise(...).
Paper-ready styling can be controlled through plot_cfg, which may override
default rcParams and common cosmetics (grid/spines/legend) while preserving
the original method API.
| PARAMETER | DESCRIPTION |
|---|---|
fig
|
Optional matplotlib Figure to draw into. If None and
DEFAULT:
|
axes
|
Optional axes list/array. If None and
DEFAULT:
|
alpha
|
Line transparency for overlaid trajectories (default: 0.1).
DEFAULT:
|
plot_cfg
|
Optional dict controlling paper-ready styling. Supported keys: - rc: dict of matplotlib rcParams overrides - figsize: tuple (w,h) for figure size - constrained_layout: bool - tight_layout: bool - grid: bool - grid_kwargs: dict passed to ax.grid(...) - despine: bool (hide top/right spines) - spine_lw: float - alpha: override alpha passed in args - lw: line width override - title/xlabel/ylabel: override strings (title can be per-axis via None) - legend: "auto" | True | False - legend_kwargs: dict passed to ax.legend(...) - save: dict like {"path": "...pdf", "dpi": 600}
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple[Figure, List[Axes]]: (fig, axes) where axes has length num_outputs. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no cached deterministic transient response is present. |
plot_transient_response_piecewise(fig=None, axes=None, alpha=1.0, input_color='red', shade_on=True, trj_color='green', pulse_lw=1.0, pulse_ls='--', gap=False, plot_cfg=None, is_main=True, normalize=False, y_label=None, legend_label=None)
Plot cached deterministic piecewise transient responses.
If is_main=False, this acts as a follower plotter:
- plots only trajectories
- uses the provided alpha
- skips pulse overlays, shading, titles, and styling extras
If normalize=True, all trajectories are divided by a single global peak
(max value across all cached conditions/scenarios/outputs in this object).
plot_phase_portrait(fig=None, axis=None, alpha=0.1, plot_cfg=None)
Plot a phase portrait from cached deterministic transient trajectories.
For two species, plots x1(t) vs x2(t). For three species, plots a 3D trajectory.
| PARAMETER | DESCRIPTION |
|---|---|
fig
|
Optional matplotlib Figure.
DEFAULT:
|
axis
|
Optional matplotlib Axis (2D or 3D).
DEFAULT:
|
alpha
|
Line transparency for overlaid trajectories.
DEFAULT:
|
plot_cfg
|
Optional dict controlling paper-ready styling. Supported keys are the same as in plot_transient_response.
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple[Figure, Axes]: (fig, axis). |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no cached deterministic transient response is present. |
ValueError
|
If num_species is not 2 or 3. |
plot_dose_response(fig=None, axes=None, alpha=0.5, plot_cfg=None)
Plot dose-response curves from cached simulation data.
Two cache modes are supported:
1) Dose-response cache: - last_task_info['type'] == 'dose response' - last_task_info['input doses'] : array-like - last_task_info['outputs'] : list of arrays shaped (q, n_doses) or similar
2) Transient-response-derived dose response: - last_task_info['type'] == 'transient response' - last_task_info['inputs'] : list of u vectors (assumes scalar dose is u[0]) - last_task_info['initial_conditions'] : list of x0 vectors - last_task_info['outputs'] : list of arrays shaped (q, T) for each (ic,u) scenario The method groups outputs by IC block and plots final-time output vs u[0].
Paper-ready styling can be controlled via plot_cfg.
| PARAMETER | DESCRIPTION |
|---|---|
fig
|
Optional matplotlib Figure.
DEFAULT:
|
axes
|
Optional axes list/array. If None, new axes are created (one per output).
DEFAULT:
|
alpha
|
Line transparency for curves (default: 0.5).
DEFAULT:
|
plot_cfg
|
Optional dict controlling paper-ready styling (see plot_transient_response).
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple[Figure, List[Axes]]: (fig, axes). |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If neither dose-response nor transient-response cache is present. |
KeyError
|
If required cache keys are missing. |
plot_frequency_content(fig=None, axes=None, alpha=0.1, t0=0.0, plot_cfg=None)
Plot normalized one-sided FFT magnitude spectra from cached transients.
For each cached trajectory: 1) keep samples with time >= t0, 2) subtract mean to remove DC component, 3) compute one-sided FFT magnitudes, 4) normalize each spectrum by its maximum, 5) overlay spectra across scenarios.
| PARAMETER | DESCRIPTION |
|---|---|
fig
|
Optional matplotlib Figure.
DEFAULT:
|
axes
|
Optional axes list/array. If None, new axes are created (one per output).
DEFAULT:
|
alpha
|
Line transparency for overlaid spectra.
DEFAULT:
|
t0
|
Time cutoff; only samples with time >= t0 are used.
DEFAULT:
|
plot_cfg
|
Optional dict controlling paper-ready styling (see plot_transient_response).
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple[Figure, List[Axes]]: (fig, axes). |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no cached deterministic transient response is present. |
ValueError
|
If insufficient points exist after t0. |
ValueError
|
If inferred sampling interval is non-positive. |
plot_SSA_transient_response(fig=None, axes=None, alpha=0.2, plot_cfg=None)
Plot cached SSA transient responses as mean ± std bands.
Expects stochastic cache produced by transient_response_SSA(...):
- last_task_info['type'] == 'transient response SSA'
- last_task_info['time_horizon'] : np.ndarray
- last_task_info['outputs'] : List[np.ndarray] mean trajectories (q, T)
- last_task_info['outputs_std'] : List[np.ndarray] std trajectories (q, T)
- optionally last_task_info['inputs'] : List[u] for labeling
| PARAMETER | DESCRIPTION |
|---|---|
fig
|
Optional matplotlib Figure.
DEFAULT:
|
axes
|
Optional axes list/array. If None, new axes are created (one per output).
DEFAULT:
|
alpha
|
Transparency for std shading (default: 0.2).
DEFAULT:
|
plot_cfg
|
Optional dict controlling paper-ready styling (see plot_transient_response).
Note: plot_cfg["alpha"] (if set) overrides the line alpha, while
the std-band alpha defaults to the method argument Additional supported key: - band_alpha: float to override std-band transparency
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Tuple[Figure, List[Axes]]: (fig, axes). |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no SSA cache is present. |
KeyError
|
If required cache keys are missing. |
solve_with_cvode(x0, time_horizon, u, nonneg_idx, stop_fn)
Integrate the IOCRN ODE using CVODE and return a solve_ivp-like solution.
This is an internal helper used when self.solver == 'CVODE'. It wraps the
sksundae.cvode.CVODE interface into an object that mimics SciPy's
solve_ivp result structure (fields .t, .y, .status, .message,
and .raw).
| PARAMETER | DESCRIPTION |
|---|---|
x0
|
Initial condition vector of shape
|
time_horizon
|
1D array of requested times at which the solver should
return values (similar to
|
u
|
Constant input vector of shape
|
nonneg_idx
|
Indices of state variables constrained to be nonnegative. If provided, CVODE inequality constraints are applied.
|
stop_fn
|
Event-like function
|
| RETURNS | DESCRIPTION |
|---|---|
|
A lightweight solution object with:
|
| RAISES | DESCRIPTION |
|---|---|
ImportError
|
If |