process-bigraph 0.0.23__tar.gz → 0.0.25__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.25}/PKG-INFO +1 -1
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/composite.py +294 -330
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/experiments/minimal_gillespie.py +55 -6
- process-bigraph-0.0.25/process_bigraph/processes/__init__.py +21 -0
- {process-bigraph-0.0.23/process_bigraph/experiments → process-bigraph-0.0.25/process_bigraph/processes}/growth_division.py +1 -9
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/processes/parameter_scan.py +7 -12
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/tests.py +14 -78
- {process-bigraph-0.0.23 → process-bigraph-0.0.25/process_bigraph.egg-info}/PKG-INFO +1 -1
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph.egg-info/SOURCES.txt +1 -1
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph.egg-info/requires.txt +1 -2
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/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.25}/AUTHORS.md +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/LICENSE +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/README.md +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/__init__.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/experiments/__init__.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/process_types.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph/protocols.py +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph.egg-info/dependency_links.txt +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/process_bigraph.egg-info/top_level.txt +0 -0
- {process-bigraph-0.0.23 → process-bigraph-0.0.25}/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)
|
|
638
|
+
|
|
639
|
+
return {
|
|
640
|
+
'inputs': union_inputs,
|
|
641
|
+
'outputs': union_outputs}
|
|
433
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', {})
|
|
@@ -798,8 +797,19 @@ class Composite(Process):
|
|
|
798
797
|
self.add_emitter(
|
|
799
798
|
emitter_config)
|
|
800
799
|
|
|
801
|
-
self.
|
|
800
|
+
self.front: Dict = {
|
|
801
|
+
path: empty_front(self.state['global_time'])
|
|
802
|
+
for path in self.process_paths}
|
|
803
|
+
|
|
804
|
+
self.bridge_updates = []
|
|
805
|
+
|
|
806
|
+
# build the step network
|
|
807
|
+
self.build_step_network()
|
|
808
|
+
|
|
809
|
+
# self.run_steps(self.to_run)
|
|
802
810
|
|
|
811
|
+
def build_step_network(self):
|
|
812
|
+
self.step_triggers = {}
|
|
803
813
|
for step_path, step in self.step_paths.items():
|
|
804
814
|
step_triggers = find_step_triggers(
|
|
805
815
|
step_path, step)
|
|
@@ -809,20 +819,18 @@ class Composite(Process):
|
|
|
809
819
|
|
|
810
820
|
self.steps_run = set([])
|
|
811
821
|
|
|
812
|
-
self.front: Dict = {
|
|
813
|
-
path: empty_front(self.state['global_time'])
|
|
814
|
-
for path in self.process_paths}
|
|
815
|
-
|
|
816
|
-
self.bridge_updates = []
|
|
817
|
-
|
|
818
822
|
self.step_dependencies, self.node_dependencies = build_step_network(
|
|
819
823
|
self.step_paths)
|
|
820
824
|
|
|
821
|
-
self.reset_step_state(
|
|
822
|
-
|
|
825
|
+
self.reset_step_state(
|
|
826
|
+
self.step_paths)
|
|
823
827
|
|
|
824
|
-
|
|
828
|
+
self.to_run = self.cycle_step_state()
|
|
825
829
|
|
|
830
|
+
def serialize_state(self):
|
|
831
|
+
return self.core.serialize(
|
|
832
|
+
self.composition,
|
|
833
|
+
self.state)
|
|
826
834
|
|
|
827
835
|
def save(self,
|
|
828
836
|
filename='composite.json',
|
|
@@ -830,9 +838,9 @@ class Composite(Process):
|
|
|
830
838
|
schema=False,
|
|
831
839
|
state=False):
|
|
832
840
|
|
|
833
|
-
#
|
|
834
|
-
|
|
835
|
-
|
|
841
|
+
# upcoming deprecation warning
|
|
842
|
+
print("Warning: save() is deprecated and will be removed in a future version. "
|
|
843
|
+
"Use use Vivarium for managing simulations instead of Composite.")
|
|
836
844
|
|
|
837
845
|
document = {}
|
|
838
846
|
|
|
@@ -840,30 +848,15 @@ class Composite(Process):
|
|
|
840
848
|
schema = state = True
|
|
841
849
|
|
|
842
850
|
if state:
|
|
843
|
-
serialized_state = self.
|
|
844
|
-
self.composition,
|
|
845
|
-
self.state)
|
|
846
|
-
|
|
851
|
+
serialized_state = self.serialize_state()
|
|
847
852
|
document['state'] = serialized_state
|
|
848
853
|
|
|
849
854
|
if schema:
|
|
850
|
-
# serialized_schema = self.core.serialize(
|
|
851
|
-
# 'schema',
|
|
852
|
-
# self.composition)
|
|
853
|
-
|
|
854
855
|
serialized_schema = self.core.representation(
|
|
855
856
|
self.composition)
|
|
856
|
-
|
|
857
857
|
document['composition'] = serialized_schema
|
|
858
858
|
|
|
859
|
-
# TODO: make this true
|
|
860
|
-
# copy_composite = Composite({
|
|
861
|
-
# 'state': self.state})
|
|
862
|
-
|
|
863
|
-
# assert copy_composite == self
|
|
864
|
-
|
|
865
859
|
# save the dictionary to a JSON file
|
|
866
|
-
|
|
867
860
|
if not os.path.exists(outdir):
|
|
868
861
|
os.makedirs(outdir)
|
|
869
862
|
filename = os.path.join(outdir, filename)
|
|
@@ -873,10 +866,10 @@ class Composite(Process):
|
|
|
873
866
|
json.dump(document, json_file, indent=4)
|
|
874
867
|
print(f"Created new file: {filename}")
|
|
875
868
|
|
|
869
|
+
|
|
876
870
|
def reset_step_state(self, step_paths):
|
|
877
871
|
self.trigger_state = build_trigger_state(
|
|
878
872
|
self.node_dependencies)
|
|
879
|
-
|
|
880
873
|
self.steps_remaining = set(step_paths)
|
|
881
874
|
|
|
882
875
|
|
|
@@ -885,7 +878,6 @@ class Composite(Process):
|
|
|
885
878
|
self.step_dependencies,
|
|
886
879
|
self.steps_remaining,
|
|
887
880
|
self.trigger_state)
|
|
888
|
-
|
|
889
881
|
return to_run
|
|
890
882
|
|
|
891
883
|
|
|
@@ -913,6 +905,11 @@ class Composite(Process):
|
|
|
913
905
|
|
|
914
906
|
|
|
915
907
|
def read_emitter_config(self, emitter_config):
|
|
908
|
+
|
|
909
|
+
# upcoming deprecation warning
|
|
910
|
+
print("Warning: read_emitter_config() is deprecated and will be removed in a future version. "
|
|
911
|
+
"Use use Vivarium for managing simulations and emitters instead of Composite.")
|
|
912
|
+
|
|
916
913
|
address = emitter_config.get('address', 'local:ram-emitter')
|
|
917
914
|
config = emitter_config.get('config', {})
|
|
918
915
|
mode = emitter_config.get('mode', 'none')
|
|
@@ -1221,25 +1218,6 @@ class Composite(Process):
|
|
|
1221
1218
|
force_complete = False
|
|
1222
1219
|
|
|
1223
1220
|
|
|
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
1221
|
def run_steps(self, step_paths):
|
|
1244
1222
|
if len(step_paths) > 0:
|
|
1245
1223
|
updates = []
|
|
@@ -1316,6 +1294,7 @@ class Composite(Process):
|
|
|
1316
1294
|
|
|
1317
1295
|
return results
|
|
1318
1296
|
|
|
1297
|
+
|
|
1319
1298
|
def update(self, state, interval):
|
|
1320
1299
|
# do everything
|
|
1321
1300
|
|
|
@@ -1337,13 +1316,11 @@ class Composite(Process):
|
|
|
1337
1316
|
return updates
|
|
1338
1317
|
|
|
1339
1318
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
This could be to a database, to a file, or to the console.
|
|
1346
|
-
"""
|
|
1319
|
+
# ========
|
|
1320
|
+
# Emitters
|
|
1321
|
+
# ========
|
|
1322
|
+
# Emitters are steps that observe the state of the system and emit it to an external source.
|
|
1323
|
+
# This could be to a database, to a file, or to the console.
|
|
1347
1324
|
|
|
1348
1325
|
class Emitter(Step):
|
|
1349
1326
|
"""Base emitter class.
|
|
@@ -1407,16 +1384,3 @@ class RAMEmitter(Emitter):
|
|
|
1407
1384
|
BASE_EMITTERS = {
|
|
1408
1385
|
'console-emitter': ConsoleEmitter,
|
|
1409
1386
|
'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.25}/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.25}/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.25'
|
|
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.25}/process_bigraph.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|