mpbn 3.3__py3-none-any.whl → 3.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mpbn might be problematic. Click here for more details.

mpbn/converters.py ADDED
@@ -0,0 +1,87 @@
1
+ import networkx as nx
2
+ from pyeda.boolalg.minimization import *
3
+ import pyeda.boolalg.expr
4
+ from pyeda.inter import expr
5
+
6
+ from colomoto import minibn
7
+
8
+ def expr2str(ex):
9
+ """
10
+ converts a pyeda Boolean expression to string representation
11
+ """
12
+ def _protect(e):
13
+ if isinstance(e, (pyeda.boolalg.expr.OrOp, pyeda.boolalg.expr.AndOp)):
14
+ return f"({expr2str(e)})"
15
+ return expr2str(e)
16
+ if isinstance(ex, pyeda.boolalg.expr.Variable):
17
+ return str(ex)
18
+ elif isinstance(ex, pyeda.boolalg.expr._One):
19
+ return "1"
20
+ elif isinstance(ex, pyeda.boolalg.expr._Zero):
21
+ return "0"
22
+ elif isinstance(ex, pyeda.boolalg.expr.Complement):
23
+ return f"!{_protect(ex.__invert__())}"
24
+ elif isinstance(ex, pyeda.boolalg.expr.NotOp):
25
+ return f"!{_protect(ex.x)}"
26
+ elif isinstance(ex, pyeda.boolalg.expr.OrOp):
27
+ return " | ".join(map(_protect, ex.xs))
28
+ elif isinstance(ex, pyeda.boolalg.expr.AndOp):
29
+ return " & ".join(map(_protect, ex.xs))
30
+ raise NotImplementedError(str(ex), type(ex))
31
+
32
+
33
+ def bn_of_asynchronous_transition_graph(adyn, names,
34
+ parse_node=(lambda n: tuple(map(int, n))),
35
+ bn_class=minibn.BooleanNetwork,
36
+ simplify=True):
37
+ """
38
+ Convert the transition graph of a (fully) asynchronous Boolean network to
39
+ a propositional logic representation.
40
+
41
+ The object `adyn` must be an instance of `networkx.DiGraph`.
42
+ The `parse_node` function must return a tuple of 0 and 1 from an `adyn`
43
+ node. By default, it is assumed that nodes are strings of binary values.
44
+ Returned object will be of `bn_class`, instantiated with a dictionnary
45
+ mapping component names to a string representation of their Boolean expression.
46
+ """
47
+ relabel = {label: parse_node(label) for label in adyn.nodes()}
48
+ adyn = nx.relabel_nodes(adyn, relabel)
49
+ n = len(next(iter(adyn.nodes)))
50
+ assert n == len(names), "list of component names and dimension of configuraitons seem different"
51
+ assert adyn.number_of_nodes() == 2**n, "unexpected number of nodes in the transition graph"
52
+
53
+ def expr_of_cfg(x):
54
+ e = "&".join(f"{'~' if not v else ''}{names[i]}" for i, v in enumerate(x))
55
+ return f"({e})"
56
+
57
+ f = []
58
+ for i in range(n):
59
+ pos = []
60
+ for x in adyn.nodes():
61
+ dx = list(x)
62
+ dx[i] = 1-x[i]
63
+ y = dx if tuple(dx) in adyn[x] else x
64
+ target = y[i]
65
+ if target:
66
+ pos.append(x)
67
+ if not pos:
68
+ f.append(expr("0"))
69
+ else:
70
+ e = expr("|".join(map(expr_of_cfg,pos)))
71
+ e, = espresso_exprs(e.to_dnf())
72
+ f.append(e)
73
+ f = map(expr2str, f)
74
+ f = bn_class(dict(zip(names, f)))
75
+ if simplify:
76
+ f = f.simplify()
77
+ return f
78
+
79
+ if __name__ == "__main__":
80
+ import mpbn
81
+
82
+ f = mpbn.MPBooleanNetwork({
83
+ "x1": "x2",
84
+ "x2": "x3",
85
+ "x3": "x1"})
86
+ g = f.dynamics("asynchronous")
87
+ print(bn_of_asynchronous_transition_graph(g, list(f)))
mpbn/simulation.py CHANGED
@@ -177,14 +177,14 @@ def step(f, mem, x, depth, W):
177
177
  sample_configuration(f, mem, x, S, W)
