process-bigraph 0.0.38__tar.gz → 0.0.41__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.38 → process-bigraph-0.0.41}/.gitignore +2 -0
- {process-bigraph-0.0.38/process_bigraph.egg-info → process-bigraph-0.0.41}/PKG-INFO +1 -1
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/__init__.py +6 -4
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/composite.py +389 -4
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/process_types.py +26 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/__init__.py +5 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/tests.py +55 -3
- {process-bigraph-0.0.38 → process-bigraph-0.0.41/process_bigraph.egg-info}/PKG-INFO +1 -1
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/SOURCES.txt +1 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/requires.txt +1 -3
- process-bigraph-0.0.41/pyproject.toml +19 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/setup.py +1 -1
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/.github/workflows/notebook_to_html.yml +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/.github/workflows/pytest.yml +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/AUTHORS.md +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/CLA.md +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/CODE_OF_CONDUCT.md +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/CONTRIBUTING.md +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/LICENSE +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/README.md +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/doc/_static/process-bigraph.png +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/notebooks/process-bigraphs.ipynb +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/notebooks/visualize_processes.ipynb +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/emitter.py +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/experiments/__init__.py +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/experiments/minimal_gillespie.py +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/growth_division.py +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/parameter_scan.py +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/protocols.py +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/dependency_links.txt +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/top_level.txt +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/pytest.ini +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/release.sh +0 -0
- {process-bigraph-0.0.38 → process-bigraph-0.0.41}/setup.cfg +0 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import pprint
|
|
2
2
|
from bigraph_schema.registry import deep_merge, default
|
|
3
3
|
from process_bigraph.processes import register_processes
|
|
4
|
-
from process_bigraph.composite import Process, Step, Composite, interval_time_precision
|
|
5
|
-
from process_bigraph.
|
|
6
|
-
from process_bigraph.emitter import Emitter, gather_emitter_results, generate_emitter_state
|
|
4
|
+
from process_bigraph.composite import Process, Step, Composite, interval_time_precision, ProcessTypes
|
|
5
|
+
from process_bigraph.emitter import Emitter, gather_emitter_results, generate_emitter_state, BASE_EMITTERS
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
pretty = pprint.PrettyPrinter(indent=2)
|
|
@@ -42,9 +41,12 @@ def register_types(core):
|
|
|
42
41
|
'rates': 'map[float]',
|
|
43
42
|
'species': 'map[float]'})
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
register_processes(
|
|
46
45
|
core)
|
|
47
46
|
|
|
48
47
|
return core
|
|
49
48
|
|
|
50
49
|
|
|
50
|
+
def allocate_core():
|
|
51
|
+
core = ProcessTypes()
|
|
52
|
+
return register_types(core)
|
|
@@ -11,7 +11,7 @@ import collections
|
|
|
11
11
|
from typing import Dict
|
|
12
12
|
|
|
13
13
|
from bigraph_schema import (
|
|
14
|
-
Edge, Registry,
|
|
14
|
+
Edge, Registry, TypeSystem, visit_method,
|
|
15
15
|
get_path, set_path, resolve_path, hierarchy_depth, deep_merge,
|
|
16
16
|
is_schema_key, strip_schema_keys)
|
|
17
17
|
|
|
@@ -22,6 +22,7 @@ from process_bigraph.protocols import local_lookup, local_lookup_module
|
|
|
22
22
|
# Process Utility Functions
|
|
23
23
|
# =========================
|
|
24
24
|
|
|
25
|
+
|
|
25
26
|
def assert_interface(interface: Dict):
|
|
26
27
|
"""Ensure that an interface dict has the required keys"""
|
|
27
28
|
required_keys = ['inputs', 'outputs']
|
|
@@ -379,6 +380,14 @@ class Defer:
|
|
|
379
380
|
self.defer.get(),
|
|
380
381
|
self.args)
|
|
381
382
|
|
|
383
|
+
def match_star_path(path, star_path):
|
|
384
|
+
compare = zip(path, star_path)
|
|
385
|
+
for element, star_element in compare:
|
|
386
|
+
if element != star_element:
|
|
387
|
+
if star_element != "*":
|
|
388
|
+
return False
|
|
389
|
+
return True
|
|
390
|
+
|
|
382
391
|
|
|
383
392
|
class Composite(Process):
|
|
384
393
|
"""
|
|
@@ -487,13 +496,16 @@ class Composite(Process):
|
|
|
487
496
|
|
|
488
497
|
def build_step_network(self):
|
|
489
498
|
self.step_triggers = {}
|
|
499
|
+
self.star_triggers = {}
|
|
490
500
|
for step_path, step in self.step_paths.items():
|
|
491
501
|
step_triggers = find_step_triggers(
|
|
492
502
|
step_path, step)
|
|
493
503
|
self.step_triggers = merge_collections(
|
|
494
504
|
self.step_triggers,
|
|
495
505
|
step_triggers)
|
|
496
|
-
|
|
506
|
+
for trigger in self.step_triggers:
|
|
507
|
+
if "*" in trigger:
|
|
508
|
+
self.star_triggers[trigger] = self.step_triggers[trigger]
|
|
497
509
|
self.steps_run = set([])
|
|
498
510
|
|
|
499
511
|
self.step_dependencies, self.node_dependencies = build_step_network(
|
|
@@ -571,6 +583,12 @@ class Composite(Process):
|
|
|
571
583
|
'process_bigraph.composite.Step')
|
|
572
584
|
|
|
573
585
|
|
|
586
|
+
def clean_front(self, state):
|
|
587
|
+
self.find_instance_paths(state)
|
|
588
|
+
|
|
589
|
+
# import ipdb; ipdb.set_trace()
|
|
590
|
+
|
|
591
|
+
|
|
574
592
|
def inputs(self):
|
|
575
593
|
return self.process_schema.get('inputs', {})
|
|
576
594
|
|
|
@@ -756,8 +774,7 @@ class Composite(Process):
|
|
|
756
774
|
self.bridge_updates.append(
|
|
757
775
|
bridge_update)
|
|
758
776
|
|
|
759
|
-
self.
|
|
760
|
-
self.state)
|
|
777
|
+
self.clean_front(self.state)
|
|
761
778
|
|
|
762
779
|
return update_paths
|
|
763
780
|
|
|
@@ -896,6 +913,10 @@ class Composite(Process):
|
|
|
896
913
|
paths = explode_path(update_path)
|
|
897
914
|
for path in paths:
|
|
898
915
|
step_paths = self.step_triggers.get(path, [])
|
|
916
|
+
if self.star_triggers:
|
|
917
|
+
for star_trigger, star_steps in self.star_triggers.items():
|
|
918
|
+
if match_star_path(path, star_trigger):
|
|
919
|
+
step_paths.extend(star_steps)
|
|
899
920
|
for step_path in step_paths:
|
|
900
921
|
if step_path is not None and step_path not in self.steps_run:
|
|
901
922
|
steps_to_run.append(step_path)
|
|
@@ -933,3 +954,367 @@ class Composite(Process):
|
|
|
933
954
|
return updates
|
|
934
955
|
|
|
935
956
|
|
|
957
|
+
# ======================
|
|
958
|
+
# Process Type Functions
|
|
959
|
+
# ======================
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
def apply_process(schema, current, update, top_schema, top_state, path, core):
|
|
963
|
+
"""Apply an update to a process."""
|
|
964
|
+
process_schema = schema.copy()
|
|
965
|
+
process_schema.pop('_apply')
|
|
966
|
+
return core.apply_update(
|
|
967
|
+
process_schema,
|
|
968
|
+
current,
|
|
969
|
+
update,
|
|
970
|
+
top_schema=top_schema,
|
|
971
|
+
top_state=top_state,
|
|
972
|
+
path=path)
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
def check_process(schema, state, core):
|
|
976
|
+
"""Check if this is a process."""
|
|
977
|
+
return 'instance' in state and isinstance(
|
|
978
|
+
state['instance'],
|
|
979
|
+
Edge)
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
def fold_visit(schema, state, method, values, core):
|
|
983
|
+
visit = visit_method(
|
|
984
|
+
schema,
|
|
985
|
+
state,
|
|
986
|
+
method,
|
|
987
|
+
values,
|
|
988
|
+
core)
|
|
989
|
+
|
|
990
|
+
return visit
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
def divide_process(schema, state, values, core):
|
|
994
|
+
# daughter_configs must have a config per daughter
|
|
995
|
+
|
|
996
|
+
daughter_configs = values.get(
|
|
997
|
+
'daughter_configs',
|
|
998
|
+
[{} for index in range(values['divisions'])])
|
|
999
|
+
|
|
1000
|
+
if 'config' not in state:
|
|
1001
|
+
return daughter_configs
|
|
1002
|
+
|
|
1003
|
+
existing_config = state['config']
|
|
1004
|
+
|
|
1005
|
+
divisions = []
|
|
1006
|
+
for index in range(values['divisions']):
|
|
1007
|
+
daughter_config = copy.deepcopy(
|
|
1008
|
+
existing_config)
|
|
1009
|
+
daughter_config = deep_merge(
|
|
1010
|
+
daughter_config,
|
|
1011
|
+
daughter_configs[index])
|
|
1012
|
+
|
|
1013
|
+
# TODO: provide a way to override inputs and outputs
|
|
1014
|
+
daughter_state = {
|
|
1015
|
+
'address': state['address'],
|
|
1016
|
+
'config': daughter_config,
|
|
1017
|
+
'inputs': copy.deepcopy(state['inputs']),
|
|
1018
|
+
'outputs': copy.deepcopy(state['outputs'])}
|
|
1019
|
+
|
|
1020
|
+
if 'interval' in state:
|
|
1021
|
+
daughter_state['interval'] = state['interval']
|
|
1022
|
+
|
|
1023
|
+
divisions.append(daughter_state)
|
|
1024
|
+
|
|
1025
|
+
return divisions
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
def serialize_process(schema, value, core):
|
|
1029
|
+
"""Serialize a process to a JSON-safe representation."""
|
|
1030
|
+
# TODO -- need to get back the protocol: address and the config
|
|
1031
|
+
process = value.copy()
|
|
1032
|
+
process['config'] = core.serialize(
|
|
1033
|
+
process['instance'].config_schema,
|
|
1034
|
+
process['config'])
|
|
1035
|
+
del process['instance']
|
|
1036
|
+
return process
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
def deserialize_process(schema, encoded, core):
|
|
1040
|
+
"""Deserialize a process from a serialized state.
|
|
1041
|
+
|
|
1042
|
+
This function is used by the type system to deserialize a process.
|
|
1043
|
+
|
|
1044
|
+
:param encoded: A JSON-safe representation of the process.
|
|
1045
|
+
:param bindings: The bindings to use for deserialization.
|
|
1046
|
+
:param core: The type system to use for deserialization.
|
|
1047
|
+
|
|
1048
|
+
:returns: The deserialized state with an instantiated process.
|
|
1049
|
+
"""
|
|
1050
|
+
encoded = encoded or {}
|
|
1051
|
+
schema = schema or {}
|
|
1052
|
+
|
|
1053
|
+
default = core.default(schema)
|
|
1054
|
+
deserialized = deep_merge(default, encoded)
|
|
1055
|
+
|
|
1056
|
+
if not deserialized.get('address'):
|
|
1057
|
+
return deserialized
|
|
1058
|
+
|
|
1059
|
+
protocol, address = deserialized['address'].split(':', 1)
|
|
1060
|
+
|
|
1061
|
+
existing_instance = 'instance' in deserialized and deserialized['instance']
|
|
1062
|
+
if existing_instance:
|
|
1063
|
+
instantiate = type(deserialized['instance'])
|
|
1064
|
+
else:
|
|
1065
|
+
process_lookup = core.protocol_registry.access(protocol)
|
|
1066
|
+
if not process_lookup:
|
|
1067
|
+
raise Exception(f'protocol "{protocol}" not implemented')
|
|
1068
|
+
|
|
1069
|
+
instantiate = process_lookup(core, address)
|
|
1070
|
+
if not instantiate:
|
|
1071
|
+
raise Exception(f'process "{address}" not found')
|
|
1072
|
+
|
|
1073
|
+
config = core.deserialize(
|
|
1074
|
+
instantiate.config_schema,
|
|
1075
|
+
deserialized.get('config', {}))
|
|
1076
|
+
|
|
1077
|
+
interval = core.deserialize(
|
|
1078
|
+
'interval',
|
|
1079
|
+
deserialized.get('interval'))
|
|
1080
|
+
|
|
1081
|
+
if interval is None:
|
|
1082
|
+
interval = core.default(
|
|
1083
|
+
schema.get(
|
|
1084
|
+
'interval',
|
|
1085
|
+
'interval'))
|
|
1086
|
+
|
|
1087
|
+
if existing_instance:
|
|
1088
|
+
process = deserialized['instance']
|
|
1089
|
+
else:
|
|
1090
|
+
process = instantiate(
|
|
1091
|
+
config,
|
|
1092
|
+
core=core)
|
|
1093
|
+
|
|
1094
|
+
deserialized['instance'] = process
|
|
1095
|
+
|
|
1096
|
+
# TODO: this mutating the original value directly into
|
|
1097
|
+
# the return value is weird (?)
|
|
1098
|
+
shared = deserialized.get('shared', {})
|
|
1099
|
+
deserialized['shared'] = {}
|
|
1100
|
+
if shared:
|
|
1101
|
+
for step_id, step_config in shared.items():
|
|
1102
|
+
step = deserialize_step(
|
|
1103
|
+
'step',
|
|
1104
|
+
step_config,
|
|
1105
|
+
core)
|
|
1106
|
+
|
|
1107
|
+
step['instance'].register_shared(
|
|
1108
|
+
process)
|
|
1109
|
+
|
|
1110
|
+
deserialized['shared'][step_id] = step
|
|
1111
|
+
|
|
1112
|
+
deserialized['config'] = config
|
|
1113
|
+
deserialized['interval'] = interval
|
|
1114
|
+
deserialized['_inputs'] = copy.deepcopy(
|
|
1115
|
+
deserialized['instance'].inputs())
|
|
1116
|
+
deserialized['_outputs'] = copy.deepcopy(
|
|
1117
|
+
deserialized['instance'].outputs())
|
|
1118
|
+
|
|
1119
|
+
return deserialized
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
def deserialize_step(schema, encoded, core):
|
|
1123
|
+
default = core.default(schema)
|
|
1124
|
+
deserialized = deep_merge(default, encoded)
|
|
1125
|
+
|
|
1126
|
+
if not deserialized['address']:
|
|
1127
|
+
return deserialized
|
|
1128
|
+
|
|
1129
|
+
protocol, address = deserialized['address'].split(':', 1)
|
|
1130
|
+
|
|
1131
|
+
existing_instance = 'instance' in deserialized and deserialized['instance']
|
|
1132
|
+
if existing_instance:
|
|
1133
|
+
instantiate = type(deserialized['instance'])
|
|
1134
|
+
else:
|
|
1135
|
+
process_lookup = core.protocol_registry.access(protocol)
|
|
1136
|
+
if not process_lookup:
|
|
1137
|
+
raise Exception(f'protocol "{protocol}" not implemented')
|
|
1138
|
+
|
|
1139
|
+
instantiate = process_lookup(core, address)
|
|
1140
|
+
if not instantiate:
|
|
1141
|
+
raise Exception(f'process "{address}" not found')
|
|
1142
|
+
|
|
1143
|
+
config = core.deserialize(
|
|
1144
|
+
instantiate.config_schema,
|
|
1145
|
+
deserialized.get('config', {}))
|
|
1146
|
+
|
|
1147
|
+
if not existing_instance:
|
|
1148
|
+
process = instantiate(config, core=core)
|
|
1149
|
+
deserialized['instance'] = process
|
|
1150
|
+
|
|
1151
|
+
deserialized['config'] = config
|
|
1152
|
+
deserialized['_inputs'] = copy.deepcopy(
|
|
1153
|
+
deserialized['instance'].inputs())
|
|
1154
|
+
deserialized['_outputs'] = copy.deepcopy(
|
|
1155
|
+
deserialized['instance'].outputs())
|
|
1156
|
+
|
|
1157
|
+
return deserialized
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
# ===================
|
|
1161
|
+
# Process Type System
|
|
1162
|
+
# ===================
|
|
1163
|
+
|
|
1164
|
+
class ProcessTypes(TypeSystem):
|
|
1165
|
+
"""
|
|
1166
|
+
ProcessTypes class extends the TypeSystem class to include process types.
|
|
1167
|
+
It maintains a registry of process types and provides methods to register
|
|
1168
|
+
new process types, protocols, and emitters.
|
|
1169
|
+
"""
|
|
1170
|
+
|
|
1171
|
+
def __init__(self):
|
|
1172
|
+
super().__init__()
|
|
1173
|
+
self.process_registry = Registry()
|
|
1174
|
+
self.protocol_registry = Registry()
|
|
1175
|
+
|
|
1176
|
+
self.update_types(PROCESS_TYPES)
|
|
1177
|
+
self.register_protocols(BASE_PROTOCOLS)
|
|
1178
|
+
|
|
1179
|
+
self.register_process('composite', Composite)
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
def register_protocols(self, protocols):
|
|
1183
|
+
"""Register protocols with the core"""
|
|
1184
|
+
self.protocol_registry.register_multiple(protocols)
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
def register_process(
|
|
1188
|
+
self,
|
|
1189
|
+
name,
|
|
1190
|
+
process_data
|
|
1191
|
+
):
|
|
1192
|
+
"""
|
|
1193
|
+
Registers a new process type in the process registry.
|
|
1194
|
+
|
|
1195
|
+
Args:
|
|
1196
|
+
name (str): The name of the process type.
|
|
1197
|
+
process_data: The data associated with the process type.
|
|
1198
|
+
"""
|
|
1199
|
+
self.process_registry.register(name, process_data)
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
def register_processes(self, processes):
|
|
1203
|
+
for process_key, process_data in processes.items():
|
|
1204
|
+
self.register_process(
|
|
1205
|
+
process_key,
|
|
1206
|
+
process_data)
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
def initialize_edge_state(self, schema, path, edge):
|
|
1210
|
+
"""
|
|
1211
|
+
Initialize the state for an edge based on the schema and the edge.
|
|
1212
|
+
"""
|
|
1213
|
+
initial_state = edge['instance'].initial_state()
|
|
1214
|
+
if not initial_state:
|
|
1215
|
+
return initial_state
|
|
1216
|
+
|
|
1217
|
+
input_ports = copy.deepcopy(get_path(schema, path + ('_inputs',)))
|
|
1218
|
+
output_ports = copy.deepcopy(get_path(schema, path + ('_outputs',)))
|
|
1219
|
+
ports = {
|
|
1220
|
+
'_inputs': input_ports,
|
|
1221
|
+
'_outputs': output_ports}
|
|
1222
|
+
|
|
1223
|
+
input_state = {}
|
|
1224
|
+
if input_ports:
|
|
1225
|
+
input_state = self.project_edge(
|
|
1226
|
+
ports,
|
|
1227
|
+
edge,
|
|
1228
|
+
path[:-1],
|
|
1229
|
+
initial_state,
|
|
1230
|
+
ports_key='inputs')
|
|
1231
|
+
|
|
1232
|
+
output_state = {}
|
|
1233
|
+
if output_ports:
|
|
1234
|
+
output_state = self.project_edge(
|
|
1235
|
+
ports,
|
|
1236
|
+
edge,
|
|
1237
|
+
path[:-1],
|
|
1238
|
+
initial_state,
|
|
1239
|
+
ports_key='outputs')
|
|
1240
|
+
|
|
1241
|
+
state = deep_merge(input_state, output_state)
|
|
1242
|
+
|
|
1243
|
+
return state
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
def default_state(self, process_class, initial_state=None):
|
|
1247
|
+
default_config = self.default(
|
|
1248
|
+
process_class.config_schema)
|
|
1249
|
+
|
|
1250
|
+
instance = process_class(
|
|
1251
|
+
default_config,
|
|
1252
|
+
core=self)
|
|
1253
|
+
|
|
1254
|
+
state = {
|
|
1255
|
+
'_type': 'process',
|
|
1256
|
+
'address': f'local:!{process_class.__module__}.{process_class.__name__}',
|
|
1257
|
+
'config': default_config,
|
|
1258
|
+
'inputs': instance.default_inputs(),
|
|
1259
|
+
'outputs': instance.default_outputs()}
|
|
1260
|
+
|
|
1261
|
+
if issubclass(process_class, Process):
|
|
1262
|
+
state['interval'] = 1.0
|
|
1263
|
+
|
|
1264
|
+
if initial_state:
|
|
1265
|
+
state = deep_merge(
|
|
1266
|
+
state,
|
|
1267
|
+
initial_state)
|
|
1268
|
+
|
|
1269
|
+
return state
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
PROCESS_TYPES = {
|
|
1273
|
+
'protocol': {
|
|
1274
|
+
'_type': 'protocol',
|
|
1275
|
+
'_inherit': 'string'},
|
|
1276
|
+
|
|
1277
|
+
'emitter_mode': 'enum[none,all,stores,bridge,paths,ports]',
|
|
1278
|
+
|
|
1279
|
+
'interval': {
|
|
1280
|
+
'_type': 'interval',
|
|
1281
|
+
'_inherit': 'float',
|
|
1282
|
+
'_apply': 'set',
|
|
1283
|
+
'_default': '1.0'},
|
|
1284
|
+
|
|
1285
|
+
'step': {
|
|
1286
|
+
'_type': 'step',
|
|
1287
|
+
'_inherit': 'edge',
|
|
1288
|
+
'_apply': apply_process,
|
|
1289
|
+
'_serialize': serialize_process,
|
|
1290
|
+
'_deserialize': deserialize_step,
|
|
1291
|
+
'_check': check_process,
|
|
1292
|
+
'_fold': fold_visit,
|
|
1293
|
+
'_divide': divide_process,
|
|
1294
|
+
'_description': '',
|
|
1295
|
+
# TODO: support reference to type parameters from other states
|
|
1296
|
+
'address': 'protocol',
|
|
1297
|
+
'config': 'quote'},
|
|
1298
|
+
|
|
1299
|
+
# TODO: slice process to allow for navigating through a port
|
|
1300
|
+
'process': {
|
|
1301
|
+
'_type': 'process',
|
|
1302
|
+
'_inherit': 'edge',
|
|
1303
|
+
'_apply': apply_process,
|
|
1304
|
+
'_serialize': serialize_process,
|
|
1305
|
+
'_deserialize': deserialize_process,
|
|
1306
|
+
'_check': check_process,
|
|
1307
|
+
'_fold': fold_visit,
|
|
1308
|
+
'_divide': divide_process,
|
|
1309
|
+
'_description': '',
|
|
1310
|
+
# TODO: support reference to type parameters from other states
|
|
1311
|
+
'interval': 'interval',
|
|
1312
|
+
'address': 'protocol',
|
|
1313
|
+
'config': 'quote',
|
|
1314
|
+
'shared': 'map[step]'},
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
BASE_PROTOCOLS = {
|
|
1319
|
+
'local': local_lookup}
|
|
1320
|
+
|
|
@@ -306,6 +306,32 @@ class ProcessTypes(TypeSystem):
|
|
|
306
306
|
return state
|
|
307
307
|
|
|
308
308
|
|
|
309
|
+
def default_state(self, process_class, initial_state=None):
|
|
310
|
+
default_config = self.default(
|
|
311
|
+
process_class.config_schema)
|
|
312
|
+
|
|
313
|
+
instance = process_class(
|
|
314
|
+
default_config,
|
|
315
|
+
core=self)
|
|
316
|
+
|
|
317
|
+
state = {
|
|
318
|
+
'_type': 'process',
|
|
319
|
+
'address': f'local:!{process_class.__module__}.{process_class.__name__}',
|
|
320
|
+
'config': default_config,
|
|
321
|
+
'inputs': instance.default_inputs(),
|
|
322
|
+
'outputs': instance.default_outputs()}
|
|
323
|
+
|
|
324
|
+
if issubclass(process_class, Process):
|
|
325
|
+
state['interval'] = 1.0
|
|
326
|
+
|
|
327
|
+
if initial_state:
|
|
328
|
+
state = deep_merge(
|
|
329
|
+
state,
|
|
330
|
+
initial_state)
|
|
331
|
+
|
|
332
|
+
return state
|
|
333
|
+
|
|
334
|
+
|
|
309
335
|
PROCESS_TYPES = {
|
|
310
336
|
'protocol': {
|
|
311
337
|
'_type': 'protocol',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from process_bigraph.processes.parameter_scan import ToySystem, ODE, RunProcess, ParameterScan
|
|
2
2
|
from process_bigraph.processes.growth_division import Grow, Divide
|
|
3
|
+
from process_bigraph.emitter import BASE_EMITTERS
|
|
3
4
|
# from process_bigraph.experiments.minimal_gillespie import GillespieInterval, GillespieEvent
|
|
4
5
|
|
|
5
6
|
|
|
@@ -18,4 +19,8 @@ TOY_PROCESSES = {
|
|
|
18
19
|
def register_processes(core):
|
|
19
20
|
for name, process in TOY_PROCESSES.items():
|
|
20
21
|
core.register_process(name, process)
|
|
22
|
+
|
|
23
|
+
core = core.register_processes(
|
|
24
|
+
BASE_EMITTERS)
|
|
25
|
+
|
|
21
26
|
return core
|
|
@@ -7,10 +7,9 @@ import random
|
|
|
7
7
|
from bigraph_schema import default
|
|
8
8
|
from process_bigraph import register_types
|
|
9
9
|
|
|
10
|
-
from process_bigraph.composite import Process, Step, Composite, merge_collections
|
|
10
|
+
from process_bigraph.composite import Process, Step, Composite, merge_collections, match_star_path, ProcessTypes
|
|
11
11
|
|
|
12
|
-
from process_bigraph.processes.growth_division import grow_divide_agent
|
|
13
|
-
from process_bigraph.process_types import ProcessTypes
|
|
12
|
+
from process_bigraph.processes.growth_division import grow_divide_agent, Grow, Divide
|
|
14
13
|
from process_bigraph.emitter import emitter_from_wires, gather_emitter_results
|
|
15
14
|
|
|
16
15
|
|
|
@@ -871,16 +870,68 @@ def test_star_update(core):
|
|
|
871
870
|
assert star.state['Compartments']['2']['Shared Environment']['counts']['biomass'] == 2899
|
|
872
871
|
|
|
873
872
|
|
|
873
|
+
class GlobalProcess(Process):
|
|
874
|
+
config_schema = {}
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
def initialize(self, config):
|
|
878
|
+
pass
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
def test_default_process_state(core):
|
|
885
|
+
# provide some initial values
|
|
886
|
+
default_rate = {
|
|
887
|
+
'config': {
|
|
888
|
+
'rate': 0.001}}
|
|
889
|
+
|
|
890
|
+
# generate a default state for the Grow process
|
|
891
|
+
default_grow = core.default_state(
|
|
892
|
+
Grow,
|
|
893
|
+
default_rate)
|
|
894
|
+
|
|
895
|
+
# create a composite from the default process state
|
|
896
|
+
composite = Composite({
|
|
897
|
+
'state': {
|
|
898
|
+
'grow': default_grow,
|
|
899
|
+
'mass': 1.0}},
|
|
900
|
+
core=core)
|
|
901
|
+
|
|
902
|
+
# run the composite
|
|
903
|
+
composite.run(10.0)
|
|
904
|
+
|
|
905
|
+
# assert the process ran and the mass increased
|
|
906
|
+
assert composite.state['mass'] > 1.0
|
|
907
|
+
|
|
908
|
+
default_divide = core.default_state(
|
|
909
|
+
Divide)
|
|
910
|
+
|
|
911
|
+
assert 'interval' not in default_divide
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
def test_update_removal(core):
|
|
915
|
+
return {}
|
|
916
|
+
|
|
917
|
+
|
|
874
918
|
def test_stochastic_deterministic_composite(core):
|
|
875
919
|
# TODO make the demo for a hybrid stochastic/deterministic simulator
|
|
876
920
|
pass
|
|
877
921
|
|
|
878
922
|
|
|
923
|
+
def test_match_star_path(core):
|
|
924
|
+
assert match_star_path(["first", "list", "test"], ["first", "*", "test"])
|
|
925
|
+
assert not match_star_path(["first", "list", "tent"], ["first", "*", "test"])
|
|
926
|
+
assert match_star_path(["first", "list", "test"], ["first", "list", "test"])
|
|
927
|
+
|
|
928
|
+
|
|
879
929
|
if __name__ == '__main__':
|
|
880
930
|
core = ProcessTypes()
|
|
881
931
|
core = register_types(core)
|
|
882
932
|
|
|
883
933
|
test_default_config(core)
|
|
934
|
+
test_default_process_state(core)
|
|
884
935
|
test_merge_collections(core)
|
|
885
936
|
test_process(core)
|
|
886
937
|
test_composite(core)
|
|
@@ -900,3 +951,4 @@ if __name__ == '__main__':
|
|
|
900
951
|
test_merge_schema(core)
|
|
901
952
|
test_grow_divide(core)
|
|
902
953
|
test_star_update(core)
|
|
954
|
+
test_match_star_path(core)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "process-bigraph"
|
|
3
|
+
version = "0.0.41"
|
|
4
|
+
description = ""
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = "==3.12.9"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"bigraph-schema",
|
|
9
|
+
"matplotlib",
|
|
10
|
+
"pytest"
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[tool.setuptools]
|
|
14
|
+
packages = [
|
|
15
|
+
"process_bigraph"
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[tool.uv.sources]
|
|
19
|
+
bigraph-schema = { path = "../bigraph-schema", editable = true }
|
|
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
|
|
File without changes
|
{process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/experiments/minimal_gillespie.py
RENAMED
|
File without changes
|
{process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/growth_division.py
RENAMED
|
File without changes
|
{process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/parameter_scan.py
RENAMED
|
File without changes
|
|
File without changes
|
{process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|