process-bigraph 0.0.23__tar.gz → 0.0.24__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.
- {process-bigraph-0.0.23/process_bigraph.egg-info → process-bigraph-0.0.24}/PKG-INFO +1 -1
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/composite.py +282 -321
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/experiments/minimal_gillespie.py +55 -6
- process-bigraph-0.0.24/process_bigraph/processes/__init__.py +21 -0
- {process-bigraph-0.0.23/process_bigraph/experiments → process-bigraph-0.0.24/process_bigraph/processes}/growth_division.py +1 -9
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/processes/parameter_scan.py +7 -12
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/tests.py +14 -78
- {process-bigraph-0.0.23 → process-bigraph-0.0.24/process_bigraph.egg-info}/PKG-INFO +1 -1
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph.egg-info/SOURCES.txt +1 -1
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph.egg-info/requires.txt +1 -2
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/setup.py +3 -3
- process-bigraph-0.0.23/process_bigraph/processes/__init__.py +0 -18
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/AUTHORS.md +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/LICENSE +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/README.md +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/__init__.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/experiments/__init__.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/process_types.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/protocols.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph.egg-info/dependency_links.txt +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph.egg-info/top_level.txt +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.24}/setup.cfg +0 -0
|
@@ -15,6 +15,11 @@ from bigraph_schema import Edge, TypeSystem, get_path, set_path, deep_merge, is_
|
|
|
15
15
|
from process_bigraph.protocols import local_lookup, local_lookup_module
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
|
|
19
|
+
# =========================
|
|
20
|
+
# Process Utility Functions
|
|
21
|
+
# =========================
|
|
22
|
+
|
|
18
23
|
def assert_interface(interface: Dict):
|
|
19
24
|
"""Ensure that an interface dict has the required keys"""
|
|
20
25
|
required_keys = ['inputs', 'outputs']
|
|
@@ -22,6 +27,224 @@ def assert_interface(interface: Dict):
|
|
|
22
27
|
assert existing_keys == set(required_keys), f"every interface requires an inputs schema and an outputs schema, not {existing_keys}"
|
|
23
28
|
|
|
24
29
|
|
|
30
|
+
def find_instances(state, instance_type='process_bigraph.composite.Process'):
|
|
31
|
+
process_class = local_lookup_module(instance_type)
|
|
32
|
+
found = {}
|
|
33
|
+
|
|
34
|
+
for key, inner in state.items():
|
|
35
|
+
if isinstance(inner, dict):
|
|
36
|
+
if isinstance(inner.get('instance'), process_class):
|
|
37
|
+
found[key] = inner
|
|
38
|
+
elif not is_schema_key(key):
|
|
39
|
+
inner_instances = find_instances(
|
|
40
|
+
inner,
|
|
41
|
+
instance_type=instance_type)
|
|
42
|
+
|
|
43
|
+
if inner_instances:
|
|
44
|
+
found[key] = inner_instances
|
|
45
|
+
return found
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def find_instance_paths(state, instance_type='process_bigraph.composite.Process'):
|
|
49
|
+
instances = find_instances(state, instance_type)
|
|
50
|
+
return hierarchy_depth(instances)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def find_step_triggers(path, step):
|
|
54
|
+
prefix = tuple(path[:-1])
|
|
55
|
+
triggers = {}
|
|
56
|
+
wire_paths = find_leaves(
|
|
57
|
+
step['inputs'])
|
|
58
|
+
|
|
59
|
+
for wire in wire_paths:
|
|
60
|
+
trigger_path = tuple(prefix) + tuple(wire)
|
|
61
|
+
if trigger_path not in triggers:
|
|
62
|
+
triggers[trigger_path] = []
|
|
63
|
+
triggers[trigger_path].append(path)
|
|
64
|
+
|
|
65
|
+
return triggers
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def explode_path(path):
|
|
69
|
+
explode = ()
|
|
70
|
+
paths = [explode]
|
|
71
|
+
|
|
72
|
+
for node in path:
|
|
73
|
+
explode = explode + (node,)
|
|
74
|
+
paths.append(explode)
|
|
75
|
+
|
|
76
|
+
return paths
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def merge_collections(existing, new):
|
|
80
|
+
if existing is None:
|
|
81
|
+
existing = {}
|
|
82
|
+
if new is None:
|
|
83
|
+
new = {}
|
|
84
|
+
for key, value in new.items():
|
|
85
|
+
if key in existing:
|
|
86
|
+
if isinstance(existing[key], dict) and isinstance(new[key], collections.abc.Mapping):
|
|
87
|
+
merge_collections(existing[key], new[key])
|
|
88
|
+
elif isinstance(existing[key], list) and isinstance(new[key], collections.abc.Sequence):
|
|
89
|
+
existing[key].extend(new[key])
|
|
90
|
+
else:
|
|
91
|
+
raise Exception(
|
|
92
|
+
f'cannot merge collections as they do not match:\n{existing}\n{new}')
|
|
93
|
+
else:
|
|
94
|
+
existing[key] = value
|
|
95
|
+
|
|
96
|
+
return existing
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def empty_front(time):
|
|
100
|
+
return {
|
|
101
|
+
'time': time,
|
|
102
|
+
'update': {}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def find_leaves(tree_structure, path=None):
|
|
107
|
+
leaves = []
|
|
108
|
+
path = ()
|
|
109
|
+
|
|
110
|
+
if tree_structure is None:
|
|
111
|
+
pass
|
|
112
|
+
elif isinstance(tree_structure, list):
|
|
113
|
+
leaves = tree_structure
|
|
114
|
+
elif isinstance(tree_structure, tuple):
|
|
115
|
+
leaves.append(tree_structure)
|
|
116
|
+
else:
|
|
117
|
+
for key, value in tree_structure.items():
|
|
118
|
+
if isinstance(value, dict):
|
|
119
|
+
subleaves = find_leaves(value, path + (key,))
|
|
120
|
+
leaves.extend(subleaves)
|
|
121
|
+
else:
|
|
122
|
+
leaves.append(path + tuple(value))
|
|
123
|
+
|
|
124
|
+
return leaves
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def build_step_network(steps):
|
|
128
|
+
ancestors = {
|
|
129
|
+
step_key: {
|
|
130
|
+
'input_paths': None,
|
|
131
|
+
'output_paths': None}
|
|
132
|
+
for step_key in steps}
|
|
133
|
+
|
|
134
|
+
nodes = {}
|
|
135
|
+
|
|
136
|
+
for step_key, step in steps.items():
|
|
137
|
+
for other_key, other_step in steps.items():
|
|
138
|
+
if step_key == other_key:
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
schema = step['instance'].interface()
|
|
142
|
+
other_schema = other_step['instance'].interface()
|
|
143
|
+
|
|
144
|
+
assert_interface(schema)
|
|
145
|
+
assert_interface(other_schema)
|
|
146
|
+
|
|
147
|
+
if ancestors[step_key]['input_paths'] is None:
|
|
148
|
+
ancestors[step_key]['input_paths'] = find_leaves(
|
|
149
|
+
step['inputs'])
|
|
150
|
+
input_paths = ancestors[step_key]['input_paths']
|
|
151
|
+
|
|
152
|
+
if ancestors[step_key]['output_paths'] is None:
|
|
153
|
+
ancestors[step_key]['output_paths'] = find_leaves(
|
|
154
|
+
step.get('outputs', {}))
|
|
155
|
+
output_paths = ancestors[step_key]['output_paths']
|
|
156
|
+
|
|
157
|
+
for input in input_paths:
|
|
158
|
+
path = tuple(input)
|
|
159
|
+
if not path in nodes:
|
|
160
|
+
nodes[path] = {
|
|
161
|
+
'before': set([]),
|
|
162
|
+
'after': set([])}
|
|
163
|
+
nodes[path]['after'].add(step_key)
|
|
164
|
+
|
|
165
|
+
for output in output_paths:
|
|
166
|
+
if output in input_paths:
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
path = tuple(output)
|
|
170
|
+
if not path in nodes:
|
|
171
|
+
nodes[path] = {
|
|
172
|
+
'before': set([]),
|
|
173
|
+
'after': set([])}
|
|
174
|
+
nodes[path]['before'].add(step_key)
|
|
175
|
+
|
|
176
|
+
return ancestors, nodes
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def build_trigger_state(nodes):
|
|
180
|
+
return {
|
|
181
|
+
key: value['before'].copy()
|
|
182
|
+
for key, value in nodes.items()}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def find_downstream(steps, nodes, upstream):
|
|
186
|
+
downstream = set(upstream)
|
|
187
|
+
visited = set([])
|
|
188
|
+
previous_len = -1
|
|
189
|
+
|
|
190
|
+
while len(downstream) > len(visited) and len(visited) > previous_len:
|
|
191
|
+
previous_len = len(visited)
|
|
192
|
+
down = set([])
|
|
193
|
+
for step_path in downstream:
|
|
194
|
+
if step_path not in visited:
|
|
195
|
+
step_outputs = steps[step_path]['output_paths']
|
|
196
|
+
if step_outputs is None:
|
|
197
|
+
step_outputs = [] # Ensure step_outputs is always an iterable
|
|
198
|
+
for output in step_outputs:
|
|
199
|
+
for dependent in nodes[output]['after']:
|
|
200
|
+
down.add(dependent)
|
|
201
|
+
visited.add(step_path)
|
|
202
|
+
downstream |= down
|
|
203
|
+
|
|
204
|
+
return downstream
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def determine_steps(steps, remaining, fulfilled):
|
|
208
|
+
to_run = []
|
|
209
|
+
for step_path in remaining:
|
|
210
|
+
step_inputs = steps[step_path]['input_paths']
|
|
211
|
+
if step_inputs is None:
|
|
212
|
+
step_inputs = []
|
|
213
|
+
all_fulfilled = True
|
|
214
|
+
for input in step_inputs:
|
|
215
|
+
if len(fulfilled[input]) > 0:
|
|
216
|
+
all_fulfilled = False
|
|
217
|
+
if all_fulfilled:
|
|
218
|
+
to_run.append(step_path)
|
|
219
|
+
|
|
220
|
+
for step_path in to_run:
|
|
221
|
+
remaining.remove(step_path)
|
|
222
|
+
step_outputs = steps[step_path]['output_paths']
|
|
223
|
+
if step_outputs is None:
|
|
224
|
+
step_outputs = []
|
|
225
|
+
|
|
226
|
+
for output in step_outputs:
|
|
227
|
+
if output in fulfilled and step_path in fulfilled[output]:
|
|
228
|
+
fulfilled[output].remove(step_path)
|
|
229
|
+
|
|
230
|
+
return to_run, remaining, fulfilled
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def interval_time_precision(timestep):
|
|
234
|
+
# get number of decimal places to set global time precision
|
|
235
|
+
timestep_str = str(timestep)
|
|
236
|
+
global_time_precision = 0
|
|
237
|
+
if '.' in timestep_str:
|
|
238
|
+
_, decimals = timestep_str.split('.')
|
|
239
|
+
global_time_precision = len(decimals)
|
|
240
|
+
|
|
241
|
+
return global_time_precision
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
# ======================
|
|
245
|
+
# Process Type Functions
|
|
246
|
+
# ======================
|
|
247
|
+
|
|
25
248
|
def apply_process(schema, current, update, core):
|
|
26
249
|
"""Apply an update to a process."""
|
|
27
250
|
process_schema = schema.copy()
|
|
@@ -245,6 +468,10 @@ BASE_PROTOCOLS = {
|
|
|
245
468
|
'local': local_lookup}
|
|
246
469
|
|
|
247
470
|
|
|
471
|
+
# ===================
|
|
472
|
+
# Process Type System
|
|
473
|
+
# ===================
|
|
474
|
+
|
|
248
475
|
class ProcessTypes(TypeSystem):
|
|
249
476
|
"""
|
|
250
477
|
ProcessTypes class extends the TypeSystem class to include process types.
|
|
@@ -328,6 +555,10 @@ class ProcessTypes(TypeSystem):
|
|
|
328
555
|
return state
|
|
329
556
|
|
|
330
557
|
|
|
558
|
+
# ===============
|
|
559
|
+
# Process Classes
|
|
560
|
+
# ===============
|
|
561
|
+
|
|
331
562
|
class SyncUpdate():
|
|
332
563
|
def __init__(self, update):
|
|
333
564
|
self.update = update
|
|
@@ -344,23 +575,6 @@ class Step(Edge):
|
|
|
344
575
|
like a workflow.
|
|
345
576
|
"""
|
|
346
577
|
# TODO: support trigger every time as well as dependency trigger
|
|
347
|
-
config_schema = {}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
def __init__(self, config=None, core=None):
|
|
351
|
-
self.core = core or ProcessTypes()
|
|
352
|
-
|
|
353
|
-
if config is None:
|
|
354
|
-
config = {}
|
|
355
|
-
|
|
356
|
-
self.config = self.core.fill(
|
|
357
|
-
self.config_schema,
|
|
358
|
-
config)
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
def initial_state(self):
|
|
362
|
-
return {}
|
|
363
|
-
|
|
364
578
|
|
|
365
579
|
def invoke(self, state, _=None):
|
|
366
580
|
update = self.update(state)
|
|
@@ -389,34 +603,6 @@ class Process(Edge):
|
|
|
389
603
|
config: Override the class defaults. This dictionary may
|
|
390
604
|
also contain the following special keys (TODO):
|
|
391
605
|
"""
|
|
392
|
-
config_schema = {}
|
|
393
|
-
|
|
394
|
-
def __init__(self, config=None, core=None):
|
|
395
|
-
self.core = core or ProcessTypes()
|
|
396
|
-
|
|
397
|
-
if config is None:
|
|
398
|
-
config = {}
|
|
399
|
-
|
|
400
|
-
# # check that all keywords in config are in config_schema
|
|
401
|
-
# for key in config.keys():
|
|
402
|
-
# if key not in self.config_schema:
|
|
403
|
-
# raise Exception(f'config key {key} not in config_schema for {self.__class__.__name__}')
|
|
404
|
-
|
|
405
|
-
# fill in defaults for config
|
|
406
|
-
self.config = self.core.fill(
|
|
407
|
-
self.config_schema,
|
|
408
|
-
config)
|
|
409
|
-
|
|
410
|
-
# TODO: validate your config after filling, report if anything
|
|
411
|
-
# is off
|
|
412
|
-
# print(self.core.validate_state(
|
|
413
|
-
# self.config_schema,
|
|
414
|
-
# config))
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
def initial_state(self):
|
|
418
|
-
return {}
|
|
419
|
-
|
|
420
606
|
|
|
421
607
|
def invoke(self, state, interval):
|
|
422
608
|
update = self.update(state, interval)
|
|
@@ -428,9 +614,33 @@ class Process(Edge):
|
|
|
428
614
|
return {}
|
|
429
615
|
|
|
430
616
|
|
|
431
|
-
|
|
432
|
-
|
|
617
|
+
class ProcessEnsemble(Process):
|
|
618
|
+
def __init__(self, config=None, core=None):
|
|
619
|
+
self.__init__(config, core)
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
def union_interface(self):
|
|
623
|
+
union_inputs = {}
|
|
624
|
+
union_outputs = {}
|
|
625
|
+
|
|
626
|
+
for self_key in dir(self):
|
|
627
|
+
if self_key.startswith('inputs_'):
|
|
628
|
+
inputs = self.getattr(self_key)()
|
|
629
|
+
union_inputs = self.core.resolve_schemas(
|
|
630
|
+
union_inputs,
|
|
631
|
+
inputs)
|
|
632
|
+
|
|
633
|
+
if self_key.startswith('outputs_'):
|
|
634
|
+
outputs = self.getattr(self_key)()
|
|
635
|
+
union_outputs = self.core.resolve_schemas(
|
|
636
|
+
union_outputs,
|
|
637
|
+
outputs)
|
|
433
638
|
|
|
639
|
+
return {
|
|
640
|
+
'inputs': union_inputs,
|
|
641
|
+
'outputs': union_outputs}
|
|
642
|
+
|
|
643
|
+
|
|
434
644
|
|
|
435
645
|
class Defer:
|
|
436
646
|
"""Allows for delayed application of a function to an update.
|
|
@@ -443,7 +653,7 @@ class Defer:
|
|
|
443
653
|
defer: An object with a ``.get_command_result()`` method
|
|
444
654
|
whose output will be passed to the function. For
|
|
445
655
|
example, the object could be an
|
|
446
|
-
:
|
|
656
|
+
:Process` object whose
|
|
447
657
|
``.get_command_result()`` method will return the process
|
|
448
658
|
update.
|
|
449
659
|
function: The function. For example,
|
|
@@ -475,216 +685,6 @@ class Defer:
|
|
|
475
685
|
self.args)
|
|
476
686
|
|
|
477
687
|
|
|
478
|
-
def find_instances(state, instance_type='process_bigraph.composite.Process'):
|
|
479
|
-
process_class = local_lookup_module(instance_type)
|
|
480
|
-
found = {}
|
|
481
|
-
|
|
482
|
-
for key, inner in state.items():
|
|
483
|
-
if isinstance(inner, dict):
|
|
484
|
-
if isinstance(inner.get('instance'), process_class):
|
|
485
|
-
found[key] = inner
|
|
486
|
-
elif not is_schema_key(key):
|
|
487
|
-
inner_instances = find_instances(
|
|
488
|
-
inner,
|
|
489
|
-
instance_type=instance_type)
|
|
490
|
-
|
|
491
|
-
if inner_instances:
|
|
492
|
-
found[key] = inner_instances
|
|
493
|
-
return found
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
def find_instance_paths(state, instance_type='process_bigraph.composite.Process'):
|
|
497
|
-
instances = find_instances(state, instance_type)
|
|
498
|
-
return hierarchy_depth(instances)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
def find_step_triggers(path, step):
|
|
502
|
-
prefix = tuple(path[:-1])
|
|
503
|
-
triggers = {}
|
|
504
|
-
wire_paths = find_leaves(
|
|
505
|
-
step['inputs'])
|
|
506
|
-
|
|
507
|
-
for wire in wire_paths:
|
|
508
|
-
trigger_path = tuple(prefix) + tuple(wire)
|
|
509
|
-
if trigger_path not in triggers:
|
|
510
|
-
triggers[trigger_path] = []
|
|
511
|
-
triggers[trigger_path].append(path)
|
|
512
|
-
|
|
513
|
-
return triggers
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
def explode_path(path):
|
|
517
|
-
explode = ()
|
|
518
|
-
paths = [explode]
|
|
519
|
-
|
|
520
|
-
for node in path:
|
|
521
|
-
explode = explode + (node,)
|
|
522
|
-
paths.append(explode)
|
|
523
|
-
|
|
524
|
-
return paths
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
def merge_collections(existing, new):
|
|
528
|
-
if existing is None:
|
|
529
|
-
existing = {}
|
|
530
|
-
if new is None:
|
|
531
|
-
new = {}
|
|
532
|
-
for key, value in new.items():
|
|
533
|
-
if key in existing:
|
|
534
|
-
if isinstance(existing[key], dict) and isinstance(new[key], collections.abc.Mapping):
|
|
535
|
-
merge_collections(existing[key], new[key])
|
|
536
|
-
elif isinstance(existing[key], list) and isinstance(new[key], collections.abc.Sequence):
|
|
537
|
-
existing[key].extend(new[key])
|
|
538
|
-
else:
|
|
539
|
-
raise Exception(
|
|
540
|
-
f'cannot merge collections as they do not match:\n{existing}\n{new}')
|
|
541
|
-
else:
|
|
542
|
-
existing[key] = value
|
|
543
|
-
|
|
544
|
-
return existing
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
def empty_front(time):
|
|
548
|
-
return {
|
|
549
|
-
'time': time,
|
|
550
|
-
'update': {}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
def find_leaves(tree_structure, path=None):
|
|
555
|
-
leaves = []
|
|
556
|
-
path = ()
|
|
557
|
-
|
|
558
|
-
if tree_structure is None:
|
|
559
|
-
pass
|
|
560
|
-
elif isinstance(tree_structure, list):
|
|
561
|
-
leaves = tree_structure
|
|
562
|
-
elif isinstance(tree_structure, tuple):
|
|
563
|
-
leaves.append(tree_structure)
|
|
564
|
-
else:
|
|
565
|
-
for key, value in tree_structure.items():
|
|
566
|
-
if isinstance(value, dict):
|
|
567
|
-
subleaves = find_leaves(value, path + (key,))
|
|
568
|
-
leaves.extend(subleaves)
|
|
569
|
-
else:
|
|
570
|
-
leaves.append(path + tuple(value))
|
|
571
|
-
|
|
572
|
-
return leaves
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
def build_step_network(steps):
|
|
576
|
-
ancestors = {
|
|
577
|
-
step_key: {
|
|
578
|
-
'input_paths': None,
|
|
579
|
-
'output_paths': None}
|
|
580
|
-
for step_key in steps}
|
|
581
|
-
|
|
582
|
-
nodes = {}
|
|
583
|
-
|
|
584
|
-
for step_key, step in steps.items():
|
|
585
|
-
for other_key, other_step in steps.items():
|
|
586
|
-
if step_key == other_key:
|
|
587
|
-
continue
|
|
588
|
-
|
|
589
|
-
schema = step['instance'].interface()
|
|
590
|
-
other_schema = other_step['instance'].interface()
|
|
591
|
-
|
|
592
|
-
assert_interface(schema)
|
|
593
|
-
assert_interface(other_schema)
|
|
594
|
-
|
|
595
|
-
if ancestors[step_key]['input_paths'] is None:
|
|
596
|
-
ancestors[step_key]['input_paths'] = find_leaves(
|
|
597
|
-
step['inputs'])
|
|
598
|
-
input_paths = ancestors[step_key]['input_paths']
|
|
599
|
-
|
|
600
|
-
if ancestors[step_key]['output_paths'] is None:
|
|
601
|
-
ancestors[step_key]['output_paths'] = find_leaves(
|
|
602
|
-
step.get('outputs', {}))
|
|
603
|
-
output_paths = ancestors[step_key]['output_paths']
|
|
604
|
-
|
|
605
|
-
for input in input_paths:
|
|
606
|
-
path = tuple(input)
|
|
607
|
-
if not path in nodes:
|
|
608
|
-
nodes[path] = {
|
|
609
|
-
'before': set([]),
|
|
610
|
-
'after': set([])}
|
|
611
|
-
nodes[path]['after'].add(step_key)
|
|
612
|
-
|
|
613
|
-
for output in output_paths:
|
|
614
|
-
path = tuple(output)
|
|
615
|
-
if not path in nodes:
|
|
616
|
-
nodes[path] = {
|
|
617
|
-
'before': set([]),
|
|
618
|
-
'after': set([])}
|
|
619
|
-
nodes[path]['before'].add(step_key)
|
|
620
|
-
|
|
621
|
-
return ancestors, nodes
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
def build_trigger_state(nodes):
|
|
626
|
-
return {
|
|
627
|
-
key: value['before'].copy()
|
|
628
|
-
for key, value in nodes.items()}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
def find_downstream(steps, nodes, upstream):
|
|
632
|
-
downstream = set(upstream)
|
|
633
|
-
visited = set([])
|
|
634
|
-
previous_len = -1
|
|
635
|
-
|
|
636
|
-
while len(downstream) > len(visited) and len(visited) > previous_len:
|
|
637
|
-
previous_len = len(visited)
|
|
638
|
-
down = set([])
|
|
639
|
-
for step_path in downstream:
|
|
640
|
-
if step_path not in visited:
|
|
641
|
-
step_outputs = steps[step_path]['output_paths']
|
|
642
|
-
if step_outputs is None:
|
|
643
|
-
step_outputs = [] # Ensure step_outputs is always an iterable
|
|
644
|
-
for output in step_outputs:
|
|
645
|
-
for dependent in nodes[output]['after']:
|
|
646
|
-
down.add(dependent)
|
|
647
|
-
visited.add(step_path)
|
|
648
|
-
downstream |= down
|
|
649
|
-
|
|
650
|
-
return downstream
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
def determine_steps(steps, remaining, fulfilled):
|
|
654
|
-
to_run = []
|
|
655
|
-
for step_path in remaining:
|
|
656
|
-
step_inputs = steps[step_path]['input_paths']
|
|
657
|
-
if step_inputs is None:
|
|
658
|
-
step_inputs = []
|
|
659
|
-
all_fulfilled = True
|
|
660
|
-
for input in step_inputs:
|
|
661
|
-
if len(fulfilled[input]) > 0:
|
|
662
|
-
all_fulfilled = False
|
|
663
|
-
if all_fulfilled:
|
|
664
|
-
to_run.append(step_path)
|
|
665
|
-
|
|
666
|
-
for step_path in to_run:
|
|
667
|
-
remaining.remove(step_path)
|
|
668
|
-
step_outputs = steps[step_path]['output_paths']
|
|
669
|
-
if step_outputs is None:
|
|
670
|
-
step_outputs = []
|
|
671
|
-
for output in step_outputs:
|
|
672
|
-
fulfilled[output].remove(step_path)
|
|
673
|
-
|
|
674
|
-
return to_run, remaining, fulfilled
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
def interval_time_precision(timestep):
|
|
678
|
-
# get number of decimal places to set global time precision
|
|
679
|
-
timestep_str = str(timestep)
|
|
680
|
-
global_time_precision = 0
|
|
681
|
-
if '.' in timestep_str:
|
|
682
|
-
_, decimals = timestep_str.split('.')
|
|
683
|
-
global_time_precision = len(decimals)
|
|
684
|
-
|
|
685
|
-
return global_time_precision
|
|
686
|
-
|
|
687
|
-
|
|
688
688
|
class Composite(Process):
|
|
689
689
|
"""
|
|
690
690
|
Composite parent class.
|
|
@@ -724,8 +724,7 @@ class Composite(Process):
|
|
|
724
724
|
return composite
|
|
725
725
|
|
|
726
726
|
|
|
727
|
-
def
|
|
728
|
-
super().__init__(config, core)
|
|
727
|
+
def initialize(self, config=None):
|
|
729
728
|
|
|
730
729
|
# insert global_time into schema if not present
|
|
731
730
|
initial_composition = self.config.get('composition', {})
|
|
@@ -818,11 +817,17 @@ class Composite(Process):
|
|
|
818
817
|
self.step_dependencies, self.node_dependencies = build_step_network(
|
|
819
818
|
self.step_paths)
|
|
820
819
|
|
|
821
|
-
self.reset_step_state(
|
|
820
|
+
self.reset_step_state(
|
|
821
|
+
self.step_paths)
|
|
822
|
+
|
|
822
823
|
self.to_run = self.cycle_step_state()
|
|
823
824
|
|
|
824
825
|
# self.run_steps(self.to_run)
|
|
825
826
|
|
|
827
|
+
def serialize_state(self):
|
|
828
|
+
return self.core.serialize(
|
|
829
|
+
self.composition,
|
|
830
|
+
self.state)
|
|
826
831
|
|
|
827
832
|
def save(self,
|
|
828
833
|
filename='composite.json',
|
|
@@ -830,9 +835,9 @@ class Composite(Process):
|
|
|
830
835
|
schema=False,
|
|
831
836
|
state=False):
|
|
832
837
|
|
|
833
|
-
#
|
|
834
|
-
|
|
835
|
-
|
|
838
|
+
# upcoming deprecation warning
|
|
839
|
+
print("Warning: save() is deprecated and will be removed in a future version. "
|
|
840
|
+
"Use use Vivarium for managing simulations instead of Composite.")
|
|
836
841
|
|
|
837
842
|
document = {}
|
|
838
843
|
|
|
@@ -840,30 +845,15 @@ class Composite(Process):
|
|
|
840
845
|
schema = state = True
|
|
841
846
|
|
|
842
847
|
if state:
|
|
843
|
-
serialized_state = self.
|
|
844
|
-
self.composition,
|
|
845
|
-
self.state)
|
|
846
|
-
|
|
848
|
+
serialized_state = self.serialize_state()
|
|
847
849
|
document['state'] = serialized_state
|
|
848
850
|
|
|
849
851
|
if schema:
|
|
850
|
-
# serialized_schema = self.core.serialize(
|
|
851
|
-
# 'schema',
|
|
852
|
-
# self.composition)
|
|
853
|
-
|
|
854
852
|
serialized_schema = self.core.representation(
|
|
855
853
|
self.composition)
|
|
856
|
-
|
|
857
854
|
document['composition'] = serialized_schema
|
|
858
855
|
|
|
859
|
-
# TODO: make this true
|
|
860
|
-
# copy_composite = Composite({
|
|
861
|
-
# 'state': self.state})
|
|
862
|
-
|
|
863
|
-
# assert copy_composite == self
|
|
864
|
-
|
|
865
856
|
# save the dictionary to a JSON file
|
|
866
|
-
|
|
867
857
|
if not os.path.exists(outdir):
|
|
868
858
|
os.makedirs(outdir)
|
|
869
859
|
filename = os.path.join(outdir, filename)
|
|
@@ -873,10 +863,10 @@ class Composite(Process):
|
|
|
873
863
|
json.dump(document, json_file, indent=4)
|
|
874
864
|
print(f"Created new file: {filename}")
|
|
875
865
|
|
|
866
|
+
|
|
876
867
|
def reset_step_state(self, step_paths):
|
|
877
868
|
self.trigger_state = build_trigger_state(
|
|
878
869
|
self.node_dependencies)
|
|
879
|
-
|
|
880
870
|
self.steps_remaining = set(step_paths)
|
|
881
871
|
|
|
882
872
|
|
|
@@ -885,7 +875,6 @@ class Composite(Process):
|
|
|
885
875
|
self.step_dependencies,
|
|
886
876
|
self.steps_remaining,
|
|
887
877
|
self.trigger_state)
|
|
888
|
-
|
|
889
878
|
return to_run
|
|
890
879
|
|
|
891
880
|
|
|
@@ -913,6 +902,11 @@ class Composite(Process):
|
|
|
913
902
|
|
|
914
903
|
|
|
915
904
|
def read_emitter_config(self, emitter_config):
|
|
905
|
+
|
|
906
|
+
# upcoming deprecation warning
|
|
907
|
+
print("Warning: read_emitter_config() is deprecated and will be removed in a future version. "
|
|
908
|
+
"Use use Vivarium for managing simulations and emitters instead of Composite.")
|
|
909
|
+
|
|
916
910
|
address = emitter_config.get('address', 'local:ram-emitter')
|
|
917
911
|
config = emitter_config.get('config', {})
|
|
918
912
|
mode = emitter_config.get('mode', 'none')
|
|
@@ -1221,25 +1215,6 @@ class Composite(Process):
|
|
|
1221
1215
|
force_complete = False
|
|
1222
1216
|
|
|
1223
1217
|
|
|
1224
|
-
# def determine_steps(self):
|
|
1225
|
-
# to_run = []
|
|
1226
|
-
# for step_key, wires in trigger_state['steps']:
|
|
1227
|
-
# fulfilled = True
|
|
1228
|
-
# for input in wires['input_paths']:
|
|
1229
|
-
# if len(trigger_state['states'][tuple(input)]) > 0:
|
|
1230
|
-
# fulfilled = False
|
|
1231
|
-
# break
|
|
1232
|
-
# if fulfilled:
|
|
1233
|
-
# to_run.append(step_key)
|
|
1234
|
-
|
|
1235
|
-
# for step_key in to_run:
|
|
1236
|
-
# wires = trigger_state['steps'][step_key]
|
|
1237
|
-
# for output in wires['output_paths']:
|
|
1238
|
-
# trigger_state['states'][tuple(output)].remove(step_key)
|
|
1239
|
-
|
|
1240
|
-
# return to_run, trigger_state
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
1218
|
def run_steps(self, step_paths):
|
|
1244
1219
|
if len(step_paths) > 0:
|
|
1245
1220
|
updates = []
|
|
@@ -1316,6 +1291,7 @@ class Composite(Process):
|
|
|
1316
1291
|
|
|
1317
1292
|
return results
|
|
1318
1293
|
|
|
1294
|
+
|
|
1319
1295
|
def update(self, state, interval):
|
|
1320
1296
|
# do everything
|
|
1321
1297
|
|
|
@@ -1337,13 +1313,11 @@ class Composite(Process):
|
|
|
1337
1313
|
return updates
|
|
1338
1314
|
|
|
1339
1315
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
This could be to a database, to a file, or to the console.
|
|
1346
|
-
"""
|
|
1316
|
+
# ========
|
|
1317
|
+
# Emitters
|
|
1318
|
+
# ========
|
|
1319
|
+
# Emitters are steps that observe the state of the system and emit it to an external source.
|
|
1320
|
+
# This could be to a database, to a file, or to the console.
|
|
1347
1321
|
|
|
1348
1322
|
class Emitter(Step):
|
|
1349
1323
|
"""Base emitter class.
|
|
@@ -1407,16 +1381,3 @@ class RAMEmitter(Emitter):
|
|
|
1407
1381
|
BASE_EMITTERS = {
|
|
1408
1382
|
'console-emitter': ConsoleEmitter,
|
|
1409
1383
|
'ram-emitter': RAMEmitter}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
# def StateEmitter(Emitter):
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
# def test_emitter():
|
|
1416
|
-
# composite = Composite({})
|
|
1417
|
-
|
|
1418
|
-
# composite.add_emitter(['emitters', 'ram'], 'ram-emitter')
|
|
1419
|
-
# composite.emit_port(
|
|
1420
|
-
# ['emitters', 'ram'],
|
|
1421
|
-
# ['processes', 'translation'],
|
|
1422
|
-
# ['outputs', 'protein'])
|
{process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/experiments/minimal_gillespie.py
RENAMED
|
@@ -11,7 +11,7 @@ general stochastic transcription.
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
import pytest
|
|
13
13
|
|
|
14
|
-
from process_bigraph.composite import Step, Process, Composite
|
|
14
|
+
from process_bigraph.composite import Step, Process, Composite, ProcessEnsemble
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class GillespieInterval(Step):
|
|
@@ -71,7 +71,7 @@ class GillespieInterval(Step):
|
|
|
71
71
|
output = {
|
|
72
72
|
'interval': interval}
|
|
73
73
|
|
|
74
|
-
print(f'produced interval: {output}')
|
|
74
|
+
# print(f'produced interval: {output}')
|
|
75
75
|
|
|
76
76
|
return output
|
|
77
77
|
|
|
@@ -87,9 +87,7 @@ class GillespieEvent(Process):
|
|
|
87
87
|
'_default': '1e-1'}}
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
def
|
|
91
|
-
super().__init__(config, core)
|
|
92
|
-
|
|
90
|
+
def initialize(self, config=None):
|
|
93
91
|
self.stoichiometry = np.array([[0, 1], [0, -1]])
|
|
94
92
|
|
|
95
93
|
|
|
@@ -151,8 +149,59 @@ class GillespieEvent(Process):
|
|
|
151
149
|
'mRNA': {
|
|
152
150
|
'A mRNA': d_c}}
|
|
153
151
|
|
|
154
|
-
print(f'received interval: {interval}')
|
|
152
|
+
# print(f'received interval: {interval}')
|
|
155
153
|
|
|
156
154
|
return update
|
|
157
155
|
|
|
158
156
|
|
|
157
|
+
class GillespieSimulation(ProcessEnsemble):
|
|
158
|
+
def __init__(self, config=None, core=None):
|
|
159
|
+
super.__init__(config, core)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def inputs_interval(self):
|
|
163
|
+
return {
|
|
164
|
+
'DNA': 'map[default 1]',
|
|
165
|
+
'mRNA': {
|
|
166
|
+
'A mRNA': 'default 1',
|
|
167
|
+
'B mRNA': 'default 1'}}
|
|
168
|
+
|
|
169
|
+
# {
|
|
170
|
+
# '_type': 'map',
|
|
171
|
+
# '_value': 'float(default:1.0)'},
|
|
172
|
+
|
|
173
|
+
# 'G': {
|
|
174
|
+
# '_type': 'float',
|
|
175
|
+
# '_default': '1.0'}},
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def outputs_interval(self):
|
|
179
|
+
return {
|
|
180
|
+
'interval': 'interval'}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# def interface_interval(self):
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def calculate_interval(self, inputs):
|
|
187
|
+
# retrieve the state values
|
|
188
|
+
g = input['DNA']['A gene']
|
|
189
|
+
c = input['mRNA']['A mRNA']
|
|
190
|
+
|
|
191
|
+
array_state = np.array([g, c])
|
|
192
|
+
|
|
193
|
+
# Calculate propensities
|
|
194
|
+
propensities = [
|
|
195
|
+
self.config['ktsc'] * array_state[0],
|
|
196
|
+
self.config['kdeg'] * array_state[1]]
|
|
197
|
+
prop_sum = sum(propensities)
|
|
198
|
+
|
|
199
|
+
# The wait time is distributed exponentially
|
|
200
|
+
interval = np.random.exponential(scale=prop_sum)
|
|
201
|
+
|
|
202
|
+
output = {
|
|
203
|
+
'interval': interval}
|
|
204
|
+
|
|
205
|
+
print(f'produced interval: {output}')
|
|
206
|
+
|
|
207
|
+
return output
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from process_bigraph.processes.parameter_scan import ToySystem, ODE, RunProcess, ParameterScan
|
|
2
|
+
from process_bigraph.processes.growth_division import Grow, Divide
|
|
3
|
+
# from process_bigraph.experiments.minimal_gillespie import GillespieInterval, GillespieEvent
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
TOY_PROCESSES = {
|
|
7
|
+
'ToySystem': ToySystem,
|
|
8
|
+
'ToyODE': ODE,
|
|
9
|
+
'RunProcess': RunProcess,
|
|
10
|
+
'ParameterScan': ParameterScan,
|
|
11
|
+
'grow': Grow,
|
|
12
|
+
'divide': Divide,
|
|
13
|
+
# 'GillespieInterval': GillespieInterval,
|
|
14
|
+
# 'GillespieEvent': GillespieEvent
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register_processes(core):
|
|
19
|
+
for name, process in TOY_PROCESSES.items():
|
|
20
|
+
core.register_process(name, process)
|
|
21
|
+
return core
|
|
@@ -1,26 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
from process_bigraph.composite import Step, Process, Composite, ProcessTypes, interval_time_precision, deep_merge
|
|
1
|
+
from process_bigraph.composite import Step, Process, deep_merge
|
|
3
2
|
|
|
4
3
|
|
|
5
4
|
class Grow(Process):
|
|
6
5
|
config_schema = {
|
|
7
6
|
'rate': 'float'}
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
def __init__(self, config, core=None):
|
|
11
|
-
super().__init__(config, core)
|
|
12
|
-
|
|
13
|
-
|
|
14
8
|
def inputs(self):
|
|
15
9
|
return {
|
|
16
10
|
'mass': 'float'}
|
|
17
11
|
|
|
18
|
-
|
|
19
12
|
def outputs(self):
|
|
20
13
|
return {
|
|
21
14
|
'mass': 'float'}
|
|
22
15
|
|
|
23
|
-
|
|
24
16
|
def update(self, state, interval):
|
|
25
17
|
# this calculates a delta
|
|
26
18
|
|
{process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph/processes/parameter_scan.py
RENAMED
|
@@ -2,7 +2,7 @@ import copy
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
|
|
4
4
|
from bigraph_schema import get_path, set_path, transform_path
|
|
5
|
-
from process_bigraph.composite import Step, Process, Composite,
|
|
5
|
+
from process_bigraph.composite import Step, Process, Composite, interval_time_precision, deep_merge
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class ToySystem(Process):
|
|
@@ -33,9 +33,7 @@ class ToySystem(Process):
|
|
|
33
33
|
class ODE(Process):
|
|
34
34
|
config_schema = 'ode_config'
|
|
35
35
|
|
|
36
|
-
def
|
|
37
|
-
super().__init__(config, core)
|
|
38
|
-
|
|
36
|
+
def initialize(self, config=None):
|
|
39
37
|
self.reactions_count = len(self.config['rates'])
|
|
40
38
|
|
|
41
39
|
self.species_count = len(
|
|
@@ -70,10 +68,9 @@ class RunProcess(Step):
|
|
|
70
68
|
'timestep': 'float',
|
|
71
69
|
'runtime': 'float'}
|
|
72
70
|
|
|
73
|
-
def
|
|
74
|
-
super().__init__(config, core)
|
|
71
|
+
def initialize(self, config):
|
|
75
72
|
|
|
76
|
-
self.process = core.deserialize('process', {
|
|
73
|
+
self.process = self.core.deserialize('process', {
|
|
77
74
|
'_type': 'process',
|
|
78
75
|
'address': self.config['process_address'],
|
|
79
76
|
'config': self.config['process_config'],
|
|
@@ -154,7 +151,7 @@ class RunProcess(Step):
|
|
|
154
151
|
**self.inputs_config),
|
|
155
152
|
'outputs': {}}}}
|
|
156
153
|
|
|
157
|
-
self.composite = Composite(composite_config, core=core)
|
|
154
|
+
self.composite = Composite(composite_config, core=self.core)
|
|
158
155
|
|
|
159
156
|
def inputs(self):
|
|
160
157
|
return self.process.inputs()
|
|
@@ -232,8 +229,7 @@ class ParameterScan(Step):
|
|
|
232
229
|
'timestep': 'float',
|
|
233
230
|
'runtime': 'float'}
|
|
234
231
|
|
|
235
|
-
def
|
|
236
|
-
super().__init__(config, core)
|
|
232
|
+
def initialize(self, config=None):
|
|
237
233
|
|
|
238
234
|
self.steps_count = int(
|
|
239
235
|
self.config['runtime'] / self.config['timestep']) + 1
|
|
@@ -283,7 +279,7 @@ class ParameterScan(Step):
|
|
|
283
279
|
self.scan = Composite({
|
|
284
280
|
'bridge': bridge,
|
|
285
281
|
'state': state},
|
|
286
|
-
core=core)
|
|
282
|
+
core=self.core)
|
|
287
283
|
|
|
288
284
|
results_schema = {}
|
|
289
285
|
process = self.first_process()
|
|
@@ -339,4 +335,3 @@ class ParameterScan(Step):
|
|
|
339
335
|
return {
|
|
340
336
|
'results': update}
|
|
341
337
|
|
|
342
|
-
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Tests for Process Bigraph
|
|
3
3
|
"""
|
|
4
|
-
|
|
5
|
-
import random
|
|
6
4
|
import pytest
|
|
5
|
+
import random
|
|
7
6
|
|
|
8
7
|
from process_bigraph import register_types
|
|
9
|
-
from process_bigraph.composite import
|
|
10
|
-
|
|
8
|
+
from process_bigraph.composite import (
|
|
9
|
+
Process, Step, Composite, merge_collections, ProcessTypes
|
|
10
|
+
)
|
|
11
|
+
from process_bigraph.processes.growth_division import grow_divide_agent
|
|
12
|
+
from process_bigraph.processes import TOY_PROCESSES
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def core():
|
|
17
|
+
core = ProcessTypes()
|
|
18
|
+
return register_types(core)
|
|
11
19
|
|
|
12
20
|
|
|
13
21
|
class IncreaseProcess(Process):
|
|
@@ -329,9 +337,6 @@ class SimpleCompartment(Process):
|
|
|
329
337
|
return update
|
|
330
338
|
|
|
331
339
|
|
|
332
|
-
# TODO: create reaction registry, register this under "divide"
|
|
333
|
-
|
|
334
|
-
|
|
335
340
|
def engulf_reaction(config):
|
|
336
341
|
return {
|
|
337
342
|
'redex': {},
|
|
@@ -533,15 +538,13 @@ def test_parameter_scan(core):
|
|
|
533
538
|
'outputs': {
|
|
534
539
|
'results': ['results']}}}
|
|
535
540
|
|
|
536
|
-
# TODO: make a Workflow class that is a Step-composite
|
|
537
|
-
# scan = Workflow({
|
|
538
541
|
scan = Composite({
|
|
539
542
|
'bridge': {
|
|
540
543
|
'outputs': {
|
|
541
544
|
'results': ['results']}},
|
|
542
545
|
'state': state},
|
|
543
546
|
core=core)
|
|
544
|
-
|
|
547
|
+
|
|
545
548
|
# TODO: make a method so we can run it directly, provide some way to get the result out
|
|
546
549
|
# result = scan.update({})
|
|
547
550
|
result = scan.update({}, 0.0)
|
|
@@ -574,16 +577,12 @@ def test_grow_divide(core):
|
|
|
574
577
|
'environment': ['environment']}}},
|
|
575
578
|
core=core)
|
|
576
579
|
|
|
577
|
-
import ipdb; ipdb.set_trace()
|
|
578
|
-
|
|
579
580
|
updates = composite.update({
|
|
580
581
|
'environment': {
|
|
581
582
|
'0': {
|
|
582
583
|
'mass': 1.1}}},
|
|
583
584
|
100.0)
|
|
584
585
|
|
|
585
|
-
import ipdb; ipdb.set_trace()
|
|
586
|
-
|
|
587
586
|
# TODO: mass is not synchronized between inside and outside the composite?
|
|
588
587
|
|
|
589
588
|
assert '0_0_0_0_1' in composite.state['environment']
|
|
@@ -592,45 +591,6 @@ def test_grow_divide(core):
|
|
|
592
591
|
|
|
593
592
|
def test_gillespie_composite(core):
|
|
594
593
|
composite_schema = {
|
|
595
|
-
# This all gets inferred -------------
|
|
596
|
-
# ==================================
|
|
597
|
-
# 'composition': {
|
|
598
|
-
# 'interval': {
|
|
599
|
-
# '_type': 'step',
|
|
600
|
-
# '_ports': {
|
|
601
|
-
# 'inputs': {
|
|
602
|
-
# 'DNA': {
|
|
603
|
-
# 'G': 'float'},
|
|
604
|
-
# 'mRNA': {
|
|
605
|
-
# 'C': 'float'}},
|
|
606
|
-
# 'outputs': {
|
|
607
|
-
# 'interval': 'float'}}},
|
|
608
|
-
# 'event': {
|
|
609
|
-
# '_type': 'process',
|
|
610
|
-
# '_ports': {
|
|
611
|
-
# 'DNA': {
|
|
612
|
-
# 'G': 'float'},
|
|
613
|
-
# 'mRNA': {
|
|
614
|
-
# 'C': 'float'}},
|
|
615
|
-
# 'interval': 'float'}}},
|
|
616
|
-
# 'emitter': {
|
|
617
|
-
# '_type': 'step',
|
|
618
|
-
# '_ports': {
|
|
619
|
-
# 'inputs': {
|
|
620
|
-
# 'DNA': {
|
|
621
|
-
# 'G': 'float'},
|
|
622
|
-
# 'mRNA': {
|
|
623
|
-
# 'C': 'float'}}},
|
|
624
|
-
# 'DNA': {
|
|
625
|
-
# 'G': 'float'},
|
|
626
|
-
# 'mRNA': {
|
|
627
|
-
# 'C': 'float'}},
|
|
628
|
-
# 'schema': {
|
|
629
|
-
# 'DNA': {
|
|
630
|
-
# 'G': 'float'},
|
|
631
|
-
# 'mRNA': {
|
|
632
|
-
# 'C': 'float'}},
|
|
633
|
-
|
|
634
594
|
'bridge': {
|
|
635
595
|
'inputs': {
|
|
636
596
|
'DNA': ['DNA'],
|
|
@@ -674,31 +634,6 @@ def test_gillespie_composite(core):
|
|
|
674
634
|
'mRNA': ['mRNA'],
|
|
675
635
|
'interval': ['event', 'interval']}}}}
|
|
676
636
|
|
|
677
|
-
# 'emit': 'any'},
|
|
678
|
-
# 'inputs': ()}}}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
# TODO: provide a way to emit everything:
|
|
682
|
-
# 'emitter': emit_all(
|
|
683
|
-
# 'console-emitter',
|
|
684
|
-
# exclusions={'DNA': {}}),
|
|
685
|
-
|
|
686
|
-
# TODO: make us able to wire to the top with '**'
|
|
687
|
-
# 'ram': {
|
|
688
|
-
# '_type': 'step',
|
|
689
|
-
# 'address': 'local:ram-emitter',
|
|
690
|
-
# 'config': {
|
|
691
|
-
# 'ports': {
|
|
692
|
-
# 'inputs': 'tree[any]'}},
|
|
693
|
-
# 'wires': {
|
|
694
|
-
# 'inputs': '**'}}}}
|
|
695
|
-
|
|
696
|
-
# 'DNA': {
|
|
697
|
-
# 'G': 13.0},
|
|
698
|
-
|
|
699
|
-
# 'mRNA': {
|
|
700
|
-
# 'C': '21.0'}}}
|
|
701
|
-
|
|
702
637
|
gillespie = Composite(
|
|
703
638
|
composite_schema,
|
|
704
639
|
core=core)
|
|
@@ -751,3 +686,4 @@ if __name__ == '__main__':
|
|
|
751
686
|
test_parameter_scan(core)
|
|
752
687
|
|
|
753
688
|
test_stochastic_deterministic_composite(core)
|
|
689
|
+
|
|
@@ -13,7 +13,7 @@ process_bigraph.egg-info/dependency_links.txt
|
|
|
13
13
|
process_bigraph.egg-info/requires.txt
|
|
14
14
|
process_bigraph.egg-info/top_level.txt
|
|
15
15
|
process_bigraph/experiments/__init__.py
|
|
16
|
-
process_bigraph/experiments/growth_division.py
|
|
17
16
|
process_bigraph/experiments/minimal_gillespie.py
|
|
18
17
|
process_bigraph/processes/__init__.py
|
|
18
|
+
process_bigraph/processes/growth_division.py
|
|
19
19
|
process_bigraph/processes/parameter_scan.py
|
|
@@ -2,7 +2,7 @@ import re
|
|
|
2
2
|
from setuptools import setup, find_packages
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
VERSION = '0.0.
|
|
5
|
+
VERSION = '0.0.24'
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
with open("README.md", "r") as readme:
|
|
@@ -30,6 +30,7 @@ setup(
|
|
|
30
30
|
packages=[
|
|
31
31
|
'process_bigraph',
|
|
32
32
|
'process_bigraph.processes',
|
|
33
|
+
'process_bigraph.experiments'
|
|
33
34
|
],
|
|
34
35
|
classifiers=[
|
|
35
36
|
"Development Status :: 3 - Alpha",
|
|
@@ -49,8 +50,7 @@ setup(
|
|
|
49
50
|
install_requires=[
|
|
50
51
|
"bigraph-schema",
|
|
51
52
|
"numpy",
|
|
52
|
-
"pytest
|
|
53
|
-
"pymongo",
|
|
53
|
+
"pytest",
|
|
54
54
|
"orjson",
|
|
55
55
|
"matplotlib"
|
|
56
56
|
]
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from process_bigraph.processes.parameter_scan import ToySystem, ODE, RunProcess, ParameterScan
|
|
2
|
-
from process_bigraph.experiments.growth_division import Grow, Divide
|
|
3
|
-
from process_bigraph.experiments.minimal_gillespie import GillespieInterval, GillespieEvent
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def register_processes(core):
|
|
7
|
-
core.register_process('ToySystem', ToySystem)
|
|
8
|
-
core.register_process('ToyODE', ODE)
|
|
9
|
-
core.register_process('RunProcess', RunProcess)
|
|
10
|
-
core.register_process('ParameterScan', ParameterScan)
|
|
11
|
-
|
|
12
|
-
core.register_process('grow', Grow)
|
|
13
|
-
core.register_process('divide', Divide)
|
|
14
|
-
|
|
15
|
-
core.register_process('GillespieInterval', GillespieInterval)
|
|
16
|
-
core.register_process('GillespieEvent', GillespieEvent)
|
|
17
|
-
|
|
18
|
-
return core
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process-bigraph-0.0.23 → process-bigraph-0.0.24}/process_bigraph.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|