178
178
  return True
179
179
 
180
-
181
180
  def is_subhypercube(a, b):
182
181
  x, H = a
183
182
  y, G = b
184
183
  return H.issubset(G) and \
185
184
  not [i for i in set(x).difference(G) if x[i] != y[i]]
186
185
 
187
- def sample_reachable_attractor(f, mem, x, A, depth, W, refresh_rate=10):
186
+ def sample_reachable_attractor(f, mem, x, A, depth, W, refresh_rate=10, emit=None):
187
+ if not isinstance(f, MPBNSim): f = MPBNSim(f)
188
188
  I = set(f)
189
189
  n = len(f)
190
190
  def filter_reachable_attractors(A, x):
@@ -194,6 +194,8 @@ def sample_reachable_attractor(f, mem, x, A, depth, W, refresh_rate=10):
194
194
  x = x.copy()
195
195
  A = filter_reachable_attractors(A, x)
196
196
  while len(A) > 1:
197
+ if emit is not None:
198
+ emit(x)
197
199
  if not step(f, mem, x, depth, W):
198
200
  k = 0
199
201
  if k % refresh_rate == 0:
@@ -201,6 +203,48 @@ def sample_reachable_attractor(f, mem, x, A, depth, W, refresh_rate=10):
201
203
  k += 1
202
204
  return A[0][0]
203
205
 
206
+ def sample_trace(f, mem, x, A, depth, W):
207
+ if not isinstance(f, MPBNSim): f = MPBNSim(f)
208
+ I = set(f)
209
+ n = len(f)
210
+ def filter_reachable_attractors(A, x):
211
+ H = spread(f, x, I, n)
212
+ return [(ia,a) for (ia,a) in A if is_subhypercube(a, (x,H))]
213
+ k = 1
214
+ x = x.copy()
215
+ trace = list()
216
+ trace.append(x.copy())
217
+ A = filter_reachable_attractors(A, x)
218
+ while len(A) and x != A[0][1][0]:
219
+ step(f, mem, x, depth, W)
220
+ trace.append(x.copy())
221
+ A = filter_reachable_attractors(A, x)
222
+ return trace
223
+
224
+
225
+ def sample_switchpoint(f, mem, x, A, depth, W):
226
+ """ experimental: sample a trace and stop at an attractor's
227
+ strong bassin, returning the attractor as well."""
228
+ if not isinstance(f, MPBNSim): f = MPBNSim(f)
229
+ I = set(f)
230
+ n = len(f)
231
+ def filter_reachable_attractors(A, x):
232
+ H = spread(f, x, I, n)
233
+ return [(ia,a) for (ia,a) in A if is_subhypercube(a, (x,H))]
234
+
235
+ names = lambda _A: set(_a_name for _a_name, _a_cfg in _A)
236
+ k = 1
237
+ x = x.copy()
238
+ trace = list()
239
+ A = filter_reachable_attractors(A, x)
240
+ trace.append((x.copy(), names(A)))
241
+ while len(A) > 1:
242
+ step(f, mem, x, depth, W)
243
+ A = filter_reachable_attractors(A, x)
244
+ trace.append((x.copy(), names(A)))
245
+ #return [*trace, [a_name for a_name, a_x in A]]
246
+ return trace
247
+
204
248
  def convert_attractor(A):
205
249
  H = {i for i,v in A.items() if v == '*'}
206
250
  x = {i:v for i,v in A.items() if v != '*'}
@@ -307,6 +351,7 @@ def nexponential_depth(f, base=2):
307
351
  ##
308
352
  ## Rates
309
353
  ##
354
+ ## TODO: resolve this
310
355
  def uniform_rates(f):
