1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
//! A library for analysis of Boolean networks. As of now, the library supports:
//! - Regulatory graphs with monotonicity and observability constraints.
//! - Boolean networks, possibly with partially unknown and parametrised update functions.
//! - Full SBML-qual support for import/export as well as custom string format `.aeon`.
//! - Fully symbolic asynchronous state-space generator using BDDs (great overall performance).
//! - Semi-symbolic state-space generator, using BDDs used only for the network parameters
//! (allows state-level parallelism for smaller networks).
//!
//! For a quick introduction to Boolean networks and their symbolic manipulation, you can
//! check out our [tutorial module](./tutorial/index.html).
//!
#[macro_use]
extern crate lazy_static;
use regex::Regex;
use std::collections::HashMap;
use std::iter::Map;
use std::ops::Range;
pub mod async_graph;
pub mod bdd_params;
pub mod biodivine_std;
pub mod sbml;
pub mod symbolic_async_graph;
pub mod tutorial;
/// **(internal)** Implements `.aeon` parser for `BooleanNetwork` and `RegulatoryGraph` objects.
mod _aeon_parser;
/// **(internal)** Utility methods for `BinaryOp`.
mod _impl_binary_op;
/// **(internal)** Utility methods for `BooleanNetwork`.
mod _impl_boolean_network;
/// **(internal)** `BooleanNetwork` to `.aeon` string.
mod _impl_boolean_network_display;
/// **(internal)** Implements experimental `.bnet` parser for `BooleanNetwork`.
mod _impl_boolean_network_from_bnet;
/// **(internal)** Implements an experimental `.bnet` writer for `BooleanNetwork`.
mod _impl_boolean_network_to_bnet;
/// **(internal)** Utility methods for `FnUpdate`.
mod _impl_fn_update;
/// **(internal)** Utility methods for `Parameter`.
mod _impl_parameter;
/// **(internal)** Utility methods for `ParameterId`.
mod _impl_parameter_id;
/// **(internal)** Utility methods for `Regulation`.
mod _impl_regulation;
/// **(internal)** Utility methods for `RegulatoryGraph`.
mod _impl_regulatory_graph;
/// **(internal)** `RegulatoryGraph` to `.aeon` string.
mod _impl_regulatory_graph_display;
/// **(internal)** Equivalence relation for `RegulatoryGraph`.
mod _impl_regulatory_graph_eq;
/// **(internal)** Export of `RegulatoryGraph` into a `.dot` format.
mod _impl_regulatory_graph_to_dot;
/// **(internal)** Utility methods for `Variable`.
mod _impl_variable;
/// **(internal)** Utility methods for `VariableId`.
mod _impl_variable_id;
/// **(internal)** A regex string of an identifier which we currently allow to appear
/// as a variable or parameter name.
const ID_REGEX_STR: &str = r"[a-zA-Z0-9_]+";
lazy_static! {
/// A regular expression that matches the identifiers allowed as names of
/// Boolean parameters or variables.
static ref ID_REGEX: Regex = Regex::new(ID_REGEX_STR).unwrap();
}
/// A type-safe index of a `Variable` inside a `RegulatoryGraph` (or a `BooleanNetwork`).
///
/// If needed, it can be converted into `usize` for serialisation and safely read
/// again by providing the original `RegulatoryGraph` as context
/// to the `VariableId::try_from_usize`.
///
/// **Warning:** Do not mix type-safe indices between different networks/graphs!
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct VariableId(usize);
/// A type-safe index of a `Parameter` inside a `BooleanNetwork`.
///
/// If needed, it can be converted into `usize` for serialisation and safely read
/// again by providing the original `BooleanNetwork` as context
/// to the `ParameterId::try_from_usize`.
///
/// **Warning:** Do not mix type-safe indices between different networks!
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ParameterId(usize);
/// Possible monotonous effects of a `Regulation` in a `RegulatoryGraph`.
///
/// Activation means positive and inhibition means negative monotonicity.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Monotonicity {
Activation,
Inhibition,
}
/// A Boolean variable of a `RegulatoryGraph` (or a `BooleanNetwork`) with a given `name`.
///
/// `Variable` can be only created by and borrowed from a `RegulatoryGraph`.
/// It has no public constructor.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Variable {
name: String,
}
/// An explicit parameter of a `BooleanNetwork`; an uninterpreted Boolean function with a given
/// `name` and `arity`.
///
/// `Parameter` can be only created by and borrowed form the `BooleanNetwork` itself.
/// It has no public constructor.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Parameter {
name: String,
arity: u32,
}
/// Describes an interaction between two `Variables` in a `RegulatoryGraph`
/// (or a `BooleanNetwork`).
///
/// Every regulation can be *monotonous*, and can be set as *observable*:
///
/// - Monotonicity is either *positive* or *negative* and signifies that the influence of the
/// `regulator` on the `target` has to *increase* or *decrease* the `target` value respectively.
/// - If observability is set to `true`, the `regulator` *must* have influence on the outcome
/// of the `target` update function in *some* context. If set to false, this is not enforced
/// (i.e. the `regulator` *can* have an influence on the `target`, but it is not required).
///
/// Regulations can be represented as strings in the
/// form `"regulator_name 'relationship' target_name"`. The 'relationship' starts with `-`, which
/// is followed by `>` for activation (positive monotonicity), `|` for inhibition (negative
/// monotonicity) or `?` for unspecified monotonicity. Finally, an additional `?` at the end
/// of 'relationship' signifies a non-observable regulation. Together, this gives the
/// following options: `->, ->?, -|, -|?, -?, -??`.
///
/// Regulations cannot be created directly, they are only borrowed from a `RegulatoryGraph`
/// or a `BooleanNetwork`.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Regulation {
regulator: VariableId,
target: VariableId,
observable: bool,
monotonicity: Option<Monotonicity>,
}
/// A directed graph representing relationships between a collection of Boolean variables
/// using `Regulations`.
///
/// It can be explored using `regulators`, `targets`, `transitive_regulators`, or
/// `transitive_targets` (for example to determine if two variables depend on each other).
/// We can also compute the SCCs of this graph.
///
/// A regulatory graph can be described using a custom string format. In this format,
/// each line represents a regulation or a comment (starting with `#`).
///
/// Regulations can be represented as strings in the form of
/// `"regulator_name 'relationship' target_name"`. The 'relationship' is one of the arrow strings
/// `->, ->?, -|, -|?, -?, -??`. Here, `>` means activation, `|` is inhibition and `?` is
/// unspecified monotonicity. The last question mark signifies observability — if it is present,
/// the regulation is not necessarily observable. See `Regulation` and tutorial module for a more
/// detailed explanation.
///
/// Example of a `RegulatoryGraph`:
///
/// ```rg
/// # Regulators of a
/// a ->? a
/// b -|? a
///
/// # Regulators of b
/// a -> b
/// b -| b
/// ```
#[derive(Clone, Debug)]
pub struct RegulatoryGraph {
variables: Vec<Variable>,
regulations: Vec<Regulation>,
variable_to_index: HashMap<String, VariableId>,
}
/// Possible binary Boolean operators that can appear in `FnUpdate`.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum BinaryOp {
And,
Or,
Xor,
Iff,
Imp,
}
/// A Boolean update function formula which references
/// `Variables` and `Parameters` of a `BooleanNetwork`.
///
/// An update function specifies the evolution rules for one specific `Variable` of a
/// `BooleanNetwork`. The arguments used in the function must be the same as specified
/// by the `RegulatoryGraph` of the network.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum FnUpdate {
/// A true/false constant.
Const(bool),
/// References a network variable.
Var(VariableId),
/// References a network parameter (uninterpreted function).
///
/// The variable list are the arguments of the function invocation.
Param(ParameterId, Vec<VariableId>),
/// Negation.
Not(Box<FnUpdate>),
/// Binary boolean operation.
Binary(BinaryOp, Box<FnUpdate>, Box<FnUpdate>),
}
/// A Boolean network, possibly parametrised with uninterpreted Boolean functions.
///
/// The structure of the network is based on an underlying `RegulatoryGraph`. However,
/// compared to a `RegulatoryGraph`, `BooleanNetwork` can have a specific update function
/// given for each variable.
///
/// If the function is not specified (so called *implicit parametrisation*), all admissible
/// Boolean functions are considered in its place. A function can be also only partially
/// specified by using declared *explicit parameters*. These are uninterpreted but named Boolean
/// functions, such that, again, all admissible instantiations of these functions are considered.
/// See crate tutorial to learn more.
///
/// ### Boolean network equivalence
///
/// Please keep in mind that we consider two networks to be equivalent when they share a regulatory
/// graph, and when they have (syntactically) the same update functions and parameters. We do not
/// perform any semantic checks for whether the update functions are functionally equivalent.
///
/// Also keep in mind that the *ordering* of variables and parameters must be shared by equivalent
/// networks. This is because we want to preserve the property that `VariableId` and `ParameterId`
/// objects are interchangeable as log as networks are equivalent.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BooleanNetwork {
graph: RegulatoryGraph,
parameters: Vec<Parameter>,
update_functions: Vec<Option<FnUpdate>>,
parameter_to_index: HashMap<String, ParameterId>,
}
/// An iterator over all `VariableIds` of a `RegulatoryGraph` (or a `BooleanNetwork`).
pub type VariableIdIterator = Map<Range<usize>, fn(usize) -> VariableId>;
/// An iterator over all `ParameterIds` of a `BooleanNetwork`.
pub type ParameterIdIterator = Map<Range<usize>, fn(usize) -> ParameterId>;
/// An iterator over all `Regulations` of a `RegulatoryGraph`.
pub type RegulationIterator<'a> = std::slice::Iter<'a, Regulation>;