mpbn 3.4__tar.gz → 3.8__tar.gz
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.
- {mpbn-3.4 → mpbn-3.8}/PKG-INFO +1 -1
- {mpbn-3.4 → mpbn-3.8}/mpbn/__init__.py +129 -52
- {mpbn-3.4 → mpbn-3.8}/mpbn/cli/__init__.py +17 -6
- mpbn-3.8/mpbn/converters.py +87 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn.egg-info/PKG-INFO +1 -1
- {mpbn-3.4 → mpbn-3.8}/mpbn.egg-info/SOURCES.txt +1 -0
- {mpbn-3.4 → mpbn-3.8}/setup.py +1 -1
- {mpbn-3.4 → mpbn-3.8}/MANIFEST.in +0 -0
- {mpbn-3.4 → mpbn-3.8}/README.md +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn/asplib/eval_circuit.asp +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn/asplib/eval_mixed.asp +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn/asplib/mp_attractor.asp +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn/asplib/mp_eval.asp +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn/asplib/mp_positivereach-np.asp +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn/cli/sim.py +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn/simulation.py +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn.egg-info/dependency_links.txt +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn.egg-info/entry_points.txt +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn.egg-info/requires.txt +0 -0
- {mpbn-3.4 → mpbn-3.8}/mpbn.egg-info/top_level.txt +0 -0
- {mpbn-3.4 → mpbn-3.8}/setup.cfg +0 -0
{mpbn-3.4 → mpbn-3.8}/PKG-INFO
RENAMED
|
@@ -46,23 +46,20 @@ if hasattr(clingo, "version") and clingo.version() >= (5,5,0):
|
|
|
46
46
|
def aspf(basename):
|
|
47
47
|
return os.path.join(__asplibdir__, basename)
|
|
48
48
|
|
|
49
|
-
def
|
|
50
|
-
s = clingo.Control(clingo_options)
|
|
49
|
+
def _clingo_domrec(mod, limit=0, project=False, extra_opts=[]):
|
|
50
|
+
s = clingo.Control(clingo_options + extra_opts)
|
|
51
51
|
s.configuration.solve.models = limit
|
|
52
|
-
|
|
52
|
+
if project:
|
|
53
|
+
s.configuration.solve.project = 1
|
|
53
54
|
s.configuration.solve.enum_mode = "domRec"
|
|
54
55
|
s.configuration.solver[0].heuristic = "Domain"
|
|
55
|
-
s.configuration.solver[0].dom_mod = "
|
|
56
|
+
s.configuration.solver[0].dom_mod = f"{mod},{16 if project else 0}"
|
|
56
57
|
return s
|
|
57
58
|
|
|
58
|
-
def
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
s.configuration.solve.enum_mode = "domRec"
|
|
63
|
-
s.configuration.solver[0].heuristic = "Domain"
|
|
64
|
-
s.configuration.solver[0].dom_mod = "3,16"
|
|
65
|
-
return s
|
|
59
|
+
def clingo_subsets(**opts):
|
|
60
|
+
return _clingo_domrec(5, **opts)
|
|
61
|
+
def clingo_supsets(**opts):
|
|
62
|
+
return _clingo_domrec(3, **opts)
|
|
66
63
|
|
|
67
64
|
def clingo_exists():
|
|
68
65
|
s = clingo.Control(clingo_options)
|
|
@@ -325,13 +322,22 @@ class MPBooleanNetwork(minibn.BooleanNetwork):
|
|
|
325
322
|
facts.append(circuitasp_of_boolfunc(f, n, self.ba))
|
|
326
323
|
return "".join(facts)
|
|
327
324
|
|
|
328
|
-
def
|
|
325
|
+
def _file_eval(self):
|
|
329
326
|
if self.encoding == "circuit":
|
|
330
|
-
|
|
327
|
+
f = aspf("eval_circuit.asp")
|
|
331
328
|
elif self.encoding == "mixed-dnf-bdd":
|
|
332
|
-
|
|
329
|
+
f = aspf("eval_mixed.asp")
|
|
333
330
|
else:
|
|
334
|
-
|
|
331
|
+
f = aspf("mp_eval.asp")
|
|
332
|
+
return f
|
|
333
|
+
|
|
334
|
+
def rules_eval(self):
|
|
335
|
+
f = self._file_eval()
|
|
336
|
+
with open(f, "r") as fp:
|
|
337
|
+
return fp.read()
|
|
338
|
+
def load_eval(self, solver):
|
|
339
|
+
f = self._file_eval()
|
|
340
|
+
solver.load(f)
|
|
335
341
|
|
|
336
342
|
def assert_pc_encoding(self):
|
|
337
343
|
assert self.encoding not in self.nonpc_encodings, "Unsupported encoding"
|
|
@@ -340,8 +346,9 @@ class MPBooleanNetwork(minibn.BooleanNetwork):
|
|
|
340
346
|
facts = ["timepoint({},{}).".format(e,t)]
|
|
341
347
|
facts += [" mp_state({},{},\"{}\",{}).".format(e,t,n,s2v(s))
|
|
342
348
|
for (n,s) in c.items()]
|
|
343
|
-
facts += ["
|
|
344
|
-
|
|
349
|
+
facts += [f"1 {{mp_state({e},{t},N,(-1;1))}} 1 :- node(N)."]
|
|
350
|
+
#facts += [" 1 {{mp_state({},{},\"{}\",(-1;1))}} 1 :- node(N).".format(e,t,n)
|
|
351
|
+
# for n in self if n not in c]
|
|
345
352
|
return "".join(facts)
|
|
346
353
|
|
|
347
354
|
def reachability(self, x, y):
|
|
@@ -371,6 +378,32 @@ class MPBooleanNetwork(minibn.BooleanNetwork):
|
|
|
371
378
|
res = s.solve()
|
|
372
379
|
return res.satisfiable
|
|
373
380
|
|
|
381
|
+
def _ground_rules(self, ctl, rules):
|
|
382
|
+
rules = "\n".join(rules)
|
|
383
|
+
ctl.add("base", [], rules)
|
|
384
|
+
ctl.ground([("base",[])])
|
|
385
|
+
|
|
386
|
+
def _fixedpoints(self, reachable_from=None, constraints={}, limit=0):
|
|
387
|
+
e = "fp"
|
|
388
|
+
t2 = "fp"
|
|
389
|
+
rules = [self.asp_of_cfg(e, t2, constraints)]
|
|
390
|
+
rules.append(f"mp_reach({e},{t2},N,V) :- mp_state({e},{t2},N,V).")
|
|
391
|
+
rules.append(f":- mp_state({e},{t2},N,V), mp_eval({e},{t2},N,-V).")
|
|
392
|
+
rules.append(self.asp_of_bn())
|
|
393
|
+
if reachable_from:
|
|
394
|
+
self.assert_pc_encoding()
|
|
395
|
+
t1 = "0"
|
|
396
|
+
rules.append(open(aspf("mp_positivereach-np.asp")).read())
|
|
397
|
+
rules.append(self.asp_of_cfg(e,t1,reachable_from))
|
|
398
|
+
rules.append("is_reachable({},{},{}).".format(e,t1,t2))
|
|
399
|
+
rules.append(f"#show. #show fixpoint(N,V) : mp_state({e},{t2},N,V).")
|
|
400
|
+
rules.append(open(aspf("mp_eval.asp")).read())
|
|
401
|
+
|
|
402
|
+
project = reachable_from and set(self.keys()).difference(reachable_from)
|
|
403
|
+
s = clingo_enum(limit=limit, project=project)
|
|
404
|
+
self._ground_rules(s, rules)
|
|
405
|
+
return s
|
|
406
|
+
|
|
374
407
|
def fixedpoints(self, reachable_from=None, constraints={}, limit=0):
|
|
375
408
|
"""
|
|
376
409
|
Iterator over fixed points of the MPBN (i.e., of f)
|
|
@@ -383,23 +416,8 @@ class MPBooleanNetwork(minibn.BooleanNetwork):
|
|
|
383
416
|
the given constraints.
|
|
384
417
|
:param int limit: maximum number of solutions, ``0`` for unlimited.
|
|
385
418
|
"""
|
|
386
|
-
s =
|
|
387
|
-
|
|
388
|
-
e = "fp"
|
|
389
|
-
t2 = "fp"
|
|
390
|
-
self.load_eval(s)
|
|
391
|
-
s.add("base", [], self.asp_of_cfg(e, t2, constraints))
|
|
392
|
-
s.add("base", [], f"mp_reach({e},{t2},N,V) :- mp_state({e},{t2},N,V).")
|
|
393
|
-
s.add("base", [], f":- mp_state({e},{t2},N,V), mp_eval({e},{t2},N,-V).")
|
|
394
|
-
if reachable_from:
|
|
395
|
-
self.assert_pc_encoding()
|
|
396
|
-
t1 = "0"
|
|
397
|
-
s.load(aspf("mp_positivereach-np.asp"))
|
|
398
|
-
s.add("base", [], self.asp_of_cfg(e,t1,reachable_from))
|
|
399
|
-
s.add("base", [], "is_reachable({},{},{}).".format(e,t1,t2))
|
|
400
|
-
s.add("base", [], f"#show. #show fixpoint(N,V) : mp_state({e},{t2},N,V).")
|
|
401
|
-
|
|
402
|
-
s.ground([("base",[])])
|
|
419
|
+
s = self._fixedpoints(reachable_from=reachable_from,
|
|
420
|
+
constraints=constraints, limit=limit)
|
|
403
421
|
for sol in s.solve(yield_=True):
|
|
404
422
|
x = {n: None for n in self}
|
|
405
423
|
data = sol.symbols(shown=True)
|
|
@@ -413,36 +431,59 @@ class MPBooleanNetwork(minibn.BooleanNetwork):
|
|
|
413
431
|
x[n] = v
|
|
414
432
|
yield x
|
|
415
433
|
|
|
434
|
+
def count_fixedpoints(self, reachable_from=None, constraints={}, limit=0):
|
|
435
|
+
"""
|
|
436
|
+
Returns number of fixed points
|
|
416
437
|
|
|
417
|
-
|
|
438
|
+
:param dict[str,int] reachable_from: restrict to the attractors
|
|
439
|
+
reachable from the given configuration. Whenever partial, restrict
|
|
440
|
+
attractors to the one reachable by at least one matching
|
|
441
|
+
configuration.
|
|
442
|
+
:param dict[str,int] constraints: consider only attractors matching with
|
|
443
|
+
the given constraints.
|
|
444
|
+
:param int limit: maximum number of solutions, ``0`` for unlimited.
|
|
445
|
+
"""
|
|
446
|
+
s = self._fixedpoints(reachable_from=reachable_from,
|
|
447
|
+
constraints=constraints, limit=limit)
|
|
448
|
+
return sum((1 for _ in s.solve(yield_=True)))
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def _trapspaces(self, reachable_from=None, subcube={}, limit=0,
|
|
418
452
|
mode="min", exclude_full=False):
|
|
419
453
|
self.assert_pc_encoding()
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
self.
|
|
423
|
-
|
|
424
|
-
|
|
454
|
+
|
|
455
|
+
rules = []
|
|
456
|
+
rules.append(self.asp_of_bn())
|
|
457
|
+
rules.append(self.rules_eval())
|
|
458
|
+
rules.append(open(aspf("mp_attractor.asp")).read())
|
|
459
|
+
rules.append("#show attractor/2.")
|
|
460
|
+
|
|
425
461
|
e = "__a"
|
|
426
462
|
t2 = "final"
|
|
427
463
|
if exclude_full and not subcube:
|
|
428
|
-
|
|
464
|
+
rules.append(f"{{ mp_reach({e},{t2},N,(-1;1)): node(N) }} {len(self)*2-1}.")
|
|
429
465
|
if reachable_from:
|
|
430
466
|
t1 = "0"
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
467
|
+
rules.append(open(aspf("mp_positivereach-np.asp")).read())
|
|
468
|
+
rules.append(self.asp_of_cfg(e,t1,reachable_from))
|
|
469
|
+
rules.append("is_reachable({},{},{}).".format(e,t1,t2))
|
|
470
|
+
rules.append("mp_state({},{},N,V) :- attractor(N,V).".format(e,t2))
|
|
435
471
|
|
|
436
472
|
for n, b in subcube.items():
|
|
437
473
|
if isinstance(b, str):
|
|
438
474
|
b = int(b)
|
|
439
475
|
if b not in [0,1]:
|
|
440
476
|
continue
|
|
441
|
-
|
|
477
|
+
rules.append(":- mp_reach({},{},\"{}\",{}).".format(e,t2,n,s2v(1-b)))
|
|
442
478
|
|
|
443
|
-
|
|
479
|
+
project = reachable_from and set(self.keys()).difference(reachable_from)
|
|
480
|
+
solver = clingo_subsets if mode == "min" else clingo_supsets
|
|
481
|
+
s = solver(limit=limit, project=project)
|
|
482
|
+
self._ground_rules(s, rules)
|
|
483
|
+
return s
|
|
444
484
|
|
|
445
|
-
|
|
485
|
+
def _yield_trapspaces(self, *args, star="*", **kwargs):
|
|
486
|
+
s = self._trapspaces(*args, **kwargs)
|
|
446
487
|
for sol in s.solve(yield_=True):
|
|
447
488
|
attractor = {n: None for n in self}
|
|
448
489
|
data = sol.symbols(shown=True)
|
|
@@ -465,6 +506,10 @@ class MPBooleanNetwork(minibn.BooleanNetwork):
|
|
|
465
506
|
attractor[n] = v
|
|
466
507
|
yield attractor
|
|
467
508
|
|
|
509
|
+
def _count_trapspaces(self, *args, **kwargs):
|
|
510
|
+
s = self._trapspaces(*args, **kwargs)
|
|
511
|
+
return sum((1 for _ in s.solve(yield_=True)))
|
|
512
|
+
|
|
468
513
|
def attractors(self, reachable_from=None, constraints={}, limit=0, star='*'):
|
|
469
514
|
"""
|
|
470
515
|
Iterator over attractors of the MPBN (minimal trap spaces of the BN).
|
|
@@ -481,17 +526,49 @@ class MPBooleanNetwork(minibn.BooleanNetwork):
|
|
|
481
526
|
:param str star: value to use for components which are free in the
|
|
482
527
|
attractor
|
|
483
528
|
"""
|
|
484
|
-
return self.
|
|
529
|
+
return self._yield_trapspaces(reachable_from=reachable_from,
|
|
485
530
|
subcube=constraints, limit=limit, star=star,
|
|
486
531
|
mode="min")
|
|
487
|
-
|
|
488
532
|
minimal_trapspaces = attractors
|
|
489
533
|
|
|
490
534
|
def maximal_trapspaces(self, limit=0, subcube={}, star="*",
|
|
491
535
|
exclude_full=True):
|
|
492
|
-
return self.
|
|
536
|
+
return self._yield_trapspaces(subcube=subcube, limit=limit, star=star,
|
|
493
537
|
mode="max", exclude_full=exclude_full)
|
|
494
538
|
|
|
539
|
+
def count_attractors(self, reachable_from=None, constraints={}, limit=0):
|
|
540
|
+
"""
|
|
541
|
+
Returns number of attractors of the MPBN (minimal trap spaces of the BN).
|
|
542
|
+
|
|
543
|
+
:param dict[str,int] reachable_from: restrict to the attractors
|
|
544
|
+
reachable from the given configuration. Whenever partial, restrict
|
|
545
|
+
attractors to the one reachable by at least one matching
|
|
546
|
+
configuration.
|
|
547
|
+
:param dict[str,int] constraints: consider only attractors matching with
|
|
548
|
+
the given constraints.
|
|
549
|
+
:param int limit: maximum number of solutions, ``0`` for unlimited.
|
|
550
|
+
"""
|
|
551
|
+
return self._count_trapspaces(reachable_from=reachable_from,
|
|
552
|
+
subcube=constraints, limit=limit,
|
|
553
|
+
mode="min")
|
|
554
|
+
count_minimal_trapspaces = count_attractors
|
|
555
|
+
|
|
556
|
+
def count_maximal_trapspaces(self, reachable_from=None, constraints={}, limit=0):
|
|
557
|
+
"""
|
|
558
|
+
Returns number of attractors of the MPBN (minimal trap spaces of the BN).
|
|
559
|
+
|
|
560
|
+
:param dict[str,int] reachable_from: restrict to the attractors
|
|
561
|
+
reachable from the given configuration. Whenever partial, restrict
|
|
562
|
+
attractors to the one reachable by at least one matching
|
|
563
|
+
configuration.
|
|
564
|
+
:param dict[str,int] constraints: consider only attractors matching with
|
|
565
|
+
the given constraints.
|
|
566
|
+
:param int limit: maximum number of solutions, ``0`` for unlimited.
|
|
567
|
+
"""
|
|
568
|
+
return self._count_trapspaces(reachable_from=reachable_from,
|
|
569
|
+
subcube=constraints, limit=limit,
|
|
570
|
+
mode="max")
|
|
571
|
+
|
|
495
572
|
def has_cyclic_attractor(self):
|
|
496
573
|
for a in self.attractors():
|
|
497
574
|
if "*" in a.values():
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
import mpbn
|
|
3
3
|
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
5
6
|
from argparse import ArgumentParser
|
|
6
7
|
|
|
7
8
|
def main():
|
|
9
|
+
if "CLINGO_OPTS" in os.environ:
|
|
10
|
+
mpbn.clingo_options += os.environ["CLINGO_OPTS"].split(" ")
|
|
11
|
+
|
|
8
12
|
ap = ArgumentParser(prog=sys.argv[0])
|
|
9
13
|
ap.add_argument("bnet_file")
|
|
10
14
|
ap.add_argument("method", choices=["attractors", "fixedpoints", "bn2asp"])
|
|
@@ -13,19 +17,26 @@ def main():
|
|
|
13
17
|
ap.add_argument("--encoding", default=mpbn.DEFAULT_ENCODING,
|
|
14
18
|
choices=mpbn.MPBooleanNetwork.supported_encodings,
|
|
15
19
|
help=f"Encoding method (default: {mpbn.DEFAULT_ENCODING})")
|
|
20
|
+
ap.add_argument("--input-is-dnf", action="store_true", default=False,
|
|
21
|
+
help="Functions are already in DNF form")
|
|
16
22
|
ap.add_argument("--simplify", action="store_true", default=False,
|
|
17
23
|
help="Try costly Boolean function simplifications to improve encoding")
|
|
18
24
|
ap.add_argument("--try-unate-hard", action="store_true", default=False,
|
|
19
25
|
help="Try even more costly Boolean function simplifications")
|
|
26
|
+
ap.add_argument("--count", action="store_true",
|
|
27
|
+
help="Returns only the number of solutions")
|
|
20
28
|
args = ap.parse_args()
|
|
21
29
|
mbn = mpbn.MPBooleanNetwork(args.bnet_file, encoding=args.encoding,
|
|
30
|
+
auto_dnf=not args.input_is_dnf,
|
|
22
31
|
simplify=args.simplify,
|
|
23
32
|
try_unate_hard=args.try_unate_hard)
|
|
24
|
-
if args.method
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
if args.method in ["attractors", "fixedpoints"]:
|
|
34
|
+
if args.count:
|
|
35
|
+
func = getattr(mbn, f"count_{args.method}")
|
|
36
|
+
print(func(limit=args.limit))
|
|
37
|
+
else:
|
|
38
|
+
func = getattr(mbn, args.method)
|
|
39
|
+
for obj in func(limit=args.limit):
|
|
40
|
+
print(obj)
|
|
30
41
|
elif args.method == "bn2asp":
|
|
31
42
|
print(mbn.asp_of_bn())
|
|
@@ -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-3.4 → mpbn-3.8}/setup.py
RENAMED
|
File without changes
|
{mpbn-3.4 → mpbn-3.8}/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mpbn-3.4 → mpbn-3.8}/setup.cfg
RENAMED
|
File without changes
|