311
356
  """
312
357
  Returns 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mpbn
3
- Version: 3.3
3
+ Version: 3.5
4
4
  Summary: Simple implementation of Most Permissive Boolean networks
5
5
  Home-page: https://github.com/bnediction/mpbn
6
6
  Author: Loïc Paulevé
@@ -20,7 +20,7 @@ Requires-Dist: scipy
20
20
  Requires-Dist: tqdm
21
21
 
22
22
 
23
- The `mpbn` Python module offers a simple implementation of reachability and attractor analysis (minimal trap spaces) in *Most Permissive Boolean Networks* ([doi:10.1038/s41467-020-18112-5](https://doi.org/10.1038/s41467-020-18112-5)).
23
+ The `mpbn` Python module offers a simple implementation of reachability and attractor analysis (minimal trap spaces) in *Most Permissive Boolean Networks* ([doi:10.1038/s41467-020-18112-5](https://doi.org/10.1038/s41467-020-18112-5)). The `mpbn` Python module also offers a *Most Permissive* simulator, which provides trajectory sampling and computes attractor propensities (see paper [Variable-Depth Simulation of Most Permissive Boolean Networks](https://link.springer.com/chapter/10.1007/978-3-031-15034-0_7) for more details).
24
24
 
25
25
  It is built on the `minibn` module from [colomoto-jupyter](https://github.com/colomoto/colomoto-jupyter) which allows importation of Boolean networks in many formats. See http://colomoto.org/notebook.
26
26
 
@@ -1,5 +1,6 @@
1
1
  mpbn/__init__.py,sha256=oPey2_tk0ymBGwiL9dcG88Hk-vUuWH-gpmP7ZDwXyu4,20578
2
- mpbn/simulation.py,sha256=Ii6QpTeeQY278wruRYPY4rY8dBPYrMyb_9Fshzf1_Jo,9115
2
+ mpbn/converters.py,sha256=33mhsGnFkJL4PlqYMIKu3zNb5oCNT6ZLaK6xoj9WsI4,3034
3
+ mpbn/simulation.py,sha256=3lk6yu7k2POrSytmtnsGIh596B-qcAgBtl16iZ0vzM4,10594
3
4
  mpbn/asplib/eval_circuit.asp,sha256=5rIbkVmvobaQwE_gHr0_USccPuI0QUPuzfw_1011hSE,989
4
5
  mpbn/asplib/eval_mixed.asp,sha256=n23pbjtxuWSCerL36Gb6O32bx8_1ukc52l1hQMMs8OE,787
5
6
  mpbn/asplib/mp_attractor.asp,sha256=CawLNxlYBZG2cl8XQAxA6EXEZ89Y9iw20CZ73n97Nu8,185
@@ -14,8 +15,8 @@ tests/test_fixpoints.py,sha256=bdDttzimiby48nVkVL-HXZ2rBldICBRbIZrVVbTGfso,786
14
15
  tests/test_input.py,sha256=mwMKd5UwAIY4Z1uZjYr09Ue8DLxD52CiPSoE-iXytfo,337
15
16
  tests/test_reachability.py,sha256=X7anTwFSIYcV2rltJBOW8TcAJnrt3SjYLqttB0eIL_Q,588
16
17
  tests/test_reachable_attractors.py,sha256=h78kvgmx9rTJWi3r2DZe_abYDxr02MLJ2iLDJUdLESY,540
17
- mpbn-3.3.dist-info/METADATA,sha256=zBtRnfvK4rhv3l78c6LYlJQO166RQ87UTd9DgfJj8H4,1833
18
- mpbn-3.3.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
19
- mpbn-3.3.dist-info/entry_points.txt,sha256=CpzAc9SkB-mH_dojzt1N3YgDxy8hniDrIGzSHcPDo8g,68
20
- mpbn-3.3.dist-info/top_level.txt,sha256=oe3jlFHbQ6oIXyE1q7yAAnf1m49oP_jBPUU05d71n74,11
21
- mpbn-3.3.dist-info/RECORD,,
18
+ mpbn-3.5.dist-info/METADATA,sha256=I6viVUknNQ532Vya9eUX-6u_QuwxrQx-w59njI7srYQ,2129
19
+ mpbn-3.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
20
+ mpbn-3.5.dist-info/entry_points.txt,sha256=CpzAc9SkB-mH_dojzt1N3YgDxy8hniDrIGzSHcPDo8g,68
21
+ mpbn-3.5.dist-info/top_level.txt,sha256=oe3jlFHbQ6oIXyE1q7yAAnf1m49oP_jBPUU05d71n74,11
22
+ mpbn-3.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
File without changes