biodivine_aeon
AEON.py is a Python library for working with Boolean networks. It supports a wide range of features, including symbolic representation of network dynamics. More general information is available on GitHub.
To explore the library documentation, you can start with one of the core data classes:
RegulatoryGraph
, BooleanNetwork
and AsynchronousGraph
. Alternatively, to learn more about the available
algorithms, you may want to look at Attractors
, TrapSpaces
, FixedPoints
, Classification
,
or Control
.
1from typing import Literal, TypedDict, Mapping, Union, Optional 2 3# Notes on Python version updates: 4# - TODO: If we ever move to 3.10, we can start using `TypeAlias`. 5# - TODO: If we ever move to 3.10, we can start using `|` instead of `Union` (and stop using `Optional`). 6# - TODO: If we ever move to 3.11, we can start using `Generic` and `TypedDict` together. 7# - TODO: If we ever move to 3.12, we can start using `type` instead of `TypeAlias`. 8# - TODO: If we ever move to 3.12, we can start using special syntax for generics. 9 10# Counterintuitively, these two lines should actually reexport the native PyO3 module here. But it is a bit of a hack 11# which does not work super reliably. Refer to the PyO3 guide for how this should be handled if it stops working. 12import biodivine_aeon 13from .biodivine_aeon import * 14 15# Replace module-level documentation. 16__doc__ = biodivine_aeon.__doc__ 17 18# The "__all__" list allows us to control what items are exported from the module. It has to be built as a single 19# assignment, because the interpreter will cache its contents (i.e. subsequent updates are not taken into account). 20# We include all Python-only types that we have in this file, plus all classes from the native module as long as 21# they do not start with an underscore. We can also use this to influence the order in which items appear 22# in documentation. 23assert hasattr(biodivine_aeon, "__all__") 24__all__ = [ 25 'LOG_NOTHING', 26 'LOG_ESSENTIAL', 27 'LOG_VERBOSE', 28 'LOG_LEVEL', 29 'BddVariableType', 30 'VariableIdType', 31 'ParameterIdType', 32 'BoolType', 33 'SignType', 34 'BinaryOperator', 35 'TemporalBinaryOperator', 36 'TemporalUnaryOperator', 37 'HybridOperator', 38 'PhenotypeOscillation', 39 'BoolClauseType', 40 'BoolExpressionType', 41 'Regulation', 42 'IdRegulation', 43 'NamedRegulation', 44 ] + [x for x in biodivine_aeon.__all__ if not x.startswith("_")] 45 46LOG_NOTHING: Literal[0] = 0 47""" 48No progress messages are printed. 49""" 50LOG_ESSENTIAL: Literal[1] = 1 51""" 52Progress messages are printed only for operations of "non-trivial" complexity. 53""" 54LOG_VERBOSE: Literal[2] = 2 55""" 56All progress messages are printed. 57""" 58 59LOG_LEVEL: Literal[0, 1, 2] = biodivine_aeon.LOG_LEVEL 60""" 61A global variable which specifies what logging messages should be printed to the standard output. These are mainly 62used to communicate progress during long-running algorithms. I.e. they typically do not communicate any new 63errors or warnings, just a rough estimate of resources being used. Note that these messages introduce some overhead 64into every algorithm. While we try to reduce this overhead as much as possible, especially `LOG_VERBOSE` can have 65measurable impact in shorter computations. For longer computations, the overhead should tend towards zero. 66 67 - `LOG_NOTHING`: No logging messages are printed. 68 - `LOG_ESSENTIAL`: Logging messages are printed when resource 69 consumption exceeds what is considered "trivial" in the context of a particular algorithm. 70 - `LOG_VERBOSE`: Prints all progress messages. This setting is useful for in-depth comparisons between algorithms, 71 but can be overwhelming under normal circumstances. 72 73The default value is `LOG_NOTHING`. 74""" 75 76BddVariableType = Union[BddVariable, str] 77""" 78You can typically refer to a `Bdd` variable using its `BddVariable` ID object, 79or you can use a "raw" `str` name. However, using names instead of IDs in frequently 80running code incurs a performance penalty. 81""" 82 83VariableIdType = Union[VariableId, str] 84""" 85You can typically refer to a network variable using its `VariableId` typed index, 86or you can use a "raw" `str` name. However, using names instead of IDs in frequently 87running code incurs a performance penalty. 88""" 89 90ParameterIdType = Union[ParameterId, str] 91""" 92You can typically refer to a network parameter using its `ParameterId` typed index, 93or you can use a "raw" `str` name. However, using names instead of IDs in frequently 94running code incurs a performance penalty. 95""" 96 97BoolType = Union[bool, int] 98""" 99Most methods can also accept `0`/`1` wherever `False`/`True` would be typically required. 100 101 > Note that `typing.Literal` is not used here due to how it behaves when typechecking in mappings/collections. 102""" 103 104SignType = Union[bool, Literal["positive", "+", "negative", "-"]] 105""" 106Sign is used in the context of regulatory networks to indicate positive/negative interaction, 107but can be also used for more general graph concepts, like positive/negative cycle. 108""" 109 110BinaryOperator = Literal["and", "or", "imp", "iff", "xor"] 111""" 112Lists the supported Boolean binary operators. 113""" 114 115TemporalBinaryOperator = Literal["exist_until", "all_until", "exist_weak_until", "all_weak_until"] 116""" 117List of temporal binary operators supported by the HCTL model checker. 118""" 119 120TemporalUnaryOperator = Literal["exist_next", "all_next", "exist_future", "all_future", "exist_global", "all_global"] 121""" 122List of temporal unary operators supported by the HCTL model checker. 123""" 124 125HybridOperator = Literal["exists", "forall", "bind", "jump"] 126""" 127List of hybrid quantifiers supported by the HCTL model checker. 128""" 129 130PhenotypeOscillation = Literal["required", "allowed", "forbidden"] 131""" 132The possible modes of oscillation in a phenotype set: 133 - `required`: To satisfy the phenotype, an attractor must visit the phenotype set intermittently 134 (i.e. it cannot be proper subset). 135 - `forbidden`: To satisfy the phenotype, an attractor must fully reside in the phenotype set. 136 - `allowed`: To satisfy the phenotype, an attractor must intersect the phenotype set, but it does not matter whether 137 it is fully contained in it or simply visits it intermittently. 138""" 139 140BoolClauseType = Union[BddPartialValuation, BddValuation, Mapping[str, BoolType], Mapping[BddVariable, BoolType]] 141""" 142A Boolean clause represents a collection of literals. This can be either done through one of the valuation types, 143or through a regular dictionary. However, any representation other than `BddPartialValuation` incurs a performance 144penalty due to conversion. 145""" 146 147BoolExpressionType = Union[BooleanExpression, str] 148""" 149A `BooleanExpression` can be typically also substituted with its "raw" string representation. However, this 150requires the expression to be repeatedly parsed whenever used and is thus slower and more error prone. 151""" 152 153 154# IDT = TypeVar('IDT', covariant=True) 155# class Regulation(TypedDict, Generic[IDT]): 156# source: IDT 157# target: IDT 158# sign: Optional[SignType] 159# essential: BoolType 160# """ 161# A typed dictionary that stores data about a single regulation. Parametrized by an "identifier type" which 162# can be either `str` or `VariableId`. 163 164# Typically both `str` and `VariableId` are accepted as inputs, but only `VariableId` is provided as output. 165 166# For backwards compatibility purposes, the `sign` key is also equivalent to `monotonicity` and `essential` 167# is equivalent to `observable`. However, we do not include this in the type hints to discourage the 168# usage of these deprecated dictionary keys. 169# """ 170 171class IdRegulation(TypedDict): 172 source: VariableId 173 target: VariableId 174 sign: Optional[SignType] 175 essential: BoolType 176 """ 177 See `Regulation` type alias. 178 """ 179 180 181class NamedRegulation(TypedDict): 182 source: str 183 target: str 184 sign: Optional[SignType] 185 essential: BoolType 186 """ 187 See `Regulation` type alias. 188 """ 189 190 191Regulation = Union[IdRegulation, NamedRegulation] 192""" 193A typed dictionary that stores data about a single regulation. Parametrized by an "identifier type" which 194can be either `str` or `VariableId`. 195 196Typically both `str` and `VariableId` are accepted as inputs, but only `VariableId` is provided as output. 197 198For backwards compatibility purposes, the `sign` key is also equivalent to `monotonicity` and `essential` 199is equivalent to `observable`. However, we do not include this in the type hints to discourage the 200usage of these deprecated dictionary keys. 201 202 > For backwards compatibility, the type is currently not generic, but provided as two separate aliases. 203"""
No progress messages are printed.
Progress messages are printed only for operations of "non-trivial" complexity.
All progress messages are printed.
A global variable which specifies what logging messages should be printed to the standard output. These are mainly
used to communicate progress during long-running algorithms. I.e. they typically do not communicate any new
errors or warnings, just a rough estimate of resources being used. Note that these messages introduce some overhead
into every algorithm. While we try to reduce this overhead as much as possible, especially LOG_VERBOSE
can have
measurable impact in shorter computations. For longer computations, the overhead should tend towards zero.
LOG_NOTHING
: No logging messages are printed.LOG_ESSENTIAL
: Logging messages are printed when resource consumption exceeds what is considered "trivial" in the context of a particular algorithm.LOG_VERBOSE
: Prints all progress messages. This setting is useful for in-depth comparisons between algorithms, but can be overwhelming under normal circumstances.
The default value is LOG_NOTHING
.
You can typically refer to a Bdd
variable using its BddVariable
ID object,
or you can use a "raw" str
name. However, using names instead of IDs in frequently
running code incurs a performance penalty.
You can typically refer to a network variable using its VariableId
typed index,
or you can use a "raw" str
name. However, using names instead of IDs in frequently
running code incurs a performance penalty.
You can typically refer to a network parameter using its ParameterId
typed index,
or you can use a "raw" str
name. However, using names instead of IDs in frequently
running code incurs a performance penalty.
Most methods can also accept 0
/1
wherever False
/True
would be typically required.
Note that
typing.Literal
is not used here due to how it behaves when typechecking in mappings/collections.
Sign is used in the context of regulatory networks to indicate positive/negative interaction, but can be also used for more general graph concepts, like positive/negative cycle.
Lists the supported Boolean binary operators.
List of temporal binary operators supported by the HCTL model checker.
List of temporal unary operators supported by the HCTL model checker.
List of hybrid quantifiers supported by the HCTL model checker.
The possible modes of oscillation in a phenotype set:
required
: To satisfy the phenotype, an attractor must visit the phenotype set intermittently (i.e. it cannot be proper subset).forbidden
: To satisfy the phenotype, an attractor must fully reside in the phenotype set.allowed
: To satisfy the phenotype, an attractor must intersect the phenotype set, but it does not matter whether it is fully contained in it or simply visits it intermittently.
A Boolean clause represents a collection of literals. This can be either done through one of the valuation types,
or through a regular dictionary. However, any representation other than BddPartialValuation
incurs a performance
penalty due to conversion.
A BooleanExpression
can be typically also substituted with its "raw" string representation. However, this
requires the expression to be repeatedly parsed whenever used and is thus slower and more error prone.
A typed dictionary that stores data about a single regulation. Parametrized by an "identifier type" which
can be either str
or VariableId
.
Typically both str
and VariableId
are accepted as inputs, but only VariableId
is provided as output.
For backwards compatibility purposes, the sign
key is also equivalent to monotonicity
and essential
is equivalent to observable
. However, we do not include this in the type hints to discourage the
usage of these deprecated dictionary keys.
For backwards compatibility, the type is currently not generic, but provided as two separate aliases.
172class IdRegulation(TypedDict): 173 source: VariableId 174 target: VariableId 175 sign: Optional[SignType] 176 essential: BoolType 177 """ 178 See `Regulation` type alias. 179 """
Inherited Members
- builtins.dict
- get
- setdefault
- pop
- popitem
- keys
- items
- values
- update
- fromkeys
- clear
- copy
182class NamedRegulation(TypedDict): 183 source: str 184 target: str 185 sign: Optional[SignType] 186 essential: BoolType 187 """ 188 See `Regulation` type alias. 189 """
Inherited Members
- builtins.dict
- get
- setdefault
- pop
- popitem
- keys
- items
- values
- update
- fromkeys
- clear
- copy
BDD (binary decision diagram) is an acyclic, directed graph which is used to represent a Boolean function. BDDs can be used to efficiently represent large sets of states, functions, or spaces.
A Bdd
can be created as:
- A conjunction of literals defined by a
BddValuation
or aBddPartialValuation
. - Deserialization of an object created with
Bdd.data_string()
orBdd.data_bytes()
.
When deserializing, a BddVariableSet
has to be provided to interpret individual BDD variables.
Produce a graphviz
-compatible .dot
representation of the underlying graph. If zero_pruned
is set,
edges leading to the 0
terminal are omitted for clarity.
You can use this in Jupyter notebooks to visualize the BDD:
bdd = ...
import graphviz
graphviz.Source(bdd.to_dot())
Produce a BooleanExpression
which is logically equivalent to the function represented by this Bdd
.
The format uses an and-or expansion of the function graph, hence it is not very
practical for complicated Bdd
objects.
Build a list of BddPartialValuation
objects that represents a disjunctive normal form
of this Boolean function.
When optimize
is set to True
, the method dynamically optimizes the BDD to obtain
a smaller DNF. This process can be non-trivial for large BDDs. However, for such BDDs,
we usually can't enumerate the full DNF anyway, hence the optimization is enabled by
default. When optimize
is set to False
, the result should be equivalent to the
actual canonical clauses of this BDD as reported by Bdd.clause_iterator
.
See also BddVariableSet.mk_dnf
.
Build a list of BddPartialValuation
objects that represents a conjunctive normal form of this
Boolean function.
See also BddVariableSet.mk_cnf
.
Return the number of decision nodes for each BddVariable
that appears in this Bdd
(i.e. in the Bdd.support_set
).
Test structural equality of two Bdd
objects. Compared to normal ==
, this equality test
matches the two BDD graphs exactly, node by node.
As such, Bdd.structural_eq
is faster than normal ==
, which performs semantic equality check. However,
if a Bdd
is not reduced, two semantically equivalent BDDs can be structurally different. For the vast
majority of use cases, a Bdd
is reduced, and hence Bdd.structural_eq
and ==
gives the same result.
However, if the Bdd
comes from an unknown source (e.g. an external file), we cannot guarantee that it is
reduced and using Bdd.structural_eq
could be unreliable as an exact equality test.
Compares two Bdd
objects semantically (i.e. whether they compute the same Boolean function).
This is also used by the ==
operator. It is slightly faster than computing Bdd.l_iff
, as it does
not need to create the full result, just check whether it is a tautology. However, it is slower than
Bdd.structural_eq
, because it needs to still explore the product graph of the two Bdd
objects.
Tests whether the function self
implies the function other
. In terms of sets, this can be interpreted
as the subset relation (i.e. self
being a subset of other
).
This is slightly faster than computing Bdd.l_imp
, as it does not need to create the full result,
just check whether it is a tautology.
Return the number of variables that are admissible in this Bdd
(equivalent to BddVariableSet.variable_count
).
Return the set
of BddVariable
identifiers that are actually actively used by this specific Bdd
.
True if this Bdd
represents a single conjunctive clause.
In other words, it can be obtained as the result of Bdd(BddPartialValuation(ctx, X))
for some value of X
.
True if this Bdd
represents a single valuation of all variables.
In other words, it can be obtained as the result of Bdd(BddValuation(ctx, X))
for some value of X
.
Compute the cardinality (the number of satisfying valuations) of this Bdd
.
By default, the operation uses unbounded integers, since the cardinality can grow quite quickly. However, by
setting exact=False
, you can instead obtain a faster approximate result based on floating-point arithmetic.
For results that exceed the f64
maximal value (i.e. overflow to infinity), the method will still revert
to unbounded integers.
Compute the number of canonical clauses of this Bdd
. These are the disjunctive clauses
reported by Bdd.clause_iterator
. Clause cardinality can be thus used as the expected
item count for this iterator.
A standard "if-then-else" ternary operation. It is equivalent to $(a \land b) \lor (\neg a \land c)$.
Additional non-standard ternary operators are available through Bdd::apply3
.
Compute a custom binary operation on two Bdd
objects.
function
must be of type(None | bool, None | bool) -> None | bool
and implements the actual logical operation that will be performed.flip_left
,flip_right
, andflip_output
specify whether all low/high links of a specific variable should be swapped in the correspondingBdd
(this is effectively ax <- !x
substitution performed "for free" by the internal algorithm).limit
has the same meaning as in other logical operations: if specified, the method throwsInterruptedError
if the size of the outputBdd
exceeds the specifiedlimit
.
The same as Bdd.apply2
, but considers a ternary Boolean function instead of binary.
Currently, the operation does not support limit
, but this could be easily added in the future.
Instead of actually performing an operation, computes useful "metadata" about it. This is faster than running the operation in full, because there is no need to save the result.
Specifically, the result of this operation is a bool
indicating whether the result is empty, and an int
which counts the number of low-level "product nodes" that had to be explored in the operation. This "product
node count" is typically a good indicator for the actual operation complexity.
An apply
function which performs two nested passes of the apply algorithm:
- First, the
outer_function
is applied to combine the left and right BDDs. - Then, for each node of the newly created BDD which conditions on one of the specified
variables
, the method executes theinner_function
on its two child nodes. The result replaces the original output node.
This operation can be used to implement various combinations of logic + projection. Specifically, using
inner_function = or
implements existential projection and inner_function = and
implements universal
projection on the result of the outer_function
. However, much "wilder" combinations are possible if
you, for whatever reason, need them.
Performs a binary logical operation (function
) on two Bdd
objects while performing an existential
projection on the given variables in the result Bdd
.
See also Bdd.apply_nested
.
Performs a binary logical operation (function
) on two Bdd
objects while performing a universal
projection on the given variables in the result Bdd
.
See also Bdd.apply_nested
.
Picks one "witness" valuation for the given BddVariable
id(s) from this Bdd
.
To understand this operation, we split the BddVariables
into picked
(variables
) and non-picked
(the rest). For every unique valuation of non-picked
variables, the operation selects exactly one valuation
of picked
variables from the original Bdd
(assuming the non-picked
valuation is present at all).
In other words, the result is satisfied by every non-picked
valuation that satisfied the original Bdd
,
but each such non-picked
valuation corresponds to exactly one full valuation of picked + non-picked
variables.
Another useful way of understanding this operation is through relations: Consider a relation
$R \subseteq A \times B$ represented as a Bdd
. The result of R.pick(variables_B)
, denoted $R'$
is a sub-relation which is a bijection: for every $a \in A$ which is present in the original $R$,
we selected exactly one $b \in B$ s.t. $(a,b) \in R' \land (a, b) \in R$. If we instead compute
R.pick(variables_A)
, we obtain a different bijection: one where we selected exactly $a \in A$ for every
$b \in B$.
This operation is biased such that it always tries to select the lexicographically "first" witness.
The semantics of this operation are the same as Bdd.r_pick
, but instead of being biased towards the
"first" available witness, the operation picks the witnesses randomly.
You can make the process randomized but deterministic by specifying a fixed seed
.
Eliminate the specified variables
from this Bdd
using existential projection.
In terms of first-order logic, this is equivalent to applying the $\exists$ operator to the underlying Boolean function.
Eliminate the specified variables
from this Bdd
using universal projection.
In terms of first-order logic, this is equivalent to applying the $\forall$ operator to the underlying Boolean function.
Fix the specified variables to the respective values, and then eliminate the variables using existential projection.
Fix the specified variables to the respective values.
Pick the lexicographically first valuation from this Bdd
.
Pick a randomized valuation from this Bdd
.
Note: At the moment, the distribution of the selected valuations is not uniform (it depends on the structure
of the Bdd
). However, in the future we plan to update the method such that it actually samples
the valuations uniformly. If this is important to you, get in touch :)
You can make the process randomized but deterministic by specifying a fixed seed
.
An iterator over all BddValuation
objects that satisfy this Bdd
.
Pick the lexicographically first satisfying clause of this Bdd
.
Pick the lexicographically last satisfying clause of this Bdd
.
Pick a randomized satisfying clause from this Bdd
.
Note: At the moment, the distribution of the selected clauses is not uniform (it depends on the structure
of the Bdd
). However, in the future we plan to update the method such that it actually samples
the clauses uniformly. If this is important to you, get in touch :)
You can make the process randomized but deterministic by specifying a fixed seed
.
Compute the most restrictive conjunctive clause that covers all satisfying valuations of this BDD.
In other words, if you compute the BDD corresponding to the resulting partial valuation, the resulting BDD will be a superset of this BDD, and it will be the smallest superset that can be described using a single clause.
Compute the BddPartialValuation
that occurs among the Bdd.clause_iterator
items and
has the highest amount of fixed variables.
Note that this is not the most fixed valuation among all valuations that
satisfy this function (that is always a full valuation of all BDD variables). In other
words, the result of this operation tells you more about the structure of a Bdd
than
the underlying Boolean function itself.
Compute the BddPartialValuation
that occurs among the Bdd.clause_iterator
items and
has the lowest amount of fixed variables.
Note that this is not the most free valuation among all valuations that
satisfy this function (that would require a more thorough optimization algorithm). In other
words, the result of this operation tells you more about the structure of a Bdd
than
the underlying Boolean function itself.
An iterator over all DNF clauses (i.e. BddPartialValuation
objects) that satisfy this Bdd
.
Replace the occurrence of a given variable
with a specific function
.
Note that at the moment, the result is not well-defined if function
also depends on the substituted
variable (the variable is eliminated both from the original Bdd
and from function
). We are planning
to fix this in the future.
Rename Bdd
variables based on the provided (from, to)
pairs.
At the moment, this operation cannot modify the graph structure of the Bdd
. It can only replace variable
identifiers with new ones. As such, rename operation is only permitted if it does not violate
the current ordering. If this is not satisfied, the method panics.
Raise a RuntimeError
if this BDD violates some internal invariants.
Normally, all BDDs should satisfy internal invariants at all times, but in case we load a corrupted BDD file or the BDD is transferred from some other implementation other than our own, the BDD structure might become corrupted.
Represents a simple Boolean expression with support for Boolean constants, string variables, negation,
and common binary operators (and
/or
/imp
/iff
/xor
).
Expressions can be converted to/from Bdd
objects.
vars = BddVariableSet(["a", "b", "c"])
# The expressions are syntactically different, but represent the same function.
expr_x = BooleanExpression("(a & b) | (!b & c)")
expr_y = BooleanExpression("(c & !b) | (b & a)")
assert vars.eval_expression(expr_x) == vars.eval_expression(expr_y)
Build a new BooleanExpression
, either as a copy of an existing expression, or from a string representation.
Return a BooleanExpression
of a constant value.
Return a negation of a BooleanExpression
.
Return an and
of two BooleanExpression
values.
Return an or
of two BooleanExpression
values.
Return an imp
of two BooleanExpression
values.
Return an iff
of two BooleanExpression
values.
Return a xor
of two BooleanExpression
values.
Return an IF-THEN-ELSE condition of thee BooleanExpression
values.
Return true if the root of this expression is a binary operator (and
/or
/imp
/iff
/xor
).
If the root of this expression is a constant, return its value, or None
otherwise.
If the root of this expression is a var
, return its name, or None
otherwise.
If this expression is either var
or !var
, return the name of the variable and whether it is positive.
Otherwise, return None
.
If the root of this expression is one of the and
/or
/imp
/iff
/xor
operators, return the name of the
operator and its two operands. Returns None
if the root is not a binary operator.
Return the set of Boolean variable names that appear in this BooleanExpression
.
A numeric identifier of a single decision variable used within a Bdd
.
It essentially behaves like a type-safe integer value:
a = BddVariable(0)
b = BddVariable(1)
assert a == eval(repr(a))
assert a != b
assert a < b
assert a <= a
assert str(a) == "x_0"
assert int(a) == 0
d = {a: True, b: False}
assert d[a] != d[b]
The value of BddVariable
is frozen (i.e. immutable).
See also BddVariableType
.
A numeric identifier of a single node in a Bdd
.
It essentially behaves like a type-safe integer value with some extra utility methods:
x = BddPointer() # Default should be zero.
y = BddPointer(True)
z = BddPointer(10)
assert z == eval(repr(z))
assert x != z
assert x < y < z
assert str(x) == "node_0"
assert int(x) == 0
assert x == BddPointer.zero()
assert y == BddPointer.one()
assert (x.as_bool() is not None) and not x.as_bool()
assert (y.as_bool() is not None) and y.as_bool()
assert z.as_bool() is None
assert x.is_terminal() and x.is_zero()
assert y.is_terminal() and y.is_one()
assert not (z.is_terminal() or z.is_one() or z.is_zero())
The value of BddPointer
are frozen (i.e. immutable).
Construct a new BddPointer
using either a bool
value, or an exact int
index.
If no value is given, defaults to BddPointer.zero
.
Try to convert this BddPointer
to bool
(if it is terminal),
or None
if it represents a decision node.
Represents a complete valuation of all variables in a Bdd
.
This can be seen as a safer alternative to list[bool]
which can be also indexed using BddVariableType
and ensures that the length always matches the total number of the symbolic variables.
ctx = BddVariableSet(["a", "b", "c"])
assert BddValuation(ctx).values() == [False, False, False]
val_1 = BddValuation(ctx, [0,1,1])
val_1_copy = BddValuation(val_1)
assert val_1 == eval(repr(val_1))
assert str(val_1) == "[0,1,1]"
assert len(val_1) == 3
assert "a" in val_1 and "z" not in val_1
assert val_1["a"] == val_1_copy["a"]
assert val_1[BddVariable(2)] == val_1_copy[BddVariable(2)]
val_1_copy["a"] = 1
assert val_1["a"] != val_1_copy["a"]
valuations_as_keys = { val_1: "foo", val_1_copy: "bar" }
assert valuations_as_keys[val_1] == "foo"
A BddValuation
can be created as:
- A copy of a different
BddValuation
. - A copy of a
BddPartialValuation
, assuming it specifies the values of all relevant variables. - From a list of
BoolType
values and aBddVariableSet
context, as long as its length is exactly the variable count.
The list of BddVariable
keys used by this BddValuation
.
ctx = BddVariableSet(["a", "b", "c"])
val_1 = BddValuation(ctx, [0,1,1])
assert val_1.keys() == ctx.variable_ids()
The list of bool
values stored in this BddValuation
.
ctx = BddVariableSet(["a", "b", "c"])
val_1 = BddValuation(ctx, [0,1,1])
assert val_1.values() == [False, True, True]
The list of (BddVariable, bool)
tuples, similar to dict.items()
(can be also used to build a dictionary).
ctx = BddVariableSet(["a", "b", "c"])
a, b, c = ctx.variable_ids()
val_1 = BddValuation(ctx, [0,1,1])
val_dict = dict(val_1.items())
assert val_dict == { a: False, b: True, c: True }
Returns true of this BddValuation
also matches the constraints of a given BddPartialValuation
.
ctx = BddVariableSet(["a", "b", "c"])
val_1 = BddValuation(ctx, [0,1,1])
val_2 = BddValuation(ctx, [0,0,0])
p_val_1 = BddPartialValuation(ctx, {'a': 0, 'c': 1 })
assert val_1.extends(p_val_1)
assert not val_2.extends(p_val_1)
Represents a partial valuation of symbolic variables of a Bdd
.
This can be seen as a safer alternative to dict[BddVariable, bool]
that can be also indexed using any
BddVariableType
.
ctx = BddVariableSet(["a", "b", "c"])
assert len(BddPartialValuation(ctx)) == 0
val_1 = BddPartialValuation(ctx, {'a': 0, 'b': 1})
val_2 = BddPartialValuation(BddValuation(ctx, [0, 1, 0]))
val_3 = BddPartialValuation(val_1)
assert val_1 == eval(repr(val_1))
assert str(val_1) == "{'a': 0, 'b': 1}"
assert len(val_1) == 2
assert "a" in val_1 and "z" not in val_1
assert (val_1['a'] is not None) and (not val_1['a'])
assert (val_1['b'] is not None) and (val_1['b'])
# For "valid" variables, we return `None`, but fail for invalid variables.
assert val_1['c'] is None
with pytest.raises(IndexError):
assert val_1['z']
assert val_1["a"] == val_3["a"]
assert val_1[BddVariable(2)] == val_3[BddVariable(2)]
val_3["a"] = 1
assert val_1["a"] != val_3["a"]
assert val_1.keys() == [BddVariable(0), BddVariable(1)]
assert val_1.values() == [False, True]
assert dict(val_1.items()) == val_1.to_dict()
A BddPartialValuation
can be created as:
- A copy of data from a
BddValuation
or aBddPartialValuation
. - From a
BddVariableSet
"context" and aBddVariableType -> BoolType
mapping, assuming the mapping only contains variables that are valid in the provided context.
The list of BddVariable
identifiers for which a fixed value is stored in this BddPartialValuation
.
A utility method for directly converting this BddPartialValuation
to dict[BddVariable, bool]
.
Return the set of variables that are actively used by this BddPartialValuation
.
(This is equivalent to BddPartialValuation.keys
, but returns a set
instead of a list
)
Represents a collection of named BddVariable
identifiers and is primarily used to create
"atomic" Bdd
objects (constants, literals, etc.).
Note that Bdd
objects created by different variable sets are inherently incompatible.
However, in many reasonable cases, you can convert between them using
BddVariableSet.transfer_from
.
ctx = BddVariableSet(["a", "b", "c"])
assert str(ctx) == 'BddVariableSet(len = 3)'
assert ctx == eval(repr(ctx))
assert len(ctx) == 3
assert ctx.variable_count() == 3
assert ctx.variable_names() == ["a", "b", "c"]
assert ctx.variable_ids() == [BddVariable(i) for i in [0,1,2]]
var_b = ctx.find_variable("b")
assert var_b is not None
assert ctx.find_variable("x") is None
assert ctx.find_variable(BddVariable(10)) is None
assert ctx.get_variable_name(var_b) == "b"
assert ctx.get_variable_name("x") is None
ctx2 = BddVariableSet(["a", "c"])
not_c_1 = ctx.mk_literal("c", False)
not_c_2 = ctx2.transfer_from(not_c_1, ctx)
assert not_c_2 == ctx2.mk_literal("c", 0)
See also BddVariableSetBuilder
.
A BddVariableSet
is typically created using a list of variable names. However, you can also create
an "anonymous" BddVariableSet
using a variable count n
. In such a case, the variables are automatically
named $(x_0, \ldots, x_{n-1})$.
Return the list of all BddVariable
identifiers managed by this BddVariableSet
.
Return the list of all names for all variables managed by this BddVariableSet
.
The ordering should match the standard ordering of BddVariable
identifiers.
Return the BddVariable
identifier of the requested variable
, or None
if the
variable does not exist in this BddVariableSet
.
Return the string name of the requested variable
, or throw RuntimeError
if
such variable does not exist.
Create a new Bdd
representing the constant Boolean function given by value
.
Create a new Bdd
representing the literal $variable$ or $\neg variable$, depending
on the given value
.
Create a new Bdd
representing a conjunction of positive/negative literals
(e.g. $x \land y \land \neg z$).
See also BoolClauseType
.
Create a new Bdd
representing a disjunction of positive/negative literals
(e.g. $x \lor y \lor \neg z$).
See also BoolClauseType
.
Create a new Bdd
representing a conjunction of disjunctive clauses
(e.g. $(x \lor y) \land (\neg x \lor z)$).
This method uses a special algorithm that is typically faster than combining the clauses one by one.
See also BddVariableSet.mk_disjunctive_clause
and BoolClauseType
.
Create a new Bdd
representing a disjunction of conjunctive clauses
(e.g. $(x \land y) \lor (\neg x \land z)$).
This method uses a special algorithm that is typically faster than combining the clauses one by one.
See also BddVariableSet.mk_conjunctive_clause
and BoolClauseType
.
Compute a Bdd
which is satisfied by (and only by) valuations where exactly k
out of the specified variables
are True
.
If variables
are None
, the result is computed w.r.t. all variables
managed by this BddVariableSet
.
Compute a Bdd
which is satisfied by (and only by) valuations where up to k
out of the specified variables
are True
.
If variables
are None
, the result is computed w.r.t. all variables
managed by this BddVariableSet
.
Evaluate the provided BoolExpressionType
into a Bdd
, or throw an error if the
expression is invalid in this context (e.g. has unknown variables).
Translate a Bdd
between two BddVariableSet
objects.
The translation is only valid if the Bdd
relies on variables that are in both
variable set, and their ordering is mutually compatible. If this is not satisfied,
i.e. some of the variables don't exist in the new context, or would have to be reordered,
the method throws a runtime exception.
A utility class that can be used to build BddVariableSet
iteratively instead of
providing all the variable names at once.
builder = BddVariableSetBuilder()
x = builder.add("var_x")
a, b, c = builder.add_all(["a", "b", "c"])
ctx = builder.build()
assert ctx.var_count() == 4
assert ctx.get_variable_name(b) == "b"
assert ctx.find_variable("x") is None
assert ctx.find_variable("var_x") == x
Create a new BddVariableSetBuilder
, optionally initialized with the given list of variables.
Add a single new variable to this BddVariableSetBuilder
.
Panics if the variable already exists.
Add a collection of new variables to this BddVariableSetBuilder
.
Panics if some of the variables already exist.
A numeric identifier of a single network variable used within a BooleanNetwork
or a RegulatoryGraph
.
It essentially behaves like a type-safe integer value:
a = VariableId(0)
b = VariableId(1)
assert a == eval(repr(a))
assert a != b
assert a < b
assert a <= a
assert str(a) == "v_0"
assert int(a) == 0
d = {a: True, b: False}
assert d[a] != d[b]
The value of VariableId
is frozen (i.e. immutable).
See also VariableIdType
: In most cases where the ID can be "inferred from context",
a name can be also used to identify a network variable.
A numeric identifier of a single explicit parameter used within a BooleanNetwork
.
It essentially behaves like a type-safe integer value:
a = ParameterId(0)
b = ParameterId(1)
assert a == eval(repr(a))
assert a != b
assert a < b
assert a <= a
assert str(a) == "p_0"
assert int(a) == 0
d = {a: True, b: False}
assert d[a] != d[b]
The value of ParameterIdId
is frozen (i.e. immutable).
See also ParameterIdType
.
A regulatory graph is a directed graph consisting of network variables connected using regulations. Each regulation can be labeled as essential (also known as observable) and it can have a specified sign (also known as monotonicity).
Currently, the set of variables in a regulatory graph is immutable, because changing the
variable count would disrupt any VariableId
references to existing variables. However,
there are still multiple properties that can be mutated:
- The variable names can be changed using
RegulatoryGraph.set_variable_name
. - Regulations can be added or removed arbitrarily using
RegulatoryGraph.add_regulation
,RegulatoryGraph.ensure_regulation
, andRegulatoryGraph.remove_regulation
. - The variable set can be modified using the
RegulatoryGraph.extend
,RegulatoryGraph.drop
, andRegulatoryGraph.inline_variable
methods. However, these always create a new copy of the graph with a new set of validVariableId
objects.
A RegulatoryGraph
can be constructed from two optional arguments:
- A list of variable names. If this list is not given, it is inferred from the list of regulations (inferred variables are sorted alphabetically).
- A list of regulations. These can be either
NamedRegulation
dictionaries, or string objects compatible with the.aeon
format notation.
If you don't provide any arguments, an "empty" RegulatoryGraph
is constructed with no variables
and no regulations.
Try to read the structure of a RegulatoryGraph
from an .aeon
file at the specified path.
Try to read the structure of a RegulatoryGraph
from a string representing the contents of an .aeon
file.
Convert this RegulatoryGraph
to a string representation of a valid .aeon
file.
Produce a graphviz
-compatible .dot
representation of the underlying graph.
You can use this in Jupyter notebooks to visualize the RegulatoryGraph
:
graph = ...
import graphviz
graphviz.Source(graph.to_dot())
The number of network variables that are represented in this RegulatoryGraph
.
Return the list of all names for all variables managed by this RegulatoryGraph
.
The ordering should match the standard ordering of VariableId
identifiers.
Return the list of all BddVariable
identifiers valid in this RegulatoryGraph
.
Return a VariableId
identifier of the requested variable
, or None
if the variable
does not exist in this RegulatoryGraph
.
Return the string name of the requested variable
, or throw RuntimeError
if
such variable does not exist.
Update the variable name of the provided variable
. This does not change the
corresponding VariableId
.
The number of regulations currently managed by this RegulatoryGraph
.
Return the list of all regulations (represented as IdRegulation
dictionaries) that are currently
managed by this RegulatoryGraph
.
Return the list of regulations encoded as strings that would appear in the .aeon
file format.
Find an IdRegulation
dictionary that represents the regulation between the two variables, or None
if such regulation does not exist.
Add a new regulation to the RegulatoryGraph
, either using a NamedRegulation
, IdRegulation
, or
a string representation compatible with the .aeon
format.
Remove a regulation that is currently present in this RegulatoryGraph
. Returns the IdRegulation
dictionary that represents the removed regulation, or throws a RuntimeError
if the regulation
does not exist.
Update the sign
and essential
flags of a regulation in this RegulatoryGraph
.
If the regulation does not exist, it is created.
Returns the previous state of the regulation as an IdRegulation
dictionary, assuming the regulation
already existed.
Create a copy of this RegulatoryGraph
that is extended with the given list of variables
.
The new variables are added after the existing variables, so any previously used VariableId
references
are still valid. However, the added names must still be unique within the new graph.
Create a copy of this RegulatoryGraph
with all the specified variables (and their associated regulations)
removed.
Throws RuntimeError
if one of the variables does not exist.
The new graph follows the variable ordering of the old graph, but since there are now variables that are
missing in the new graph, the VariableId
objects are not compatible with the original graph.
Inline a variable into its downstream targets. This also "merges" the essential and sign flags of
the associated regulations in a way that makes sense for the existing constraints (e.g. +
and -
becomes
-
, -
and -
becomes +
; a regulation is essential if both "partial" regulations are essential, etc.).
Raises a RuntimeError
if the inlined variable has a self-regulation. This is because inlining
a self-regulated variable potentially "erases" a feedback loop in the graph, which can fundamentally
change its behaviour. And as opposed to RegulatoryGraph.drop
, the intention of this method is to produce
a result that is functionally compatible with the original regulatory graph. Of course, you can use
RegulatoryGraph.remove_regulation
to explicitly remove the self-loop before inlining the variable.
Make a copy of this RegulatoryGraph
with all constraints on the regulations removed.
In particular, every regulation is set to non-essential with an unknown sign.
The set of all variables that transitively regulate the given variable, or a set of variables.
If subgraph
is specified, the search is limited to a subgraph induced by the given collection of variables.
The set of all variables that are transitively regulated by the given variable, or a set of variables.
If subgraph
is specified, the search is limited to a subgraph induced by the given collection of variables.
Heuristically computes an approximation of a minimal feedback vertex set of this RegulatoryGraph
.
A feedback vertex set (FVS) is a set of variables which once removed cause the graph to become acyclic. The set is minimal if there is no smaller set that is also an FVS (in terms of cardinality).
You can specify a subgraph
restriction, in which case the algorithm operates only on the subgraph
induced by the provided variables. Similarly, you can specify parity
, which causes the algorithm to
only consider positive or negative cycles when evaluating the validity of an FVS.
Finally, note that the algorithm is not exact in the sense that it can result in a non-minimal FVS,
but the FVS is always correct in the context of this RegulatoryGraph
(or the specified subgraph
).
The algorithm is deterministic.
Heuristically computes an approximation of a maximal set of independent cycles of this RegulatoryGraph
.
Two cycles are independent if they do not intersect. A set of independent cycles (IC set) is maximal if it has the largest possible cardinality with all cycles being pair-wise disjoint.
You can specify a subgraph
restriction, in which case the algorithm operates only on the subgraph
induced by the provided variables. Similarly, you can specify parity
, which causes the algorithm to
only consider positive or negative cycles when evaluating the validity of an IC set.
Finally, note that the algorithm is not exact in the sense that it can result in a non-maximal IC set,
but the set is always correct in the context of this RegulatoryGraph
(or the specified subgraph
).
The algorithm is deterministic and the results are sorted from shortest to longest.
Compute the set of non-trivial strongly connected components of this RegulatoryGraph
.
If the subgraph
option is specified, only operates on the subgraph induced by these variables.
Note that a single variable with a self-regulation is considered a non-trivial SCC, even if it is not a member of a larger component.
Compute the set of weakly connected components of this RegulatoryGraph
. Note that typical regulatory graphs
represent a single weakly connected component.
If the subgraph
option is specified, only operates on the subgraph induced by these variables.
Find the shortest cycle in this RegulatoryGraph
that contains the pivot
variable, or None
if no such
cycle exists.
You can further restrict the algorithm using:
parity
: restricts the search to only positive/negative cycles.subgraph
: only considers cycles that fully belong to the specified induced subgraph.length
: only return cycles which are shorter or equal to the provided length.
The length of a cycle is counted in terms of edges, and a self-loop is thus a cycle of length one. If there are multiple shortest cycles, the algorithm always deterministically picks one such cycle, but the exact criterion is not documented. The result is ordered such that the first variable in the list is always the pivot vertex.
A BooleanNetwork
extends a RegulatoryGraph
with the ability to reference logical
parameters (Boolean uninterpreted functions), and with the ability to store an
UpdateFunction
for each network variable.
Logical parameters come in two varieties:
An explicit parameter is an uninterpreted function with a fixed name that can appear within
larger expressions, for example a | f(b, !c & d)
. An explicit parameter has to be declared
using BooleanNetwork.add_explicit_parameter
and can be referenced using a ParameterId
.
A single explicit parameter can appear in multiple update functions, in which case it is
always instantiated to the same Boolean function.
Meanwhile, an implicit parameter arises when a variable has an unknown (unspecified)
update function. In such case, we assume the update function of the variable is an
anonymous uninterpreted function which depends on all regulators of said variable. Such
implicit parameter does not have a ParameterId
. We instead refer to it using the VariableId
of the associated variable.
Read a BooleanNetwork
from a file path.
Supported file formats are .aeon
, .sbml
, or .bnet
.
By default, the method reads the underlying regulatory graph just as it is described in the input file.
However, such graph may not always be logically consistent with the actual update functions. If you set
repair_graph=True
, the underlying graph is instead inferred correctly from the actual update functions.
Try to read a BooleanNetwork
from a string representing the contents of an .aeon
file.
Convert this BooleanNetwork
to a string representation of a valid .aeon
file.
Update the variable name of the provided variable
. This does not change the
corresponding VariableId
.
Add a new regulation to the underlying RegulatoryGraph
of this BooleanNetwork
, either
using a NamedRegulation
, IdRegulation
, or a string representation compatible
with the .aeon
format.
Remove a regulation that is currently present in the underlying RegulatoryGraph
of this
BooleanNetwork
. Returns the IdRegulation
dictionary that represents the removed
regulation, or throws a RuntimeError
if the regulation does not exist. Also throws
a RuntimeError
if the regulation exists, but is used by the corresponding update
function and so cannot be safely removed.
Update the sign
and essential
flags of a regulation in the underlying
RegulatoryGraph
. If the regulation does not exist, it is created.
Returns the previous state of the regulation as an IdRegulation
dictionary,
assuming the regulation already existed.
Create a copy of this BooleanNetwork
that is extended with the given list of variables
.
The new variables are added after the existing ones, so any previously used
VariableId
references are still valid. However, the added names must still be unique
within the new network.
Create a copy of this BooleanNetwork
with all the specified variables
(and their associated regulations) removed.
If the removed variable also appears in some update function, the update function
is set to None
, but only if the variable actually appears in the update function
(i.e. just having a removed regulator does not automatically cause the function to
be removed). If a parameter becomes unused by removing said variables, the parameter
is removed as well.
Throws RuntimeError
if one of the variables does not exist.
The new graph follows the variable ordering of the old graph, but since there are now
variables that are missing in the new graph, the VariableId
objects are not compatible
with the original graph.
Produce a new BooleanNetwork
where the given variable has been eliminated by inlining
its update function into all downstream variables.
Note that the inlining operation is purely syntactic. This means that even if we create
new regulations when relevant, the resulting regulatory graph may be inconsistent with the
update functions. If you set repair_graph
to True
, the method will perform semantic
analysis on the new functions and repair regulatory graph where relevant. If repair_graph
is set to False
, the operation does not perform any such post-processing.
A simple example where "inconsistent" regulatory graph is produced is the inlining of a
constant input variable f_a = true
into the update function f_c = a | b
. Here, we have
regulations a -> c
and b -> c
. However, for the inlined function, we have
f_c = (true | b) = true
. As such, b
is no longer essential in f_c
and the resulting
model is thus not "logically consistent". We need to either fix this manually, or using
BooleanNetwork.infer_valid_graph
.
Limitations
At the moment, the reduced variable cannot have a self-regulation. If such a variable is
targeted with reduction, the function throws a RuntimeError
. If a variable is inlined
into a missing function, the function is given a name as a new parameter, and the variable
is inlined into this new parameter function.
Note that variables that don't regulate anything (outputs) are simply removed by this reduction. However, this is correct behaviour, just not super intuitive.
Also note that because the set of variables is different between this and the resulting
BooleanNetwork
, any VariableId
that is valid in this network is not valid in the
resulting network.
Logical parameters
Finally, note the set of admissible parameter instantiations (interpretations of
uninterpreted functions) can change between the original and the reduced model. The reason
for this is the same as in the example of a "logically inconsistent" system described
above. For example, consider a -> b
and b -> c
, but also a -| c
. Then, let's have
f_b = f(a)
and f_c = b & !a
. Then f(a) = a
is the only admissible interpretation
of f
. However, suppose we inline variable b
, obtaining f_c = f(a) & !a
with
regulation a -? c
(because a -> b -> c
and a -| c
in the original system). Then f
can actually be false
, a
, or !a
.
This does not mean you cannot use reduction on systems with uninterpreted functions at all, but be careful about the new meaning of the static constraints on these functions.
Return a copy of the underlying RegulatoryGraph
for this BooleanNetwork
.
Try to load a Boolean network from the contents of a .bnet
model file.
Note that this is currently only a "best effort" implementation, and you may encounter
unsupported .bnet
models.
We also support some features that .bnet
does not, in particular, you can use
Boolean constants (true
/false
). However, there are other things that we do not
support, since .bnet
can essentially use R syntax to define more complex functions,
but in practice this is not used anywhere.
Note that .bnet
files do not have any information about regulations. As such, by default regulations
are loaded as non-essential with no fixed sign. If you set repair_graph=True
, then we use a symbolic
method that infers these annotations automatically.
Produce a .bnet
string representation of this BooleanNetwork
.
Returns an error if the network is parametrised and thus cannot be converted to .bnet
.
By default, the method will rename any variables whose names are not supported in .bnet
.
However, you can instead ask it to throw a RuntimeError
using the
rename_if_necessary
flag.
Try to load a BooleanNetwork
from the contents of an .sbml
model file.
The number of explicit parameters, i.e. named uninterpreted functions in this network.
The number of implicit parameters, i.e. anonymous uninterpreted functions in this network.
Return the dictionary of ParameterId
identifiers of explicit parameters and their
corresponding arities.
Keep in mind that the iteration order of keys of this dictionary is not deterministic. If you need deterministic iteration, you have to sort the keys.
Return the dictionary of VariableId
identifiers for variables with anonymous update
functions and their corresponding arities.
Keep in mind that the iteration order of keys of this dictionary is not deterministic. If you need deterministic iteration, you have to sort the keys.
Return the list of explicit parameter names. The names as sorted in accordance with the
ParameterId
identifiers.
Return a ParameterId
identifier of the requested parameter
, or None
if the
uninterpreted function does not exist in this BooleanNetwork
.
Create a new explicit parameter.
the parameter name must be unique among existing variables and parameters.
Get the UpdateFunction
of a particular network variable, or None
if the function
is unknown (i.e. na implicit parameter).
Update the current update function of the specified variable
and return the previous
function.
All variables and parameters used in the new function must already exist in the
BooleanNetwork
. Furthermore, the function can only use variables that are declared
as regulators of the target variable
.
Infer a sufficient local regulatory graph based on the update functions of
this BooleanNetwork
.
Notes
- The method will simplify the update functions when it detects that a variable is not an essential input of the update function (for any instantiation).
- This also removes any unused parameters (uninterpreted functions), or parameters that become unused due to the transformation.
- For fully specified update functions, the method simply updates the regulations to match the actual behaviour of the function (i.e. any non-essential regulations are removed, sign is always specified unless the input is truly non-monotonic).
- For regulations that interact with uninterpreted functions:
- Essentiality: If there are no instantiations where the regulation is essential, we remove the regulation completely. Otherwise, we preserve the original essentiality constraint.
- Monotonicity: Similarly, if every instantiation of the function has a known monotonicity, then we use the corresponding sign. Otherwise, if the original constraint is still satisfied for a subset of all instantiations, we use the original one.
Limitations
The result only guarantees that the constraints are locally consistent*, meaning they are valid when applied to the singular update function, not necessarily the whole model. In other words, uninterpreted functions that are used by multiple variables can still cause the model to be invalid if they use contradictory constraints, but this usually cannot be resolved deterministically because we would have to pick which constraint should be relaxed to resolve the conflict.
Output
The function can fail if, for whatever reason, it cannot create SymbolicContext
for
the input network.
Make a copy of this BooleanNetwork
with all constraints on the regulations removed.
In particular, every regulation is set to non-essential with an unknown sign.
Similar to BooleanNetwork.inline_inputs
, but inlines constant values (i.e. x=true
or
x=false
).
By default, the constant check is purely syntactic, but we do perform basic constant
propagation (e.g. x | true = true
) in order to catch the most obvious non-trivial cases.
However, you can set infer_constants
to True
, in which case a symbolic method will
be used to check if the variable has a constant function. Note that this can also
eliminate parameters in some cases (e.g. inlining x=true
into y=x | f(z)
).
Furthermore, similar to BooleanNetwork.inline_inputs
, you can set repair_graph
to
true
to fix any inconsistent regulations that arise due to the inlining
(this is highly recommended if you are using infer_constants
).
The inlining is performed iteratively, meaning if the inlining produces a new constant, it is eventually also inlined.
The method can fail if infer_constants
or repair_graph
is specified and the network
does not have a valid symbolic representation.
Try to inline the input nodes (variables) of the network as logical parameters (uninterpreted functions of arity 0).
Here, an "input" is a variable x
such that:
x
has no incoming regulations and a missing update function.x
has an identity update function. This is either checked syntactically (default), or semantically using BDDs (ifinfer_inputs
is set toTrue
).
Note that this does not include constant nodes (e.g. x=true
). These are handled
separately by BooleanNetwork.inline_constants
. Also note that input variables that
do not influence any other variable are removed.
Variables with update functions x=f(true, false)
or x=a
(where a
is a zero-arity
parameter) are currently not considered to be inputs, although their role is conceptually
similar.
This method is equivalent to calling BooleanNetwork.inline_variable
on each input,
but the current implementation of BooleanNetwork.inline_variable
does not permit
inlining of self-regulating variables, hence we have a special method for inputs only.
Finally, just as BooleanNetwork.inline_variable
, the method can generate an
inconsistent regulatory graph. If repair_graph
is set to True
, the static properties
of relevant regulations are inferred using BDDs.
Return a copy of this network where all unused explicit parameters (uninterpreted functions) are removed.
Note that VariableId
objects are still valid for the result network, but ParameterId
objects can now refer to different parameters.
Replaces an implicit parameter (i.e. an anonymous update function) with an explicit parameter of the given name. If no name is provided, a default name is generated instead.
The arguments of the newly created update function follow the ordering of variable IDs.
Replaces all implicit parameters with explicit counterparts using default names.
See also BooleanNetwork.assign_parameter_name
.
Returns True
if the given variable
is an input of the BooleanNetwork
.
Input can be either:
- A variable with no incoming regulations and no update function.
- A variable with a positive self-regulation and an update function that is equivalent to an identity function.
Note that by default, function equivalent is tested only syntactically (with basic
simplifications applied). To test equivalence semantically, you have to provide
a SymbolicContext
object as the second argument.
Tests whether the given variable
is a constant of the BooleanNetwork
. A variable
is a constant if it's update function is equivalent to True
or False
. Note that
this differs from inputs, whose update function is equivalent to identity.
If the variable is not constant, the function returns None
. If it is constant,
it returns its constant value.
By default, function equivalent is tested only syntactically (with basic
simplifications applied). To test equivalence semantically, you have to provide
a SymbolicContext
object as the second argument.
Return the list of all inputs that are present in this BooleanNetwork
. See also
BooleanNetwork.is_var_input
.
If infer=True
, the method will use symbolic equivalence check for identifying
input variables, which is more accurate but also more resource intensive.
Same as BooleanNetwork.inputs
, but returns a list of variable names instead.
Return the dictionary of all constants that are present in this BooleanNetwork
. See also
BooleanNetwork.is_var_constant
.
If infer=True
, the method will use symbolic equivalence check for identifying
constant variables, which is more accurate but also more resource intensive.
Same as BooleanNetwork.constants
, but the keys in the dictionary are variable names,
not IDs.
Inherited Members
- RegulatoryGraph
- to_dot
- variable_count
- variable_names
- variables
- find_variable
- get_variable_name
- regulation_count
- regulations
- regulation_strings
- find_regulation
- predecessors
- successors
- backward_reachable
- forward_reachable
- feedback_vertex_set
- independent_cycles
- strongly_connected_components
- weakly_connected_components
- shortest_cycle
Describes a single update function that is used to describe the dynamics of a BooleanNetwork
.
It is similar to a BooleanExpression
, but additionally admits the use of uninterpreted functions (also called
explicit parameters in the context of a BooleanNetwork
). These are Boolean functions with unknown but fixed
specification that stand in for any unknown behaviour in the corresponding BooleanNetwork
.
Additionally, compared to a BooleanExpression
, the UpdateFunction
refers to network variables and parameters
using VariableId
and ParameterId
. To that end, every UpdateFunction
has an underlying BooleanNetwork
which is used to resolve names to IDs and vice versa.
Build a new UpdateFunction
in the context of the specified BooleanNetwork
.
The value
can be either a string (in which case it is parsed), an UpdateFunction
,
in which case it is "translated" into the given context (IDs are updated based on matching names),
or a BooleanExpression
, in which case it also translated using variable names.
Return an UpdateFunction
for a constant value.
Return an UpdateFunction
of a single variable.
Return an and
of two UpdateFunction
values.
Return an or
of two UpdateFunction
values.
Return an imp
of two BooleanExpression
values.
Return an iff
of two BooleanExpression
values.
Return a xor
of two BooleanExpression
values.
Construct a binary expression using the given operator (and
/or
/imp
/iff
/xor
).
Build a conjunction of multiple expressions.
Build a disjunction of multiple expressions.
Return true if the root of this expression is a call to an uninterpreted function.
Return true if the root of this expression is a binary operator (and
/or
/imp
/iff
/xor
).
If the root of this expression is a constant, return its value, or None
otherwise.
If the root of this expression is a call to an uninterpreted function, return its ID and arguments, or
None
otherwise.
If this expression is either var
or !var
, return the ID of the variable and whether it is positive.
Otherwise, return None
.
If the root of this expression is one of the and
/or
/imp
/iff
/xor
operators, return the name of the
operator and its two operands. Returns None
if the root is not a binary operator.
Return the set of variable IDs that are used in this UpdateFunction
.
Return the set of parameter IDs that are used in this UpdateFunction
.
Create a copy of this UpdateFunction
with every occurrence of the specified variables substituted
for the corresponding function.
Note that at the moment, there is no substitution method for parameters, since we don't have a concept of an "expression with holes" which we could use here.
Rename all occurrences of the specified variables
and parameters
to new IDs.
The variables
and parameters
dictionaries map the old variables (using VariableId
or a string name)
to new variables (again, using IDs or names). If the new names or IDs are not valid in the currently
referenced BooleanNetwork
, you can supply a new_ctx
. If new_ctx
is given, dictionary keys are resolved
in the current context, but dictionary values are resolved in the newly provided context.
Creates a copy of this UpdateFunction
with all constant values propagated into the remaining
expression. Consequently, the result contains constant values only if (a) the whole function is a constant,
or (b) a constant value is used as an argument of an uninterpreted function (parameter).
Creates a copy of this UpdateFunction
where the negation operation is distributed to the propositions
(constants, network variables, and function invocations).
The operation is also applied to each expression that is an argument of an uninterpreted function. However, we cannot distribute the negation of an uninterpreted function to its arguments without further knowledge about its behaviour.
Creates a copy of this UpdateFunction
where all binary operators are expanded into their and
/or
equivalents.
Note that in extreme cases, the result can be an exponentially larger formula compared to the original.
Convert the UpdateFunction
to a BooleanExpression
, as long as the function contains no uninterpreted
functions (otherwise throws a RuntimeError
).
Annotations are "meta" objects that can be declared as part of .aeon
models to add additional
properties that are not directly recognized by the main AEON toolbox.
An annotation object behaves like a tree, where each node can have an optional string value, and an unordered collection of children which behave mostly like a dictionary:
ann = ModelAnnotation()
# Empty ModelAnnotation is created automatically when key is first accessed.
desc = ann['description']
assert desc.value is None
desc.value = "Multiline...\n"
desc.value += "...test description"
desc['x'].value = "Variable X"
desc['y'].value = "Variable Y"
assert len(desc) == 2
assert ann['description']['x'].value == "Variable X"
This generates the following set of annotation comments:
#!description:Multiline...
#!description:...test description
#!description:x:Variable X
#!description:y:Variable Y
Annotation syntax
Annotations are comments which start with #!
. After the #!
"preamble", each annotation
can contain a "path prefix" with path segments separated using :
(path segments can be
surrounded by white space that is automatically trimmed). Based on these path
segments, the parser will create an annotation tree. If there are multiple annotations with
the same path, their values are concatenated using newlines.
For example, annotations can be used to describe the model layout:
#! layout : var_1 : 10,20
#! layout : var_2 : 14,-3
Another usage for annotations are additional properties expected from the model, for example written in CTL:
#! property : AG (problem => AF apoptosis)
Obviously, you can also use annotations to specify model metadata:
#! name: My Awesome Model
#! description: This model describes ...
#! description:var_1: This variable describes ...
You can use "empty" path (e.g. #! is_multivalued
), and you can use an empty annotation
value with a non-empty path (e.g. #! is_multivalued:var_1:
). Though this is not particularly
encouraged: it is better to just have var_1
as the annotation value if you can do that.
An exception to this may be a case where is_multivalued:var_1:
has an "optional" value, and
you want to express that while the "key" is provided, the "value" is missing. Similarly, for
the sake of completeness, it is technically allowed to use empty path names (e.g. a::b:value
translates to ["a", "", "b"] = "value"
), but it is discouraged.
Note that the path segments should only contain alphanumeric characters and underscores,
but can be escaped using backticks (`
; other backticks in path segments are not allowed).
Similarly, annotation values cannot contain colons (path segment separators) or backticks,
unless escaped with #`ACTUAL_STRING`#
. You can also use escaping if you wish to
retain whitespace surrounding the annotation value. As mentioned, multi-line values can be
split into multiple annotation comments.
Create a new ModelAnnotation
with an optional string value
.
The child annotations can be then set similar to a normal dictionary, but this is not supported in the constructor for now.
Intuitively, a SymbolicContext
encodes the entities of a BooleanNetwork
into a set
of symbolic variables managed by a BddVariableSet
. Using this representation, we can
ecode sets of states, sets of function interpretations, or relations over both.
Internally, each VariableId
corresponds to one BddVariable
, and each uninterpreted
function corresponds to a table of 2^k
BddVariable
identifiers, which together represent
the logical table of the uninterpreted function.
An uninterpreted function is created for each explicit and implicit parameter of the
BooleanNetwork
for which a SymbolicContext
is constructed. The SymbolicContext
is
static and does not update even if the supplied network changes later. Also, keep in mind
that implicit parameters are only created for variables with missing update functions,
not all network variables.
Additionally, you can specify your own "extra" symbolic variables. These can be used to build
more complex symbolic algorithms on top of the basic encoding, like model checking, control,
or trap space detection. These extra variables are grouped with the network variables for
convenience. This also determines their ordering within the BddVariableSet
: the extra
variables associated with variable x
are created right after x
for best locality.
Finally, SymbolicContext
allows to build and interpret Bdd
objects that are valid in
the encoding it describes. For example, you can use SymbolicContext.mk_update_function
to create a symbolic Bdd
representation of an UpdateFunction
.
Whenever a
SymbolicContext
returns a list of sortable objects (likeBddVariable
,VariableId
, orParameterId
), it is expected that these objects are sorted.
A SymbolicContext
is created by providing a BooleanNetwork
and optional
extra_variables
dictionary.
At the moment, it is required that all explicit parameters (uninterpreted functions) that are declared in the given network are actually used by some update function in said network.
In the future, this restriction will be lifted, but it is not quite clear how soon will this happen.
Furthermore, due to this dependence on a BooleanNetwork
structure, a
SymbolicContext
cannot be currently pickled. It is recommended that you instead save
the .aeon
representation of the BooleanNetwork
in question.
The number of the network variables (or state variables) that are encoded by this SymbolicContext
.
The names of the network variables that are encoded by this SymbolicContext
.
The VariableId
identifiers of the network variables that are encoded by this
SymbolicContext
.
The BddVariable
IDs of symbolic variables that encode the network variables
in this SymbolicContext
.
Return a VariableId
of the specified network variable, assuming such variable exists.
Compare to methods like BooleanNetwork.find_variable
, this method can also resolve
a BddVariable
to the corresponding VariableId
(assuming said BddVariable
encodes
a network variable).
The same as SymbolicContext.find_network_variable
, but returns the BddVariable
which encodes the specified network variable.
The total number of extra symbolic variables that are present in this SymbolicContext
.
The list of all extra symbolic variable in this SymbolicContext
.
The number of explicit functions (parameters) managed by this SymbolicContext
.
The list of ParameterId
objects identifying the individual explicit functions
in this SymbolicContext
.
The list of all symbolic variables which this SymbolicContext
uses for the encoding of
the explicit uninterpreted functions.
A dictionary which maps the ParameterId
of an explicit function to the list of symbolic
variables that are used to encode said function.
The number of implicit functions (parameters) managed by this SymbolicContext
.
The list of all symbolic variables which this SymbolicContext
uses for the encoding of
the implicit uninterpreted functions.
A dictionary which maps the VariableId
of an implicit function to the list of symbolic
variables that are used to encode said function.
The list of all symbolic variables which this SymbolicContext
uses for the encoding of
the uninterpreted functions (both implicit and explicit).
A dictionary which maps the VariableId
and ParameterId
objects identifying individual
uninterpreted functions to the symbolic variables that are used to encode said function.
Find a ParameterId
(explicit function) or VariableId
(implicit function) which
identifies the specified function, or None
if such function does not exist.
The function can accept a BddVariable
. In such case, it will try to identify the
function table in which the variable resides. Note that this is a linear search.
Return the name of an uninterpreted function. For explicit functions, the name of the network parameter is returned. For implicit functions, the name of the corresponding network variable is returned.
Return the "function table" a specified uninterpreted function. A function table consists of tuples, where each tuple represents one input-output pair of the logical table of the function in question. The input is a list of Boolean values, the output is a symbolic variable that represents the output of the function for this input vector.
Create a new Bdd
which is true if and only if the specified network variable is true.
This is equivalent to calling SymbolicContext.mk_update_function
with
UpdateFunction.mk_var(variable)
as the argument.
Create a new Bdd
which is true if and only if the specified extra symbolic variable
is true. The variable is specified by its associated network variable and index (or offset).
If the arguments are not provided, the method uses the first network variable and index 0
.
Create a Bdd
which is valid if and only if the specified uninterpreted function is valid.
The function takes a vector of arguments which must match the arity of the uninterpreted
function. An argument can be either an arbitrary Bdd
object, or an UpdateFunction
from which a Bdd
is then constructed.
Create a Bdd
which is valid if and only if the specified UpdateFunction
is valid.
This can be used to build any Boolean function that depends on the network variables and the explicit uninterpreted functions. It cannot be used to operate on the extra symbolic variables or implicit uninterpreted functions.
This is similar to BddVariableSet.transfer_from
, but is applied at the level of
symbolic contexts.
In other words, you can use this method to translate Bdd
objects between contexts
that use similar variables and parameters, as long as the Bdd
only uses objects that
are present in both context, and are ordered the same in both contexts.
Compute a "canonical context" for this SymbolicContext
. A canonical context has no
extra symbolic variables. In other words, it is a context that contains only
the elements necessary to encode the original BooleanNetwork
and nothing else.
You can use this method in combination with SymbolicContext.transfer_from
in algorithms
that require more complicated symbolic contexts. After such algorithm computes a result,
it can be safely transferred to the "canonical context" which ensures it can be then
interpreted using only the input model, without any internal information about the
algorithm that was used to obtain the result.
Create a new SymbolicContext
which is compatible with the current context (it uses the
same BddVariableSet
), but is missing the given network variable.
The new context uses the same ParameterId
identifiers as the old context, but has
different VariableId
identifiers, since one of the variables is no longer used, and
VariableId
identifiers must be always a contiguous sequence. You should use variable
names to "translate" VariableId
identifiers between the two symbolic context. Of course,
SymbolicContext.transfer_from
should also still work.
Note that the extra symbolic variables and implicit function tables do not disappear,
even if they are only used by the eliminated variable. They will still appear in
SymbolicContext.extra_bdd_variables_list
and
SymbolicContext.functions_bdd_variables_list
. However, you will no longer
find them in SymbolicContext.extra_bdd_variables
and
SymbolicContext.functions_bdd_variables
, since their variable is eliminated.
An extension of the SymbolicContext
which supports symbolic representation of network
sub-spaces.
To implement this, SymbolicSpaceContext
uses the "extra variables" feature of the
standard SymbolicContext
. On its own, SymbolicSpaceContext
currently does not allow
having any extra variables aside from those used for space representation. However, nothing
fundamentally prevents us from including additional variables in the future.
A SymbolicSpaceContext
is created from a BooleanNetwork
, just as a regular
SymbolicContext
. However, no extra symbolic variables can be specified in this case.
The symbolic variable that encodes the fact that a specified network_variable
can have value True
in a particular subspace.
The symbolic variable that encodes the fact that a specified network_variable
can have value False
in a particular subspace.
Compute a Bdd
which encodes all spaces in which the value of function
can be
true
for some state. We assume that function
can depend on state variables and
parameter variables, but not on the dual variables used for space encoding.
In other words, a space S
satisfies the result Bdd
if and only if there exists
a state x \in S
such that function(x) = true
.
To compute this, we evaluate the following (informal) expression:
exists s_1...s_n: [(s_i => s_i_T) & (!s_i => s_i_F)] & function(s_1, ..., s_n)
WARNING: The resulting BDD also allows invalid space encodings, mostly because
these are to some extent still interesting in some applications. You'll need to
intersect it with SymbolicSpaceContext.mk_unit_bdd
.
Compute the colored set of all network sub-spaces.
Note that SymbolicSpaceContext
has no notion of "unit colors". By default, the final relation contains
all colors. If you want to restrict the relation in the same manner as
AsynchronousGraph.mk_unit_colored_vertices
, you have to provide an optional AsynchronousGraph
.
Compute the set of all network sub-spaces.
Note that this is different from a Bdd
function True
because not every valuation of the dual variables
encodes a valid network space.
Compute the Bdd
which contains all correctly encoded spaces tracked by this SymbolicSpaceContext
.
The Bdd
only constraints the space variables and it has no impact on the network/parameter
variables. Also note that this is not the true
function, since not every valuation of space variables
correctly encodes a space.
Extend the given set
with all the sub-spaces for every element of the set.
For colored sets, this extension is happening color-wise, so new sub-spaces are added with the same color as their parent space.
Extend the given set
with all the sub-spaces for every element of the set.
For colored sets, this extension is happening color-wise, so new sub-spaces are added with the same color as their parent space.
Compute the SpaceSet
that represents a single network subspace.
See also AsynchronousGraph.mk_subspace
.
A utility method which "materializes" the network spaces in the dual encoding into a set of vertices that reside in these places.
See also SymbolicSpaceContext::vertices_to_spaces
, but note that these operations
are not invertible, that is vertices_to_spaces(spaces_to_vertices(x))
does not
produce the original set x
.
Convert a set of vertices into a set of singleton spaces. That is, for each vertex, the corresponding space is created.
In other words, this does not try to decompose the set into maximal spaces or anything like that, it converts each vertex 1:1 into a space.
Inherited Members
- SymbolicContext
- network_variable_count
- network_variable_names
- network_variables
- network_bdd_variables
- find_network_variable
- find_network_bdd_variable
- get_network_variable_name
- extra_bdd_variable_count
- extra_bdd_variables_list
- extra_bdd_variables
- explicit_function_count
- explicit_functions
- explicit_functions_bdd_variables_list
- explicit_functions_bdd_variables
- implicit_function_count
- implicit_functions
- implicit_functions_bdd_variables_list
- implicit_functions_bdd_variables
- function_count
- functions
- functions_bdd_variables_list
- functions_bdd_variables
- find_function
- get_function_name
- get_function_arity
- get_function_table
- mk_constant
- mk_network_variable
- mk_extra_bdd_variable
- mk_function
- mk_update_function
- bdd_variable_set
- transfer_from
- to_canonical_context
A symbolic representation of a set of "vertices", i.e. valuations of variables
of a particular BooleanNetwork
.
Normally, a new VertexSet
is derived using an AsynchronousGraph
. However, in some
cases you may want to create it manually from a SymbolicContext
and a Bdd
.
Just keep in mind that this method does not check that the provided Bdd
is semantically
a valid set of vertices.
True if this set is a subset of the other set.
Should be faster than just calling set.minus(superset).is_empty()
True if this set is a subspace, i.e. it can be expressed using a single conjunctive clause.
Deterministically pick a subset of this set that contains exactly a single vertex.
If this set is empty, the result is also empty.
Extend this set of vertices with all the colors from the given set.
This is essentially a cartesian product with the given ColorSet
.
Returns an iterator over all vertices in this VertexSet
with an optional projection to a subset
of network variables.
When no retained
collection is specified, this is equivalent to VertexSet.__iter__
. However, if a retained
set is given, the resulting iterator only considers unique combinations of the retained
variables.
Consequently, the resulting VertexModel
instances will fail with an IndexError
if a value of a variable
outside the retained
set is requested.
Compute the smallest enclosing subspace, represented as dict[VariableId, bool]
with
missing variables being treated as unrestricted.
Returns None
if the set is empty.
Compute the smallest enclosing subspace, represented as dict[str, bool]
, using variable
names as keys and with missing variables being treated as unrestricted.
Returns None
if the set is empty.
Compute the largest subspace that is fully enclosed in this vertex set. Note that such subspace may not be unique (i.e. there can be other subspaces that are just as large).
Returns None
if the set is empty.
Same as VertexSet.enclosed_subspace
, but uses names instead of IDs.
Represents a single vertex stored in a VertexSet
(or a ColoredVertexSet
), or a projection
of said vertex to the chosen variables.
Behaves like an immutable dictionary: Boolean variable values can be queried using
a VariableId
, a string name, or a BddVariable
.
The actual "retained" network variables in this model.
This is the list of all network variables if no projection was applied.
The same as VertexModel.items
, but returns a dictionary instead.
The same as VertexModel.to_dict
, but the keys in the dictionary are names, not IDs.
Return the underlying BddPartialValuation
for this symbolic model.
Return a VertexSet
where all the variables are fixed according
to the values in this VertexModel
. Variables that are not present in the VertexModel
are unrestricted.
A symbolic representation of a set of "colours", i.e. interpretations of explicit and
implicit parameters within a particular BooleanNetwork
.
Normally, a new ColorSet
is derived using an AsynchronousGraph
. However, in some
cases you may want to create it manually from a SymbolicContext
and a Bdd
.
Just keep in mind that this method does not check that the provided Bdd
is semantically
a valid set of colors.
Returns the number of "colors" (function interpretations) that are represented in this set.
True if this set is a subset of the other set.
Should be faster than just calling set.minus(superset).is_empty()
True if this set is a singleton, i.e. a single function interpretation.
True if this set is a subspace, i.e. it can be expressed using a single conjunctive clause.
Deterministically pick a subset of this set that contains exactly a single function interpretation.
If this set is empty, the result is also empty.
Extend this set of colors with all the vertices from the given set.
This is essentially a cartesian product with the given VertexSet
.
Extend this set of colors with all the spaces from the given set.
This is essentially a cartesian product with the given SpaceSet
.
Returns an iterator over all interpretations in this ColorSet
with an optional projection to a subset
of uninterpreted functions.
When no retained
collection is specified, this is equivalent to ColorSet.__iter__
. However, if a retained
set is given, the resulting iterator only considers unique combinations of the retained
functions.
Consequently, the resulting ColorModel
instances will fail with an IndexError
if a value of a function
outside the retained
set is requested.
Represents a single "color" stored in a ColorSet
(or a ColoredVertexSet
), or a projection
of said color to the chosen uninterpreted functions.
Behaves like an immutable dictionary: Uninterpreted functions can be queried using
a VariableId
/ParameterId
(implicit/explicit parameters), a string name, or
a BddVariable
from the function table. The result is a BooleanExpression
.
However, note that each function instantiation is by default represented as a
BooleanExpression
using anonymous variable names x_0 ... x_k
(where k
is the arity
of the uninterpreted function). If you actually want to instantiate the function w.r.t.
a set of arguments, specific UpdateFunction
, or a parametrized BooleanNetwork
,
you can use the ColorModel.instantiate
method.
The actual "retained" uninterpreted functions in this ColorModel
.
This is the list of all ParameterId
and VariableId
objects that admit an associated
uninterpreted function and said function is present in this ColorModel
.
The list of BooleanExpression
objects representing the individual uninterpreted functions
from ColorModel.keys
.
The same as VertexModel.items
, but returns a dictionary instead.
The same as ColorModel.to_dict
, but the keys in the dictionary are names, not IDs.
Return the underlying BddPartialValuation
for this symbolic model.
Return a ColorSet
where all the implicit and explicit parameters are fixed according
to the values in this ColorModel
. Parameters that are not present in the ColorModel
are unrestricted.
Note that this does not apply any constraints that may be relevant in the
AsynchronousGraph
that was used to create this model.
The ColorModel.instantiate
method is used to "fill in" the actual implementation of
the uninterpreted functions defined in this ColorModel
into an object that depends on
this implementation.
Specifically, there are three supported modes of operation:
- If
item
is anUpdateFunction
, the result is a newUpdateFunction
that only depends on network variables and is the interpretation of the original function under this model. - If
item
is aBooleanNetwork
, the result is a newBooleanNetwork
where all uninterpreted functions that are retained in this model are instantiated. By default, the newBooleanNetwork
has a regulatory graph that is inferred from the update functions (in particular, this removes all unused regulations). If you want to retain the original regulatory graph, useinfer_regulations=False
(this argument has no effect in the other use cases). - If
item
identifies an uninterpreted function (byParameterId
,VariableId
, or a string name), the method returns anUpdateFunction
that is an interpretation of the uninterpreted function with specifiedargs
under this model. This is equivalent to computingSymbolicContext.mk_function
and then instantiating this function. Note that in this situation, theargs
argument is required, and it must match the arity of the uninterpreted function.
Note that in some cases, instantiating an UpdateFunction
with two different
interpretations can lead to the same UpdateFunction
. This happens if parts of the
function are redundant. For example, f(x) | !f(x)
always instantiates to true
,
regardless of the interpretation of f
. Hence, you can assume that while interpretations
(i.e. model["f"]
) are unique within a set, the instantiations of more complex functions
that depend on them are not.
A symbolic representation of a set of "spaces", i.e. hypercubes in the state space
of a particular BooleanNetwork
.
Normally, a new SpaceSet
is derived using a SymbolicSpaceContext
. However, in some
cases you may want to create it manually from a SymbolicSpaceContext
and a Bdd
.
Just keep in mind that this method does not check that the provided Bdd
is semantically
a valid set of spaces.
True if this set is a subset of the other set.
Should be faster than just calling set.minus(superset).is_empty()
Deterministically pick a subset of this set that contains exactly a single subspace.
If this set is empty, the result is also empty.
Extend this set of spaces with all the colors from the given set.
This is essentially a cartesian product with the given ColorSet
.
Returns an iterator over all sub-spaces in this SpaceSet
with an optional projection to
a subset of network variables.
When no retained
collection is specified, this is equivalent to SpaceSet.__iter__
.
However, if a retained set is given, the resulting iterator only considers unique
valuations for the retained
variables. Consequently, the resulting SpaceModel
instances
will fail with an IndexError
if a value of a variable outside the retained
set is
requested.
Produce a set of spaces that is a superset of this set, and in addition contains all spaces that are a subspace of some item in this set.
Represents a single space stored in a SpaceSet
(or a ColoredSpaceSet
), or a projection
of said space to the chosen variables.
Behaves like an immutable dictionary: Boolean variable values can be queried using
a VariableId
, a string name, or a BddVariable
. If the value is unconstrained, the result
is None
. If the variable is projected away, the operation throws an IndexError
.
The actual "retained" network variables in this model.
This is the list of all network variables if no projection was applied.
The list of values for individual variables from SpaceModel.keys
.
The same as SpaceModel.items
, but returns a dictionary instead.
The same as SpaceModel.to_dict
, but the keys in the dictionary are names, not IDs.
Return the underlying BddPartialValuation
for this symbolic model.
Return a SpaceSet
where all the variables are fixed according
to the values in this SpaceModel
. Variables that are not present in the SpaceModel
are unrestricted, meaning their value can be any of 0
, 1
, and *
.
A symbolic representation of a relation of "coloured vertices", i.e. pairs of vertices
(see VertexSet
) and colors (see ColorSet
).
Together, such pair represents a specific interpretation of network parameters and valuation of network variables.
Normally, a new ColoredVertexSet
is derived using an AsynchronousGraph
. However, in some
cases you may want to create it manually from a SymbolicContext
and a Bdd
.
Just keep in mind that this method does not check that the provided Bdd
is semantically
a valid colored set of vertices.
Returns the number of vertex-color pairs that are represented in this set.
True if this set is a subset of the other set.
Should be faster than just calling set.minus(superset).is_empty()
True if this set is a subspace, i.e. it can be expressed using a single conjunctive clause.
Compute the existential projection of this relation to the color component. I.e. returns a set of colors such that for each color, there is at least one vertex-color pair in the original set.
Compute the existential projection of this relation to the vertex component. I.e. returns a set of vertices such that for each vertex, there is at least one vertex-color pair in the original set.
Retain only those vertex-color pairs for which the color is also contained in the given colors
set.
Retain only those vertex-color pairs for which the vertex is also contained in the given vertex
set.
Remove all vertex-color pairs for which the color is present in the given colors
set.
Pick a subset of this relation such that each color that is in the original relation is only present with a single vertex in the result relation.
I.e. for each color
that appears in this set, result.intersect_colors(color)
is a singleton.
Pick a subset of this relation such that each vertex that is in the original relation is only present with a single color in the result relation.
I.e. for each vertex
that appears in this set, result.intersect_vertices(vertex)
is a singleton.
Deterministically pick a subset of this set that contains exactly a single vertex-color pair.
If this set is empty, the result is also empty.
Returns an iterator over all interpretation-vertex pairs in this ColoredVertexSet
relation, with an optional
projection to a subset of network variables and uninterpreted functions.
When no retained
collections are specified, this is equivalent to ColoredVertexSet.__iter__
. However, if
a retained collection is given, the resulting iterator only considers unique combinations of the retained
functions and variables. Consequently, the resulting ColorModel
and VertexModel
instances will fail with
an IndexError
if a value outside the retained
set is requested.
Note that if you set retained_variables = []
and retained_functions = None
, this is equivalent to
set.colors().items()
. Similarly, with retained_variables = None
and retained_functions = []
, this is
equivalent to set.vertices().items()
.
A symbolic representation of a colored relation of "spaces", i.e. hypercubes in the state space
of a particular partially specified BooleanNetwork
together with the instantiations of
individual interpretations of network parameters.
Normally, a new ColoredSpaceSet
is derived using an SymbolicSpaceContext
. However, in some
cases you may want to create it manually from a SymbolicSpaceContext
and a Bdd
.
Just keep in mind that this method does not check that the provided Bdd
is semantically
a valid colored set of vertices.
Returns the number of space-color pairs that are represented in this set.
True if this set is a subset of the other set.
Should be faster than just calling set.minus(superset).is_empty()
Compute the existential projection of this relation to the color component. I.e. returns a set of colors such that for each color, there is at least one space-color pair in the original set.
Compute the existential projection of this relation to the subspace component. I.e. returns a set of spaces such that for each space, there is at least one space-color pair in the original set.
Retain only those space-color pairs for which the color is also contained in the given colors
set.
Retain only those space-color pairs for which the space is also contained in the given spaces
set.
Remove all space-color pairs for which the color is present in the given colors
set.
Remove all space-color pairs for which the space is present in the given spaces
set.
Pick a subset of this relation such that each color that is in the original relation is only present with a single vertex in the result relation.
I.e. for each color
that appears in this set, result.intersect_colors(color)
is a singleton.
Pick a subset of this relation such that each space that is in the original relation is only present with a single color in the result relation.
I.e. for each space
that appears in this set, result.intersect_spaces(space)
is a singleton.
Deterministically pick a subset of this set that contains exactly a single space-color pair.
If this set is empty, the result is also empty.
Returns an iterator over all interpretation-space pairs in this ColoredSpaceSet
relation, with an optional
projection to a subset of network variables and uninterpreted functions.
When no retained
collections are specified, this is equivalent to ColoredSpaceSet.__iter__
. However, if
a retained collection is given, the resulting iterator only considers unique combinations of the retained
functions and variables. Consequently, the resulting ColorModel
and SpaceModel
instances will fail with
an IndexError
if a value outside the retained
set is requested.
Note that if you set retained_variables = []
and retained_functions = None
, this is equivalent to
set.colors().items()
. Similarly, with retained_variables = None
and retained_functions = []
, this is
equivalent to set.spaces().items()
.
Produce a set of spaces that is a superset of this set, and in addition contains all spaces that are a subspace of some item in this set.
Colors are retained on a per-space basis.
A new AsynchronousGraph
is constructed from a BooleanNetwork
. Optionally, you can also provide
a SymbolicContext
(that is compatible with said network), or a unit_bdd
which restricts the set
of vertices and colors of the AsynchronousGraph
.
Note that the graph structure is immutable: if you change the original network, you have to create
a new AsynchronousGraph
.
Create a new AsynchronousGraph
whose SymbolicContext
contains enough additional
symbolic variables to model-check the requirement
HCTL formula (or explicit
quantified variable count).
This uses the "extra" variables supported by the SymbolicContext
object and hence
cannot be used with other features that also rely on "extra" variables
(like SymbolicSpaceContext
).
Note that the symbolic representation in the resulting AsynchronousGraph
likely
won't be compatible with the "default" AsynchronousGraph
either. However, you can
translate between these representations using AsynchronousGraph.transfer_from
.
The VariableId
identifiers of the network variables.
Return a VariableId
of the specified network variable, assuming such variable exists.
Try to reconstruct the underlying BooleanNetwork
from the symbolic functions of
this AsynchronousGraph
.
This is only possible when the graph does not use any non-trivial uninterpreted functions (i.e. arity more than zero), because there is no suitable way to reconstruct a function expression form a partially specified function. The only exception are implicit parameters (i.e. fully erased functions) that can be reconstructed as well.
Return a "unit" (i.e. full) ColoredVertexSet
.
Compute the set of colors where the function of the given id
outputs the specified
value
for the given input row
.
Note that this does not reflect the static constraints of the underlying network. It simply outputs all functions where given inputs evaluate to the given output.
Compute a set of colors that corresponds to the given function interpretation
(functions other than id
remain unconstrained).
Note that the result of this operation does not have to be a subset of
AsynchronousGraph.mk_unit_colors
. In other words, this method allows you to
also create instances of colors that represent valid functions, but are disallowed
by the regulation constraints.
The first argument must identify an unknown function (i.e. explicit or implicit parameter). The second argument then represents a Boolean function of the arity prescribed for the specified unknown function. Such a Boolean function can be represented as:
- A
BooleanExpression
(or a string that parses into aBooleanExpression
) which uses only variablesx_0 ... x_{A-1}
(A
being the function arity). - A
Bdd
that only depends on the firstA
symbolic variables.
In both cases, the support set of the function can be of course a subset of the prescribed
variables (e.g. x_0 | x_3
is allowed for a function with A=4
, even though x_1
and
x_2
are unused).
Transfer a symbolic set (ColorSet
, VertexSet
, or ColoredVertexSet
) from a compatible AsynchronousGraph
into the encoding of this graph.
Create a symbolic ColoredVertexSet
consisting of unit colors and vertices with the specified variables
fixed to their respective values.
Create a symbolic VertexSet
of vertices with the specified variables fixed to their respective values.
Compute the Bdd
representation of the update function that is associated with the given variable
.
Compute the set of direct successors of the given set
by updating the specified var
that are outside
of the given set
.
Compute the set of direct successors of the given set
by updating the specified var
that are within
the given set
.
Compute the set of direct predecessors of the given set
by updating the specified var
that are outside
of the given set
.
Compute the set of direct predecessors of the given set
by updating the specified var
that are within
the given set
.
Compute the subset of the given set
that has a successor by updating the variable var
that is outside
of the given set
.
Compute the subset of the given set
that has a successor by updating the variable var
that is within
the given set
.
Compute the subset of the given set
that has a predecessor by updating the variable var
that is outside
of the given set
.
Compute the subset of the given set
that has a predecessor by updating the variable var
that is within
the given set
.
Compute a version of the AsynchronousGraph
where the specified variable is inlined.
This is similar to BooleanNetwork.inline_variable
, but performs the operation
symbolically on the Bdd
update functions, not syntactically on the UpdateFunction
of the BooleanNetwork
.
As such, the result is often much smaller than the syntactic inlining. However, the
process does not produce an actual BooleanNetwork
and is slightly unusual in the
context of biodivine_aeon
: The new system uses new VariableId
identifiers,
shifted due to the removed network variable. However, to maintain compatibility
with the original AsynchronousGraph
, it uses the same underlying BddVariableSet
.
In other words, the variable is inlined inside the AsynchronousGraph
, but still
(theoretically) exists in the symbolic representation, it is just eliminated everywhere,
including the SymbolicContext
of the AsynchronousGraph
.
Currently, variables with a self-regulation cannot be inlined (raised a RuntimeError
).
Computes the coloured set of "essential" trap spaces of a Boolean network.
A trap space is essential if it cannot be further reduced through percolation. In general, every minimal trap space is always essential.
Computes the minimal coloured trap spaces of the provided network
within the specified
restriction
set.
Currently, this method always slower than [Self::essential_symbolic], because it first has to compute the essential set.
Iteratively compute the colored set of fixed-points in an AsynchronousGraph
that are the
subset of the restriction
set.
Iteratively compute the set of fixed-point vertices in an AsynchronousGraph
.
This is equivalent to FixedPoints.symbolic(graph, set).vertices()
, but can be
significantly faster because the projection is applied on-demand within the algorithm.
Iteratively compute the set of fixed-point vertices in an AsynchronousGraph
.
This is equivalent to FixedPoints.symbolic(graph, set).colors()
, but can be
significantly faster because the projection is applied on-demand within the algorithm.
Compute a subset of the given restriction
set that is guaranteed to be a superset
of all the attractors within the restriction
set.
Note that the attractor property is evaluated globally, not with respect to
the restriction
set. The restriction
set only specifies that the result must be
a subset of the input. If no restriction
is given, the whole state space is used.
Furthermore, note that the exact characterisation of the set
that is retained is a bit complicated. You shouldn't assume that the result is
a trap set or that it is forward/backward closed. Just that any attractor
that is a subset of restriction
is still a subset of the result.
You can limit which variables are reduced using the to_reduce
list. For example, for
some larger models, it may be sufficient to select a subset of variables.
Perform attractor detection on the given symbolic set.
This is similar to Attractors.attractors
, but it does not perform
Attractors.transition_guilded_reduction
. Instead, it directly runs the attractor
detection algorithm on the restriction
set without any preprocessing.
Note that the result is a collection of sets, such that for each set and each color holds that if the color is present in the set, the vertices of this color in the set together form an attractor. It is not guaranteed that this "decomposition" into colored sets is in some sense canonical (but the method should be deterministic). If you only care about attractor states and not individual attractors, you can simply merge all the sets together.
Compute the (colored) attractor set of the given AsynchronousGraph
.
See Attractors.xie_beerel
and Attractors.transition_guided_reduction
for relevant
documentation.
Performs a percolation of a single subspace.
Percolation propagates the values of variables that are guaranteed to be constant in the given subspace. Note that this function will not overwrite values fixed in the original space if they percolate to a conflicting value. Also note that the result is a subspace of the original space, i.e. it does not just contain the newly propagated variables.
This method should technically work on parametrized networks as well, but the constant check is performed across all interpretations, hence a lot of sub-spaces will not percolate meaningfully. We recommend using other symbolic methods for such systems.
An "algorithm object" that facilitates reachability procedures, i.e. iterative computation of successors (or predecessors) of a particular symbolic set.
Compute the (colored) set of vertices that are forward-reachable from the given initial set.
Note that this method should be faster than just iteratively calling
AsynchronousGraph.post
as it is based on the saturation technique.
Compute the (colored) set of vertices that are backward-reachable from the given initial set.
Note that this method should be faster than just iteratively calling
AsynchronousGraph.pre
as it is based on the saturation technique.
An "algorithm object" that can be used to compute symbolic constraints that correspond to typical properties of model regulations (i.e. monotonicity and essentiality).
However, you can use this to create symbolic constraints for arbitrary symbolic functions, not just the update functions of a BN.
Compute a Bdd
which is satisfied exactly by those function interpretations for which
the given function
is positively monotonous in the specified input variable
.
Note that the result only depends on the "parameter" variables of the given
SymbolicContext
. You can thus directly convert it to a ColorSet
by calling
ColorSet(context, result)
.
Also note that (at the moment), the input variable must be one of the network variables. For example, it cannot be one of the extra variables.
You can also use this function to check if a non-parametrized function is monotonous:
simply check if the resulting Bdd
is a true
function.
Compute a Bdd
which is satisfied exactly by those function interpretations for which
the given function
is negatively monotonous in the specified input variable
.
Note that the result only depends on the "parameter" variables of the given
SymbolicContext
. You can thus directly convert it to a ColorSet
by calling
ColorSet(context, result)
.
Also note that (at the moment), the input variable must be one of the network variables. For example, it cannot be one of the extra variables.
You can also use this function to check if a non-parametrized function is monotonous:
simply check if the resulting Bdd
is a true
function.
Compute a Bdd
which is satisfied exactly by those function interpretations for which
the given function
is has the specified variable
as an essential input (i.e. it
plays a role in the function's outcome).
Note that the result only depends on the "parameter" variables of the given
SymbolicContext
. You can thus directly convert it to a ColorSet
by calling
ColorSet(context, result)
.
Also note that (at the moment), the input variable must be one of the network variables. For example, it cannot be one of the extra variables.
You can also use this function to check if a non-parametrized function has an essential
input: simply check if the resulting Bdd
is a true
function.
This method takes a symbolic (parametrized) function
and two network variables
(source
and target
).
It assumes the symbolic function
represents the update function of the target
variable. It then tries to infer the most specific IdRegulation
that is valid for
every interpretation of the provided function.
If the function is not parametrized, this simply infers the monotonicity and essentiality
of source
in the given function.
Note that the function returns None
if no interpretation of the function depends on
source
. It returns essential=False
only when the function has more than one
interpretation, such that some depend on source
, but not all.
Represents the syntax tree of a HCTL formula.
The string format for representing these formulas is available on the repository site of the original Rust library.
Note that this format uses ~
instead of !
to represent negation (compared to other
expression formats used in AEON).
Create a new HctlFormula
, either parsing it from a string, or as a copy of an existing formula.
If allow_extended
is specified, the parser will also recognize "extended" propositions
(denoted %prop%
) that can be used to reference pre-computed symbolic sets.
If minimize_with
is specified with a SymbolicContext
, the created formula is
automatically converted to a canonical format, using standardized variable names and
removing redundancies (for this, a SymbolicContext
is required in order to check
the mapping between hybrid state variables and their symbolic representation).
Create a new HctlFormula
that uses a hybrid operator (see also HybridOperator
).
Optionally, you can provide a named domain
which further restricts the validity
of the operator. Note that such formulas have separate pattern matching methods
(e.g. HctlFormula.is_hybrid_in
instead of HctlFormula.is_hybrid
).
Create a new HctlFormula
that uses the 3{x}
operator.
Optionally, you can provide a named domain
which further restricts the validity
of the operator (i.e. it creates the 3{x} in %domain%
operator). Note that such
formulas have separate pattern matching methods (e.g. HctlFormula.is_exists_in
instead of HctlFormula.is_exists
).
Create a new HctlFormula
that uses the V{x}
operator.
Optionally, you can provide a named domain
which further restricts the validity
of the operator (i.e. it creates the V{x} in %domain%
operator). Note that such
formulas have separate pattern matching methods (e.g. HctlFormula.is_forall_in
instead of HctlFormula.is_forall
).
Create a new HctlFormula
that uses the !{x}
operator.
Optionally, you can provide a named domain
which further restricts the validity
of the operator (i.e. it creates the !{x} in %domain%
operator). Note that such
formulas have separate pattern matching methods (e.g. HctlFormula.is_forall_in
instead of HctlFormula.is_forall
).
Create a new HctlFormula
that uses the @{x}
operator.
Create a new HctlFormula
that uses a temporal operator (see TemporalUnaryOperator
and
TemporalBinaryOperator
).
For unary operators, provide only one HctlFormula
. For binary operators, provide
both formulas.
Create a new HctlFormula
that uses a binary Boolean operator (see BinaryOperator
).
Create a new HctlFormula
that uses the &
operator.
Create a new HctlFormula
that uses the |
operator.
Create a new HctlFormula
that uses the =>
operator.
Create a new HctlFormula
that uses the <=>
operator.
Create a new HctlFormula
that uses the ^
operator.
Create a new HctlFormula
that uses the EX
operator.
Create a new HctlFormula
that uses the AX
operator.
Create a new HctlFormula
that uses the EF
operator.
Create a new HctlFormula
that uses the AF
operator.
Create a new HctlFormula
that uses the EG
operator.
Create a new HctlFormula
that uses the AG
operator.
Create a new HctlFormula
that uses the EU
operator.
Create a new HctlFormula
that uses the AU
operator.
Create a new HctlFormula
that uses the EW
operator.
Create a new HctlFormula
that uses the AW
operator.
Create a new HctlFormula
that represents a quantified state variable.
Create a new HctlFormula
that represents a network variable proposition.
Create a new HctlFormula
that represents a Boolean constant.
Create a new HctlFormula
that represents an extended proposition.
Check if this HctlFormula
represents on of the hybrid operators without a domain
restriction (see HybridOperator
).
Check if this HctlFormula
represents on of the hybrid operators with a domain
restriction (see HybridOperator
).
Check if this HctlFormula
represents on of the temporal operators (see TemporalUnaryOperator
and TemporalBinaryOperator
).
Check if this HctlFormula
represents on of the unary temporal operators (see TemporalUnaryOperator
).
Check if this HctlFormula
represents on of the binary temporal operators (see TemporalBinaryOperator
).
Check if this HctlFormula
represents on of the binary Boolean operators (see BinaryOperator
).
Check if this HctlFormula
represents a quantified state proposition.
Check if this HctlFormula
represents a network variable proposition.
Return the operator, variable and argument if this HctlFormula
represents a
hybrid operator without domain restriction.
Return the operator, variable, domain and argument if this HctlFormula
represents a
hybrid operator with domain restriction.
Return the operator and argument if this HctlFormula
represents a unary temporal operator.
Return the operator and arguments if this HctlFormula
represents a binary temporal operator.
Return the operator and arguments if this HctlFormula
represents a binary Boolean operator.
Return the variable name if this HctlFormula
represents a state variable proposition.
Return the variable name if this HctlFormula
represents a network variable proposition.
Return the Boolean value if this HctlFormula
represents a constant.
Return the property name if this HctlFormula
represents an extended proposition (%name%
).
Return the state variable name and the child formula if this HctlFormula
represents
the 3{x}
hybrid operator.
(This method returns None
if the formula represents the 3{x} in %domain%
operator.)
Return the state variable name, domain name, and the child formula if this
HctlFormula
represents the 3{x} in %domain%
hybrid operator.
Return the state variable name and the child formula if this HctlFormula
represents
the V{x}
hybrid operator.
(This method returns None
if the formula represents the V{x} in %domain%
operator.)
Return the state variable name, domain name, and the child formula if this
HctlFormula
represents the V{x} in %domain%
hybrid operator.
Return the state variable name and the child formula if this HctlFormula
represents
the !{x}
hybrid operator.
(This method returns None
if the formula represents the !{x} in %domain%
operator.)
Return the state variable name, domain name, and the child formula if this
HctlFormula
represents the !{x} in %domain%
hybrid operator.
Return the state variable name and the child formula if this HctlFormula
represents
the @{x}
hybrid operator.
Return the child formula if this HctlFormula
represents the ~
operator.
Return the two child formulas if this HctlFormula
represents the &
Boolean operator.
Return the two child formulas if this HctlFormula
represents the |
Boolean operator.
Return the two child formulas if this HctlFormula
represents the =>
Boolean operator.
Return the two child formulas if this HctlFormula
represents the <=>
Boolean operator.
Return the two child formulas if this HctlFormula
represents the ^
Boolean operator.
Return the child formula if this HctlFormula
represents the EX
temporal operator.
Return the child formula if this HctlFormula
represents the AX
temporal operator.
Return the child formula if this HctlFormula
represents the EF
temporal operator.
Return the child formula if this HctlFormula
represents the AF
temporal operator.
Return the child formula if this HctlFormula
represents the EG
temporal operator.
Return the child formula if this HctlFormula
represents the AG
temporal operator.
Return the two child formulas if this HctlFormula
represents the EU
temporal operator.
Return the two child formulas if this HctlFormula
represents the AU
temporal operator.
Return the two child formulas if this HctlFormula
represents the EW
temporal operator.
Return the two child formulas if this HctlFormula
represents the AW
temporal operator.
Returns True
if the provided AsynchronousGraph
has enough extra symbolic variables
such that it can be used to model-check this HctlFormula
.
Returns the set of HCTL state variables that are used in this formula.
Returns the set of extended property names and domain names that are used in this formula.
Return the direct child sub-formulas of this HctlFormula
(one child for unary and hybrid
operators, two children for binary operators, no children for atoms).
For binary operators, the left-most child is returned first.
Return the string representation of the operator used by this HctlFormula
, or None
if this is an atom.
Verify the provided HCTL formula or formulas, returning the vertex-color pairs for which the property holds.
The property argument can be either a single formula (str
or HctlFormula
), in which
case the result is a single ColoredVertexSet
. Alternatively, you can provide a list
of formulas, in which case the result is a list[ColoredVertexSet]
.
If the formulas contain extended propositions or quantifier domains, you should provide
a substitution
map which assigns each proposition a set of valid vertex-color pairs
(the algorithm fails if the used extended propositions cannot be resolved).
The following only applies to HCTL formulas that use quantified state variables (i.e. "plain" CTL formulas do not need this):
Note that the provided AsynchronousGraph
must contain enough symbolic variables
to successfully represent all quantified variables in the provided formulae. You can
create such graph using AsynchronousGraph.mk_for_model_checking
, or by manually creating
enough extra symbolic variables for each variable in the SymbolicContext
.
The resulting ColoredVertexSet
uses the symbolic encoding of the provided
AsynchronousGraph
that supports the extra symbolic variables necessary for model
checking. If you want to output the result in a way that is compatible with the "default"
AsynchronousGraph
representation (i.e. AsynchronousGraph(network)
), you can use
AsynchronousGraph.transfer_from
to translate the sets into the "default"
symbolic encoding.
A Class
is an immutable collection of sorted "features", such that each feature is
a described by its string name. A Class
is used by the various classification workflows
in AEON to label a specific mode of behavior that a system can exhibit.
Depending on which operations are used, a class can behave either as a set
(each feature
can only appear once in a Class
), or a list
(multiple features of the same name appear
multiple times). This entirely depends on the classification workflow used and is not
a property of a Class
itself (you can even mix the set
and list
behavior depending on
the exact feature you are adding). Note that an "empty" class is allowed.
The main reason why we even need Class
is that lists and sets are not hash-able in Python,
hence we can't use them as keys in dictionaries. Because Class
is immutable, it has a stable
hash and is safe to use as a dictionary key.
Create a Class
from a list
of string features.
The items
are sorted, but duplicates are not removed.
Return the list
of features, including duplicates, that appear in this Class
.
Count the number of times a given feature
appears in this Class
.
Create a Class
instance that extends this class with the given feature (or features).
If an added feature already exists (at least once), it is not added again.
Create a Class
instance where the given feature (or features) is added. If an added
feature already exists, it is added again.
Create a Class
with all occurrences of a particular feature (or features) removed.
An "algorithm object" that groups all methods related to the classification of various model properties.
Extend an existing classification
dictionary in such a way that every color
in the colors
set appears in a Class
with the specified features
.
For example: Extending { ['a']: [1,2,3], ['b']: [4,5,6] }
with 'a': [3,4]
results in
{
a: [1,2,3], ['b']: [5,6], ['a','b']: [4] }
.
This does not "increase" the number of times a feature appears in a class, it merely creates new classes if the feature is not present.
Extend an existing classification
dictionary in such a way that every color
in the colors
set has an additional features according to the specified Class
.
For example: Extending { ['a']: [1,2,3], ['b']: [4,5,6] }
with 'a': [3,4]
results in
{
a: [1,2], ['b']: [5,6], ['a','a']: [3], ['a','b']: [4] }
.
In other words, compared to Class.classification_ensure
, this does "increase" the number
of times a feature appears in a class.
Read the list of dynamic assertions from .aeon
model annotations.
An assertion typically encodes a HctlFormula
that must be satisfied by all
the relevant interpretations of a partially specified model.
The argument is either a ModelAnnotation
dictionary, a path to an existing model
file from which the annotations are extracted, or a multi-line string content that
directly represents the annotations.
Assertions appear as a #! dynamic_assertion: CONTENT
annotation
comments in the .aeon
file.
Read the list of dynamic properties from .aeon
model annotations.
A property typically encodes a HctlFormula
that is of interest in a particular model,
but is not necessarily satisfied by all relevant interpretations of a model. Each property
is identified by a name (first item in the tuple).
The argument is either a ModelAnnotation
dictionary, or a path to an existing model
file from which the annotations are extracted, or a multi-line string content that
directly represents the annotations.
Properties appear as a #! dynamic_property: NAME: CONTENT
annotation
comments in the .aeon
file.
Write the provided dynamic assertions into a ModelAnnotation
dictionary. Note that
this method does not modify any assertions that may already exist in the annotation
dictionary.
Assertions appear as a #! dynamic_assertion: CONTENT
annotation
comments in the .aeon
file.
Write the provided dynamic properties into a ModelAnnotation
dictionary. Note that
this method does not modify any properties that may already exist in the annotation
dictionary. If a property of the same name already exists, the method fails with
a RuntimeError
.
Properties appear as a #! dynamic_property: NAME: CONTENT
annotation
comments in the .aeon
file.
Save the classification results into a .zip
archive that can be analyzed by
the BN Classifier.
The annotations
dictionary is optional. If these include the HCTL properties and
assertions that were used to create the classification
dictionary, then the BN Classifier
will be able to show the exact properties in the UI. Otherwise, names of the classes
will be used.
Note that this method will automatically sanitize the ColorSet
objects such that they
use the "default" symbolic encoding for the provided network
.
Load a BN Classifier archive into a usable representation. The result includes:
- The original
BooleanNetwork
for which the classification is valid. - A classification mapping from (collections of) properties to sets of network interpretations.
- A
ModelAnnotation
object that can (optionally) contain the properties that were used to generate the classification.
Classify the interpretations (colors) of the provided component
based on their long-term
behavior. That is:
stable
: the component is a single state;cycle
: all states in the component form a single (deterministic) cycle (each state has exactly one successor).complex
: any other set of states that has a non-trivial structure.
Note that this method is primarily intended to be used with attractors, but can be
(in theory) also applied to any colored set of vertices. However, in such case, the
result will typically be the complex
behavior class.
However, the properties described above are only tested in a subgraph induced by the
vertices in the given component
. Hence, you can use the method to at least distinguish
between cycles and other complex components, or to quickly identify colors for which
a component is trivial (i.e. stable
).
Perform a full classification of attractor behavior in the given AsynchronousGraph
.
This is a generalization of Classification.classify_long_term_behavior
in the sense
that the result covers all attractors, not just one component. Note that the Class
instances produced by this process count the number of attractors of each behavior type.
If attractors are already known, or you wish to only consider a subset of attractors,
you can provide them through the optional attractors
argument.
Note that you can achieve similar results using
Classification.classify_long_term_behavior
and Classification.ensure
(or Classification.append
). However, this process is not limited to attractors
and can be potentially combined with other features (like HCTL properties).
Classify the individual attractors of an AsynchronousGraph
according to their affinity
to biological phenotypes.
This is similar to Classification.classify_phenotypes
, but it actually returns
per-attractor results instead of lumping all attractors of one phenotype into
a single class. This results in a sort-of nested classification, where each class
consists of entries for individual attractors, but each entry is itself a class
that describes the phenotypes of that particular attractor.
For example, given phenotypes "a"
and "b"
, the result could contain a class
Class(["Class(['a'])", "Class(['b'])", "Class(['a', 'b'])"])
. This means that there
are three attractors: One with only the "a" phenotype, one with only the "b" phenotype,
and one with both phenotypes. Note that the "inner" classes are encoded as strings
(you can convert such string into a proper class object by running
c = eval(class_string)
).
The meaning of oscillation_types
is the same as in Classification.classify_phenotypes
:
Forbidden
oscillation means the attractor must be a subset of the phenotype, allowed
oscillation means the attractor must intersect the phenotype, and required
oscillation
means that the attractor must intersect the phenotype, but can't be its subset.
Similar to Classification.classify_phenotypes
, the method allows you to provide
a collection of traps
that will be considered instead of the network attractors.
The method checks that these sets are indeed trap sets, but they do not have to be
minimal (i.e. attractors). If traps
are given, the classification treats each trap
set as a separate "attractor".
Finally, if count_multiplicity
is set to False
, the method will lump together
attractors that satisfy the same phenotypes, meaning the resulting Class
object
will only contain up to one instance of the same phenotype configuration. For example,
if I have two attractors, each satisfying phenotype "a"
, then by default the result
is a Class(["Class(['a'])", "Class(['a'])"])
(and this situation is different compared
to the case when I only have one such attractor). If I set count_multiplicity=False
,
the result will be Class(["Class(['a'])"])
, regardless of how many attractors actually
satisfy the "a"
phenotype.
Classify the colors of an AsynchronousGraph
according to their affinity to biological
phenotypes.
Each phenotype is given as an arbitrary VertexSet
, identified by a Class
instance.
Most often, phenotypes are described through pair-wise disjoint sub-spaces (see also
AsynchronousGraph.mk_subspace_vertices
). The result of this method then associates
each network color with a collection of phenotypes (i.e. Class
) that are attainable
in the corresponding fully instantiated network.
By default, the network exhibits a phenotype if it can stay in the phenotype set
forever (i.e. there exists at least one attractor that is fully in this set). However,
we also allow other types of phenotypes based on the PhenotypeOscillation
:
- [default]
forbidden
: There exists an attractor that is a subset of the given phenotypeVertexSet
(oscillation is forbidden). required
: There exists an attractor that intersects the phenotype set, but is not a proper subset (phenotype is visited intermittently).allowed
: There exists an attractor that intersects the phenotype set, but can be also a proper subset (i.e. the network either stays in the phenotype forever, or visits it intermittently, we don't care which one).
Colors that do not match any phenotype are returned with an empty class (i.e. Class([])
).
Note that this method does not count the number of attractors, and it can assign the
same attractor to multiple phenotypes (for example, a network with a fixed-point 111
exhibits both phenotype a=11*
and b=*11
, i.e. the network will be returned within
the class Class(['a','b'])
). This is usually not a problem for disjoint phenotypes with
forbidden oscillation, just beware that for more complex phenotypes,
you might need additional analysis of the relevant colors.
If you do also need to map attractors to phenotypes, have a look at
Classification.classify_attractor_phenotypes
.
You can (optionally) provide your own attractor states (or any other relevant
set of states) as the initial_trap
argument (the method assumes this is a trap set).
However, computing phenotype classification does not require precise knowledge of
attractors. Thus, it can be often much faster than exact attractor computation (especially
if the number of attractors is high). However, you can use this option to restrict the
input space if you want to explicitly ignore certain parts of the state space.
You can also combine the results of this analysis with other classifications (e.g.
attractor bifurcations, or HCTL properties) using Classification.ensure
or
Classification.append
.
Classify the behavior of the given graph
based on the specified
HctlFormula
properties.
Optionally, you can also give a collection of assertions that restrict the applicable graph colors.
Note that this method internally creates a dedicated AsynchronousGraph
with enough
symbolic variables to check all the provided properties/assertions. However, the results
are always transformed back into an encoding that is valid for the graph
that is given
as the first argument.
An extension of AsynchronousGraph
that admits various variable perturbations through
additional colors/parameters. Such graph can then be analyzed to extract control strategies
(perturbations) that are sufficient to achieve a particular outcome (an attractor or
a phenotype).
This representation is similar to SymbolicSpaceContext
in the sense that it introduces
additional variables into the symbolic encoding in order to encode more complex modes of
behavior in a BN. However, in this case, it is also necessary to modify the actual update
functions of the network. Hence, this implementation extends the AsynchronousGraph
directly.
To represent perturbations, AsynchronousPerturbedGraph
introduces the following
changes to the network dynamics:
- For each variable (that can be perturbed), we create an explicit Boolean "perturbation parameter".
- Implicit parameters are given explicit names, since we may need to augment the update functions of these variables with perturbation parameters.
- We maintain two versions of network dynamics: original (unperturbed), meaning the additional parameters have no impact on the update functions, and perturbed, where a variable is allowed to evolve only if it is not perturbed.
- This representation allows us to also encode sets of perturbations, since for a perturbed variable, we can use the state variable (that would otherwise be unused) to represent the value to which the variable is perturbed.
Note that this encoding does not implicitly assume any perturbation temporality (one-step, permanent, temporary). These aspects are managed by the analysis algorithms.
By default, PerturbationAsynchronousGraph
behaves as if all variables are unperturbed
and the newly introduced parameters are set to False
, i.e. unperturbed. The perturbation
parameters always appear in the symbolic encoding, they are just not considered in the update
functions. To access the "perturbed" dynamics,
see AsynchronousPerturbationGraph.to_perturbed
.
Build a new AsynchronousPerturbationGraph
for the given BooleanNetwork
. Optionally
also specify a list of variables that can be perturbed in the resulting graph
(otherwise all variables can be perturbed).
Reconstruct the BooleanNetwork
that represents the unperturbed dynamics of this graph.
The network does not contain any perturbation parameters.
(see also AsynchronousGraph.reconstruct_network
).
Return a "unit" (i.e. full) ColoredVertexSet
, with the perturbation
parameters all fixed to False
.
Return a "unit" (i.e. full) ColorSet
, with the perturbation
parameters all fixed to False
.
A version of AsynchronousGraph.mk_function_row_colors
that also fixes the perturbation
parameters for False
.
A version of AsynchronousGraph.mk_function_colors
that also fixes the perturbation
parameters for False
.
A version of AsynchronousGraph.mk_subspace
that also fixes the perturbation
parameters for False
.
A copy of the base BooleanNetwork
that was used to create this graph,
without additional perturbation parameters or any modification (e.g. still with all
implicit parameters).
A copy of the BooleanNetwork
with the extra perturbation parameters, but with the
update functions unaffected.
A copy of the BooleanNetwork
with the extra perturbation parameters and with the
update functions changed to reflect the perturbations.
A copy of the AsynchronousGraph
that represents the unperturbed asynchronous
dynamics of this network. It supports the additional parameters necessary to represent
perturbations, but does not actually use them in any meaningful way.
This is effectively the "parent" implementation of this instance, so you can already
access these methods directly by calling them on this graph. Just keep in mind that
methods that return color sets do not fix the perturbation parameters to False
in
the "parent" implementation.
A copy of the AsynchronousGraph
that represents the perturbed asynchronous
dynamics of this network. It supports the additional parameters necessary to represent
perturbations, and they do affect the state-transitions: In colors where a variable
is perturbed, it cannot be updated.
List of names of variables that can be perturbed in this graph.
Find the ParameterId
which corresponds to the synthetic parameter that is used to
encode that the given variable
is perturbed (i.e. fixed and cannot evolve).
The list of ParameterId
objects that identify the perturbation parameters
of this graph.
The dictionary of all VariableId
, BddVariable
identifier pairs that correspond to
the symbolic encoding of perturbation parameters of the respective network variables.
Compute the ColoredPerturbationSet
which causes the network to go from the source
state into one of the target
states.
In other words, if you fix all the variables prescribed by one of the resulting
perturbations in the source
state, you obtain one of the target
states.
This operation is mostly used internally in various control algorithms.
Create a ColorSet
with unconstrained perturbation parameters, meaning every variable
that is declared as perturbable can be actually perturbed.
Meanwhile, AsynchronousPerturbationGraph.mk_unit_colors
returns a color set where
perturbation parameters are set to False
to better resemble the behavior of a "normal"
AsynchronousGraph
.
Create a ColoredVertexSet
with unconstrained perturbation parameters, meaning every
variable that is declared as perturbable can be actually perturbed.
Meanwhile, AsynchronousPerturbationGraph.mk_unit_colored_vertices
returns a color set
where perturbation parameters are set to False
to better resemble the behavior of
a "normal" AsynchronousGraph
.
Create a singleton PerturbationSet
based on the given values of perturbable variables.
The difference between this method and AsynchronousPerturbationGraph.mk_perturbations
is in how missing values are treated: In mk_perturbations
, a variable with an unspecified
value is treated as unconstrained: i.e. it can be unperturbed, or perturbed to
False
/True
. Meanwhile, mk_perturbation
treats any unspecified value as unperturbed,
since the result must always represent a single perturbation.
Create a set of perturbations that match the given dictionary of values.
The dictionary should contain True
/False
for a perturbed variable and None
for
an unperturbed variable. If all perturbable variables are specified, the result is
a singleton set. If some of the perturbable variables is missing from the dictionary,
it is unconstrained and the result contains any perturbation that matches the description
w.r.t. the remaining (specified) variables.
Create a set of perturbations of the given exact size (in terms of perturbed variables).
If size
is greater or equal to the number of perturbable variables, the result is
equivalent to AsynchronousPerturbationGraph.mk_unit_perturbations
.
If the up_to
parameter is given, the result contains all perturbations up to (including)
the specified size.
Compute the robustness of the given color set w.r.t. the unit color set.
Note that this is essentially just set.cardinality() / unit.cardinality()
with some
additional measures taken to prevent floating point overflow with large numbers.
Inherited Members
- AsynchronousGraph
- mk_for_model_checking
- symbolic_context
- network_variable_count
- network_variable_names
- network_variables
- find_network_variable
- get_network_variable_name
- mk_empty_colored_vertices
- mk_empty_colors
- mk_empty_vertices
- mk_unit_vertices
- transfer_from
- mk_subspace_vertices
- mk_update_function
- post
- pre
- var_post
- var_post_out
- var_post_within
- var_pre
- var_pre_out
- var_pre_within
- can_post
- can_pre
- var_can_post
- var_can_post_out
- var_can_post_within
- var_can_pre
- var_can_pre_out
- var_can_pre_within
- inline_variable_symbolic
Represents a single perturbation stored in a PerturbationSet
(or a ColoredPerturbationSet
),
or a projection of said perturbation to the chosen variables.
Behaves like an immutable dictionary: Boolean variable values can be queried using
a VariableId
, a string name, or a BddVariable
. Values that are perturbable but not
perturbed return None
, while values that are not perturbable raise a KeyError
exception.
The actual "retained" network variables in this model.
This is the list of all network variables if no projection was applied.
Returns a dictionary of only the perturbed variables (identified by names) and their values.
The size of this perturbation. That is, the number of perturbed variables.
The list of values for individual variables from PerturbationModel.keys
.
The same as PerturbationModel.items
, but returns a dictionary instead.
The same as PerturbationModel.to_dict
, but the keys in the dictionary are names, not IDs.
Return the underlying BddPartialValuation
for this symbolic model.
Return a PerturbationSet
where all the variables are fixed according
to the values in this PerturbationModel
. Variables that are not present in the
PerturbationModel
are unrestricted.
A symbolic representation of a set of "perturbations". A perturbation specifies for each
variable whether it is fixed or not, and if it is fixed, it prescribes a value. To do so,
it uses a combination of state variables and perturbation parameters declared by an
AsynchronousPerturbationGraph
.
Internally, the representation therefore uses the state variables of the perturbable network
variables, plus the perturbation parameters. If a variable is not perturbed, the state variable
should remain unconstrained, as this is the most "natural" representation. However, this
introduces some issues in terms of cardinality computation and iterators, since we now have
to account for the fact that if a variable is unperturbed, it actually generates two
perturbation instances (one with state variable true
, one with false
). We generally
address this by manually fixing the state variable to false
within these operations.
Normally, a new PerturbationSet
is derived using an AsynchronousPerturbationGraph
. However, in some
cases you may want to create it manually from a AsynchronousPerturbationGraph
and a Bdd
.
Just keep in mind that this method does not check that the provided Bdd
is semantically
a valid set of spaces.
True if this set is a subset of the other set.
Should be faster than just calling set.minus(superset).is_empty()
Deterministically pick a subset of this set that contains exactly a single vertex.
If this set is empty, the result is also empty.
Obtain the internal representation of this PerturbationSet
, which uses the
AsynchronousPerturbationGraph
encoding. This is a colored set of vertices, where
the colors only depend on the perturbation parameters, and the vertices are only
constrained in case the variable is perturbed.
Extend this set of perturbations with all the colors from the given set.
This is essentially a cartesian product with the given ColorSet
.
Returns an iterator over all perturbations in this PerturbationSet
with an optional
projection to a subset of network variables.
When no retained
collection is specified, this is equivalent to
PerturbationSet.__iter__
. However, if a retained set is given, the resulting iterator
only considers unique combinations of the retained
variables. Consequently, the
resulting PerturbationModel
instances will fail with an IndexError
if a value of
a variable outside the retained
set is requested.
Similarly, IndexError
is raised if you request a value of a variable that is not
perturbable in the underlying AsynchronousPerturbationGraph
.
A symbolic representation of a colored set of "perturbations". A perturbation specifies for
each variable whether it is fixed or not, and if it is fixed, it prescribes a value. To do so,
it uses a combination of state variables and perturbation parameters declared by an
AsynchronousPerturbationGraph
. The colors then prescribes the interpretations of the
remaining network parameters.
Normally, a new ColoredPerturbationSet
is derived using an AsynchronousPerturbationGraph
. However, in some
cases you may want to create it manually from a AsynchronousPerturbationGraph
and a Bdd
.
Just keep in mind that this method does not check that the provided Bdd
is semantically
a valid colored set of vertices.
Returns the number of vertex-color pairs that are represented in this set.
True if this set is a subset of the other set.
Should be faster than just calling set.minus(superset).is_empty()
True if this set is a singleton, i.e. a single perturbation-color pair.
Compute the existential projection of this relation to the color component. I.e. returns a set of colors such that for each color, there is at least one perturbation-color pair in the original set.
Note that this also fixes perturbation parameters to False
, meaning the set no longer
meaningfully depends on them. However, they do still appear in the symbolic encoding
to ensure that the result is compatible with
the underlying AsynchronousPerturbationGraph
.
Compute the existential projection of this relation to the perturbation component. I.e. returns a set of perturbations such that for each perturbation, there is at least one perturbation-color pair in the original set.
Retain only those perturbation-color pairs for which the color is also contained in the
given colors
set.
Retain only those perturbation-color pairs for which the perturbation is also contained
in the given perturbations
set.
Remove all perturbation-color pairs for which the color is present in the
given colors
set.
Remove all perturbation-color pairs for which the perturbation is present in the
given perturbations
set.
Return the subset of this relation that has all the perturbations fixed according to the provided values.
To specify that a variable should be unperturbed, use "var": None
. Any variable that
should remain unrestricted should be completely omitted from the perturbations
dictionary. This is similar to AsynchronousPerturbationGraph.mk_perturbations
. If a
PerturbationModel
is given, only values that are omitted through projection will be
considered as unrestricted.
Return the set of colors for which the given perturbation exists in this set.
Note that here, we assume that the dictionary represents a single perturbation. Therefore,
any missing perturbable variables are treated as unperturbed. This is the same behavior
as in AsynchronousPerturbationGraph.mk_perturbation
. Similarly, if a PerturbationModel
is provided with some values eliminated through projection, these are assumed to be
unperturbed.
Return the global robustness of the given perturbation as represented in this colored set.
This is the fraction of colors for which the perturbation is present w.r.t. all colors
that are admissible in the unperturbed system. Note that this has no relation to the
total set of colors stored in this relation (i.e. set.colors()
).
Note that here, we assume that the dictionary represents a single perturbation. Therefore, any missing perturbable variables are treated as unperturbed.
Only retain those perturbations that have the given size
. If up_to
is set to True
,
then retain perturbations that have smaller or equal size.
This is similar to AsynchronousPerturbationGraph.mk_perturbations_with_size
.
Select all perturbations from this relation whose robustness is at least the given
threshold
.
Since this operation cannot be completed symbolically, the result is a list of explicit
PerturbationModel
instances, together with their robustness and their ColorSet
.
The perturbations are returned from smallest to largest (in terms of the number of
perturbed variables, not robustness). Optionally, you can use result_limit
to restrict
the maximal number of returned perturbations.
You can also use ColoredPerturbationSet.select_by_size
to first only select perturbations
of a specific size and only then enumerate their robustness.
Deterministically pick a subset of this set that contains exactly a single perturbation-color pair.
If this set is empty, the result is also empty.
Obtain the internal representation of this ColoredPerturbationSet
, which uses the
AsynchronousPerturbationGraph
encoding. This is a colored set of vertices, where
the colors depend on the perturbation parameters and normal parameters, but the vertices
are only constrained in case the variable is perturbed.
Returns an iterator over all perturbation-color pairs in this ColoredPerturbationSet
relation, with an optional projection to a subset of network variables and
uninterpreted functions.
Note that the perturbation parameters are automatically projected away from the
returned ColorModel
instances.
When no retained
collections are specified, this is equivalent to
ColoredPerturbationSet.__iter__
. However, if a retained collection is given, the
resulting iterator only considers unique combinations of the retained
functions and variables. Consequently, the resulting ColorModel
and PerturbationModel
instances will fail with an IndexError
if a value outside the retained
set
is requested (for the PerturbationModel
, IndexError
is also thrown if a value
of a variable that is not perturbable is requested).
Note that if you set retained_variables = []
and retained_functions = None
, this is
equivalent to set.colors().items()
. Similarly, with retained_variables = None
and
retained_functions = []
, this is equivalent to set.perturbations().items()
.
Compute the color-perturbation pairs which guarantee that the network reaches
a target
attractor from the given source
state, assuming the perturbation is applied
for a single time step.
Optionally, you can provide a subset of relevant colors
that will be considered. If not
given, the method considers all colors.
Compute the color-perturbation pairs which guarantee that the network reaches
a target
attractor from the given source
state, assuming the perturbation is applied
indefinitely, but the system eventually returns to its original dynamics.
Optionally, you can provide a subset of relevant colors
that will be considered. If not
given, the method considers all colors.
Compute the color-perturbation pairs which guarantee that the network reaches
a target
attractor from the given source
state, assuming the perturbation is applied
indefinitely.
Optionally, you can provide a subset of relevant colors
that will be considered. If not
given, the method considers all colors.
Compute the color-perturbation pairs which guarantee that the network reaches the
specified target phenotype
from any initial state, assuming the perturbation
is applied indefinitely.
Optionally, you can provide an PhenotypeOscillation
type that specifies whether the attractors
must fully reside in the phenotype
set (forbidden
), can only intersect the
phenotype set but still be proper subsets (allowed
), or must intersect the phenotype
while not being subsets (required
). Default behavior is forbidden
,
i.e. each attractor fully resides in the phenotype
set.
To reduce the search space (and speed up the computation), you can also specify an
size_limit
constraint (only perturbations that are smaller or equal will be considered).
Furthermore, if stop_when_found
is set, the method terminates early if a perturbation
with robustness 1.0
is discovered (i.e. a perturbation is found that is effective for
all network colors). When this option is active, other results that have been computed
so far are still returned.