Overview#
BoNesis takes two inputs:
a domain of Boolean networks (BNs),
a set of Boolean dynamical properties,
and can then enumerate the BNs from the domain that verify the given properties.
The synthesis task is conducted from a BoNesis
object, that can be instantiated
as follows:
bo = bonesis.BoNesis(dom, data)
where dom
is an object representing the Domain of Boolean networks, and data
is a dict
-like object defining named observations, that are (possibly
partial) mappings from network components to Boolean values.
Dynamical properties are then specified using a specific declarative language, whose predicate are available as BoNesis
methods.
Input#
Domain of Boolean networks#
- Single Boolean network
From
.bnet
files (see example below),colomoto.minibn.BooleanNetwork
, or `mpbn.MPBooleanNetwork objects.dom = bonesis.BooleanNetwork("model.bnet")
Useful for reprogramming prediction and model-checking. There are no restriction on the type of Boolean network (can be non-monotone).
- Explicit ensemble of Boolean networks:
Instantiated with
bonesis.BooleanNetworkEnsemble
with a list ofbonesis.BooleanNetwork
ormpbn.MPBooleanNetwork
objects.dom = bonesis.BooleanNetworkEnsemble([bn1, bn2, bn3])
Can also be constructed from a zipfile: in that case, all the files ending with
.bnet
will be loaded as compoundbonesis.BooleanNetwork
objects:dom = bonesis.BooleanNetworkEnsemble.from_zip("models.zip")
There are no restriction on the type of Boolean network (can be non-monotone).
- Influence graph (GRN)
Implicit domain of any locally-monotone Boolean network whose influence graph is a subgraph of the given (partially) signed directed graph. The influence graph is instantiated with a
bonesis.InfluenceGraph
class which inherits fromnetworkx.MutiDiGraph
. The sign of edges must be specified with a"sign"
data attribute. If the sign is"?"
(or"ukn"
), then BoNesis will consider any possible sign.edges = [("a", "b", {"sign": 1}), ("b", "a", {"sign": -1})] dom = bonesis.InfluenceGraph(edges)
Positive sign can be indicated using values
1
,"+"
,"+1"
"->"
; negative sign can be indicated using values0
,"-"
,"-1"
"-|"
; unknown sign can be indicated using values"?"
,"ukn"
,"unspecified"
.Options.
exact
(defaultFalse
): WhenFalse
, considers Boolean networks whose influence graph is a subgraph (not all regulations have to be used). WhenTrue
, considers only Boolean networks having the exact same influence graph; this is always unsatisfiable in presence of unknown sign. When"unsigned"
, it behaves likeTrue
except that unknown signs are ignored.allow_skipping_nodes
(defaultFalse
). IfTrue
, allow to BoNesis to ignore nodes of the graph. No Boolean function will be synthesized for them. This is intended to be use in conjunction with maximization statements on the number of nodes.canonic
(defaultTrue
): Ensures that an enumeration of distinct Boolean networks. This adds some complexity in the encoding. Setting toFalse
can help to addresslarge instances when enumeration of Boolean functions is not needed.maxclause
(defaultNone
): Maximum number of clauses to consider for each Boolean function to synthesize in disjunctive normal form. WhenNone
the maximum bound is automatically computed for each node. As it is exponential with the number of regulators, it is recommended to set to an integer for large instances (e.g.,maxclause=32
).
See tour tutorial for further examples.
The influence graph domain can also be loaded from specific file formats:
from CSV files:
dom = bonesis.InfluenceGraph.from_csv("grn.csv")
Options. By default, the field separator is comma (
sep=","
), source component is taken from first column (column_source=0
), target component from second column (column_target=1
) and sign value from second column (column_sign=2
). Moreover, a self-positive regulation will be added to components without regulators (unsource=True
). Other options are passed toInfluenceGraph
constructor.from SIF files:
dom = bonesis.InfluenceGraph.from_sif("grn.sif")
Options. By default, a self-positive regulation will be added to components without regulators (
unsource=True
). Other options are passed toInfluenceGraph
constructor.
Specific influence graphs can be constructed as follows:
complete graph:
dom = bonesis.InfluenceGraph.complete(nodes)
where
nodes
is the list of nodes of the complete graph (seenetworkx.complete_graph
). Options. By default, self-loops are added on each node (loops=True
), and sign is unspecified (sign=0
). Other options are passed toInfluenceGraph
constructor.
Current limitation: locally-monotone Boolean networks.
- Partially-specified Boolean network (AEON)
From
.aeon
files in AEON Format orbiodivine_aean.BooleanNetwork
object.dom = bonesis.aeon.AEONDomain.from_file("partial-bn.aeon")
In addition to enforcing completely or partially the Boolean functions of components, the AEON format enables a fine-grained specification of mandatory and optional influences, as well as having unknown signs.
Current limitation: functions specified in AEON can be non-monotone, but unspecified functions will be assumed to be monotone.
Named observations [optional]#
In addition to the mandatory domain, the BoNesis
constructor accepts a second optional
dict
-like object associating names to Boolean observations over network components,
also represented with a dict
-like object.
The name can then be used as argument to the obs
object.
An observation can be partial (it does not have to assocate a Boolean value for each component), and it can refer to components that are not referenced in the domain (in that case, they will be ignored).
data = {
"init": {"a": 1, "b": 0, "c": 1},
"phenotype1": {"b": 1}
}
bo = bonesis.BoNesis(dom, data)
~bo.obs("init") >= ~bo.obs("phenotype1")
Dynamical properties#
The properties that the Boolean network must satisfes are specified using
predicates that can be declared using the language and methods of the BoNesis
object. See Declarative language for dynamical properties.
Optimization statements#
It is possible to restrict the solutions to optimal ones, according to an ordered list of objectives. See implemented .
# build a domain while allowing to ignore any number of node
dom = bonesis.InfluenceGraph(..., allow_skipping_nodes=True)
bo = bonesis.BoNesis(dom, data)
...
# consider only solutions accounting for the maximum possible number of nodes
bo.maximize_nodes()
Outputs#
The inputs defined above delineate a set of constraints that must hold alltogether. Generally, the constraints involve choices (free variables), such as the choice of Boolean functions in the defined domain, whenever it is not a single Boolean network, and the choice of state of components in configurations tied with partial observations.
BoNeis gives access to the solutions with views. A view specifies which objects are to be enumarated from the solution space, and returns an iterator other them. Views support a number of options, including:
solutions
with value either"all"
(default),"subset-minimal"
, or"subset-maximal"
: enable to focus only on most sparse/dense solutions. Precise meaning depend on the object being enumerated.limit
(default0
): maximum number of solutions to extract;0
means all.progress
: atqdm
-like object which will be notified after each iteration.
View classes are defined in the module
bonesis.views
. They take a BoNesis object as first argument.
For convenience, most usual views are provided as methods of the BoNesis object.
Boolean networks#
boolean_networks()
: basic enumeration#
The view bo.boolean_networks()
returns an iterator over the Boolean networks
of the given domaine that verify the specified properties.
Boolean networks are returned as mpbn.MPBooleanNetwork
objects, which are dict
-like objects associating nodes to a Boolean function in disjunctive normal form.
Examples of usage:
tabular view of the results, using
pandas
:view = bo.boolean_networks() import pandas as pd solutions = pd.DataFrame(view)
export to individual model files:
for i, f in enumerate(bo.boolean_networks(limit=5)): f.save(f"solution{i}.bnet")
diverse_boolean_networks()
: sampling with diversity#
When facing numerous solutions, one often observe that the basic
enumeration of a limited number of Boolean networks results in very lookalike
networks.
One can circumvent this issue by employing the bo.diverse_boolean_networks()
view which, after each solution, will attempt to force the solver to browse
distant solutions.
Note that the enumeration speed can be largely reduced by this process.
Projections#
To better understand the composition of the different solutions, one can project the solutions on each node: given a node A, it enumerates all the Boolean functions for A that are used in at least one full solution.
The projected solutions can be accessed from the following object:
projs = bo.local_functions()
The projs
object as as_dict
method which offers direct access to all the projected solutions. By default, it will enumerate the Boolean functions for each node. The method “count” instead returns the number of solutions per node. There is also a keys
parameter to specify a subset of nodes for the computation.
counts = projs.as_dict(method="count")
counts
Note that the projected solutions gives an over-approximation of the full set of solutions: the full set of solutions is, in general, a strict subset of the cartesian product (see Feature tour for a concrete example).
Access to the solutions of a specific node can be done as follows:
with projs.view("Tuj1") as view:
Tuj1_functions = [f for f in view]
Finally, projs
has a as_dataframe
method for pretty display of the projected solutions using pandas
. The option keys
enables to specify a subset of nodes to consider.
table = projs.as_dataframe()
Influence graphs#
The view bo.influence_graphs()
returns an iterator over the distinct influence
graphs of satisfying Boolean networks.
This is an efficient approach to capture the space of solutions whenever there
are too many possible Boolean network.
Influence graphs are returned as networkx.DiGraph
objects, with sign and label stored as "sign"
and "label"
attributes, respectively.
The option solution="subset-minimal"
will return all the influence graphs which are minimal by signed-edge inclusion. Thus, any satisfying Boolean network employs necessarily all the influences of at least one of the returned graphs.
Nodes#
bonesis.NonConstantNodesView(bo)
View over the nodes that jointly received a non-constant Boolean function. A typical usage is with option
solutions="subset-minimal"
or withbo.maximize_constants()
.bonesis.NonStrongConstantNodesView(bo)
View over the nodes that jointly received a non-constant Boolean function or differ of state in at least two configurations. A typical usage is with option
solutions="subset-minimal"
or withbo.maximize_strong_constants()
.bonesis.NodesView(bo)
Iterator over the sets of nodes involved in the solutions. Think of it as the influence graph view, but with edges ignored. This is useful in conjunction with domains having option
allow_skipping_nodes=True
.
Assignments#
BoNesis Declarative language for dynamical properties enables to define objects with only a partial
specification.
This is the case of configurations (cfg
objects), which
can be either free or bound to a partial assignment of the state of components
(observations) and variables (Some
objects).
Each of these object have an assignment()
method, which is a view other their
satisfying complete value assignment.
In the case of Some
object, the option solution
defaults to
"subset-minimal"
.
This is mostly used with a single Boolean network as the domain. Otherwsie, keep in my that an assignment is returned if there exists at least one Boolean network of the domain with which it is a satisfying assignment.
Examples
Satisfying assignments of a configuration:
# fixed point matching with a partial observation x = bo.fixed(~bo.obs("final")) for val in x.assignments(): ...
Satisfying assignments of a mutant:
x = ~bo.obs("init") y = bo.fixed(~bo.obs("final")) # x is a fixed point in the wild type... bo.fixed(x) M = bo.Some(max_k=3) with bo.mutant(M): # x can reach y in the mutant M x >= y for val in M.assignment(): ...
The extra
option#
The views provide an efficient iteration over specified object types by the means of projection techniques implemeted in the clingo solver, and each iteration will return a distinct object.
The extra
option of views enables to extract, for each solution, a
corresponding satisfying assignment of other objects of specified types.
The option supports values among "configurations"
, "boolean-network"
, "somes"
, or a tuple of them.
Examples
Extract a possible complete assignment of configurations for each returned Boolean network:
# Get up to 5 distinct Boolean networks together with an instance of # satisfying assignment of configurations. for f, cfgs in f.boolean_networks(limit=5, extra="configurations"): ...
Extract a Boolean network and configuration assignments alongside distinct influence graphs:
# Get all distinct subset-minimal influence graphs, and for each of them one # instance of Boolean networks and configuration assignements for ig, f, cfgs in f.influence_graphs(solutions="subset-minimal", extra=("boolean-network", "configurations")): ...