process-bigraph 0.0.1__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.1/PKG-INFO +49 -0
- process-bigraph-0.0.1/README.md +23 -0
- process-bigraph-0.0.1/process_bigraph/__init__.py +0 -0
- process-bigraph-0.0.1/process_bigraph/composite.py +296 -0
- process-bigraph-0.0.1/process_bigraph.egg-info/PKG-INFO +49 -0
- process-bigraph-0.0.1/process_bigraph.egg-info/SOURCES.txt +9 -0
- process-bigraph-0.0.1/process_bigraph.egg-info/dependency_links.txt +1 -0
- process-bigraph-0.0.1/process_bigraph.egg-info/requires.txt +1 -0
- process-bigraph-0.0.1/process_bigraph.egg-info/top_level.txt +1 -0
- process-bigraph-0.0.1/setup.cfg +4 -0
- process-bigraph-0.0.1/setup.py +49 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: process-bigraph
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: UNKNOWN
|
|
5
|
+
Home-page: https://github.com/vivarium-collective/process-bigraph
|
|
6
|
+
Author: Ryan Spangler, Eran Agmon
|
|
7
|
+
Author-email: ryan.spangler@gmail.com, agmon.eran@gmail.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Platform: UNKNOWN
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Requires-Python: >=3.6
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Process-Bigraph
|
|
26
|
+
|
|
27
|
+
**Process-Bigraph** is...
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="https://github.com/vivarium-collective/bigraph-viz/blob/main/doc/_static/cell_structure_function.png?raw=true" width="600" alt="Bigraph-viz example">
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
## What are Process Bigraphs?
|
|
34
|
+
|
|
35
|
+
## Getting Started
|
|
36
|
+
|
|
37
|
+
### Installation
|
|
38
|
+
|
|
39
|
+
You can install `process-bigraph` using pip:
|
|
40
|
+
|
|
41
|
+
```console
|
|
42
|
+
pip install process-bigraph
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Tutorial
|
|
46
|
+
|
|
47
|
+
To get started with Process-Bigraph, explore the *tutorial*. coming soon...
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Process-Bigraph
|
|
2
|
+
|
|
3
|
+
**Process-Bigraph** is...
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="https://github.com/vivarium-collective/bigraph-viz/blob/main/doc/_static/cell_structure_function.png?raw=true" width="600" alt="Bigraph-viz example">
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
## What are Process Bigraphs?
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
### Installation
|
|
14
|
+
|
|
15
|
+
You can install `process-bigraph` using pip:
|
|
16
|
+
|
|
17
|
+
```console
|
|
18
|
+
pip install process-bigraph
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Tutorial
|
|
22
|
+
|
|
23
|
+
To get started with Process-Bigraph, explore the *tutorial*. coming soon...
|
|
File without changes
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from bigraph_schema import fill, registry_registry, type_registry, apply_update
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def hierarchy_depth(hierarchy, path=()):
|
|
6
|
+
"""
|
|
7
|
+
Create a mapping of every path in the hierarchy to the node living at
|
|
8
|
+
that path in the hierarchy.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
base = {}
|
|
12
|
+
|
|
13
|
+
for key, inner in hierarchy.items():
|
|
14
|
+
down = tuple(path + (key,))
|
|
15
|
+
if isinstance(inner, dict):
|
|
16
|
+
base.update(hierarchy_depth(inner, down))
|
|
17
|
+
else:
|
|
18
|
+
base[down] = inner
|
|
19
|
+
|
|
20
|
+
return base
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def find_processes(state):
|
|
24
|
+
found = {}
|
|
25
|
+
|
|
26
|
+
for key, inner in state.items():
|
|
27
|
+
if isinstance(inner, Process):
|
|
28
|
+
found[key] = inner
|
|
29
|
+
elif isinstance(inner, dict):
|
|
30
|
+
result = find_processes(inner)
|
|
31
|
+
if result:
|
|
32
|
+
found[key] = result
|
|
33
|
+
|
|
34
|
+
return found
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def find_process_paths(state):
|
|
38
|
+
processes = find_processes(state)
|
|
39
|
+
return hierarchy_depth(processes)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def empty_front(time):
|
|
43
|
+
return {
|
|
44
|
+
'time': time,
|
|
45
|
+
'update': {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# deal with steps vs temporal process vs edges
|
|
49
|
+
|
|
50
|
+
class Process:
|
|
51
|
+
config_schema = {}
|
|
52
|
+
|
|
53
|
+
def __init__(self, config=None):
|
|
54
|
+
if config is None:
|
|
55
|
+
config = {}
|
|
56
|
+
|
|
57
|
+
self.config_schema.setdefault(
|
|
58
|
+
'timestep',
|
|
59
|
+
{'_type': 'float', '_default': '1.0'}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
self.config = fill(
|
|
63
|
+
self.config_schema,
|
|
64
|
+
config
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@abc.abstractmethod
|
|
68
|
+
def schema(self):
|
|
69
|
+
return {}
|
|
70
|
+
|
|
71
|
+
def calculate_timestep(self, state):
|
|
72
|
+
return self.config['timestep']
|
|
73
|
+
|
|
74
|
+
@abc.abstractmethod
|
|
75
|
+
def update(self, state, interval):
|
|
76
|
+
return {}
|
|
77
|
+
|
|
78
|
+
# TODO: should we include run(interval) here?
|
|
79
|
+
# process would have to maintain state
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class Composite(Process):
|
|
83
|
+
config_schema = {
|
|
84
|
+
'schema': 'tree[any]',
|
|
85
|
+
'bridge': 'wires',
|
|
86
|
+
'instance': 'tree[any]',
|
|
87
|
+
'initial_time': 'float',
|
|
88
|
+
'global_time_precision': 'maybe[float]',
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
def __init__(self, config=None):
|
|
92
|
+
super().__init__(config)
|
|
93
|
+
self.global_time = self.config['initial_time']
|
|
94
|
+
self.state = fill(
|
|
95
|
+
self.config['schema'],
|
|
96
|
+
self.config['instance']
|
|
97
|
+
)
|
|
98
|
+
self.process_paths = find_process_paths(state)
|
|
99
|
+
self.front: Dict = {
|
|
100
|
+
path: empty_front(self.global_time)
|
|
101
|
+
for path in self.process_paths
|
|
102
|
+
}
|
|
103
|
+
self.global_time_precision = self.config['global_time_precision']
|
|
104
|
+
|
|
105
|
+
def schema(self):
|
|
106
|
+
return self.config['schema']
|
|
107
|
+
|
|
108
|
+
def run_process(self, path, process):
|
|
109
|
+
if path not in self.front:
|
|
110
|
+
self.front[path] = empty_front(self.global_time)
|
|
111
|
+
process_time = self.front[path]['time']
|
|
112
|
+
if process_time <= self.global_time:
|
|
113
|
+
if self.front[path].get('future'):
|
|
114
|
+
future_front = self.front[path]['future']
|
|
115
|
+
process_timestep = future_front['timestep']
|
|
116
|
+
store = future_front['store']
|
|
117
|
+
state = future_front['state']
|
|
118
|
+
del self.front[path]['future']
|
|
119
|
+
else:
|
|
120
|
+
# get the time step
|
|
121
|
+
store, state = self._process_state(path)
|
|
122
|
+
process_timestep = process.calculate_timestep(state)
|
|
123
|
+
|
|
124
|
+
if force_complete:
|
|
125
|
+
# force the process to complete at end_time
|
|
126
|
+
future = min(process_time + process_timestep, end_time)
|
|
127
|
+
else:
|
|
128
|
+
future = process_time + process_timestep
|
|
129
|
+
if self.global_time_precision is not None:
|
|
130
|
+
# set future time based on global_time_precision
|
|
131
|
+
future = round(future, self.global_time_precision)
|
|
132
|
+
|
|
133
|
+
if future <= end_time:
|
|
134
|
+
|
|
135
|
+
update = self._process_update(
|
|
136
|
+
path,
|
|
137
|
+
process,
|
|
138
|
+
store,
|
|
139
|
+
state,
|
|
140
|
+
process_timestep
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# update front, to be applied at its projected time
|
|
144
|
+
self.front[path]['time'] = future
|
|
145
|
+
self.front[path]['update'] = update
|
|
146
|
+
|
|
147
|
+
# absolute timestep
|
|
148
|
+
timestep = future - self.global_time
|
|
149
|
+
if timestep < full_step:
|
|
150
|
+
full_step = timestep
|
|
151
|
+
else:
|
|
152
|
+
# absolute timestep
|
|
153
|
+
timestep = future - self.global_time
|
|
154
|
+
if timestep < full_step:
|
|
155
|
+
full_step = timestep
|
|
156
|
+
|
|
157
|
+
else:
|
|
158
|
+
# don't shoot past processes that didn't run this time
|
|
159
|
+
process_delay = process_time - self.global_time
|
|
160
|
+
if process_delay < full_step:
|
|
161
|
+
full_step = process_delay
|
|
162
|
+
|
|
163
|
+
return full_step
|
|
164
|
+
|
|
165
|
+
def run(self, interval, force_complete=False):
|
|
166
|
+
end_time = self.global_time + interval
|
|
167
|
+
while self.global_time < end_time or force_complete:
|
|
168
|
+
full_step = math.inf
|
|
169
|
+
for path, process in self.process_paths.items():
|
|
170
|
+
full_step = self.run_process(process, path)
|
|
171
|
+
|
|
172
|
+
# apply updates based on process times in self.front
|
|
173
|
+
if full_step == math.inf:
|
|
174
|
+
# no processes ran, jump to next process
|
|
175
|
+
next_event = end_time
|
|
176
|
+
for path in self.front.keys():
|
|
177
|
+
if self.front[path]['time'] < next_event:
|
|
178
|
+
next_event = self.front[path]['time']
|
|
179
|
+
self.global_time = next_event
|
|
180
|
+
|
|
181
|
+
elif self.global_time + full_step <= end_time:
|
|
182
|
+
# at least one process ran within the interval
|
|
183
|
+
# increase the time, apply updates, and continue
|
|
184
|
+
self.global_time += full_step
|
|
185
|
+
|
|
186
|
+
# advance all quiet processes to current time
|
|
187
|
+
for quiet in quiet_paths:
|
|
188
|
+
self.front[quiet]['time'] = self.global_time
|
|
189
|
+
|
|
190
|
+
# apply updates that are behind global time
|
|
191
|
+
updates = []
|
|
192
|
+
paths = []
|
|
193
|
+
for path, advance in self.front.items():
|
|
194
|
+
if advance['time'] <= self.global_time \
|
|
195
|
+
and advance['update']:
|
|
196
|
+
new_update = advance['update']
|
|
197
|
+
updates.append(new_update)
|
|
198
|
+
advance['update'] = {}
|
|
199
|
+
paths.append(path)
|
|
200
|
+
|
|
201
|
+
self._send_updates(updates)
|
|
202
|
+
|
|
203
|
+
# display and emit
|
|
204
|
+
if self.progress_bar:
|
|
205
|
+
print_progress_bar(self.global_time, end_time)
|
|
206
|
+
if self.emit_step == 1:
|
|
207
|
+
self._emit_store_data()
|
|
208
|
+
elif emit_time <= self.global_time:
|
|
209
|
+
while emit_time <= self.global_time:
|
|
210
|
+
self._emit_store_data()
|
|
211
|
+
emit_time += self.emit_step
|
|
212
|
+
|
|
213
|
+
else:
|
|
214
|
+
# all processes have run past the interval
|
|
215
|
+
self.global_time = end_time
|
|
216
|
+
|
|
217
|
+
if force_complete and self.global_time == end_time:
|
|
218
|
+
force_complete = False
|
|
219
|
+
|
|
220
|
+
def update(self, state, interval):
|
|
221
|
+
# do everything
|
|
222
|
+
|
|
223
|
+
# this needs to go through the bridge
|
|
224
|
+
self.state = apply_update(
|
|
225
|
+
self.schema,
|
|
226
|
+
self.state,
|
|
227
|
+
state
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
self.run(interval)
|
|
231
|
+
|
|
232
|
+
# pull the update out of the state and return it
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class IncreaseProcess(Process):
|
|
236
|
+
config_schema = {
|
|
237
|
+
'rate': {
|
|
238
|
+
'_type': 'float',
|
|
239
|
+
'_default': '0.1',
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
def __init__(self, config=None):
|
|
244
|
+
super().__init__(config)
|
|
245
|
+
|
|
246
|
+
def schema(self):
|
|
247
|
+
return {
|
|
248
|
+
'level': 'float',
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
def update(self, state, interval):
|
|
252
|
+
return {
|
|
253
|
+
'level': state['level'] * self.config['rate']
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def test_process():
|
|
258
|
+
process = IncreaseProcess({'rate': 0.2})
|
|
259
|
+
schema = process.schema()
|
|
260
|
+
state = fill(schema)
|
|
261
|
+
update = process.update({'level': 5.5}, 1.0)
|
|
262
|
+
new_state = apply_update(schema, state, update)
|
|
263
|
+
assert new_state['level'] == 1.1
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
{"level":"float","down":{"a":"int"}}
|
|
267
|
+
|
|
268
|
+
def test_composite():
|
|
269
|
+
# TODO: add support for the various vivarium emitters
|
|
270
|
+
|
|
271
|
+
increase = IncreaseProcess({'rate': 0.3})
|
|
272
|
+
composite = Composite({
|
|
273
|
+
'schema': {
|
|
274
|
+
'increase': 'process[level:float]',
|
|
275
|
+
# 'increase': 'process[{"level":"float","down":{"a":"int"}}]',
|
|
276
|
+
'value': 'float',
|
|
277
|
+
},
|
|
278
|
+
'bridge': {
|
|
279
|
+
'exchange': 'value'
|
|
280
|
+
},
|
|
281
|
+
'instance': {
|
|
282
|
+
'increase': increase,
|
|
283
|
+
'wires': {
|
|
284
|
+
'level': 'value'
|
|
285
|
+
},
|
|
286
|
+
'value': 11.11,
|
|
287
|
+
},
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
composite.update({'exchange': 3.33}, 10.0)
|
|
291
|
+
import ipdb; ipdb.set_trace()
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
if __name__ == '__main__':
|
|
295
|
+
test_process()
|
|
296
|
+
test_composite()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: process-bigraph
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: UNKNOWN
|
|
5
|
+
Home-page: https://github.com/vivarium-collective/process-bigraph
|
|
6
|
+
Author: Ryan Spangler, Eran Agmon
|
|
7
|
+
Author-email: ryan.spangler@gmail.com, agmon.eran@gmail.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Platform: UNKNOWN
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Requires-Python: >=3.6
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Process-Bigraph
|
|
26
|
+
|
|
27
|
+
**Process-Bigraph** is...
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="https://github.com/vivarium-collective/bigraph-viz/blob/main/doc/_static/cell_structure_function.png?raw=true" width="600" alt="Bigraph-viz example">
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
## What are Process Bigraphs?
|
|
34
|
+
|
|
35
|
+
## Getting Started
|
|
36
|
+
|
|
37
|
+
### Installation
|
|
38
|
+
|
|
39
|
+
You can install `process-bigraph` using pip:
|
|
40
|
+
|
|
41
|
+
```console
|
|
42
|
+
pip install process-bigraph
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Tutorial
|
|
46
|
+
|
|
47
|
+
To get started with Process-Bigraph, explore the *tutorial*. coming soon...
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
process_bigraph/__init__.py
|
|
4
|
+
process_bigraph/composite.py
|
|
5
|
+
process_bigraph.egg-info/PKG-INFO
|
|
6
|
+
process_bigraph.egg-info/SOURCES.txt
|
|
7
|
+
process_bigraph.egg-info/dependency_links.txt
|
|
8
|
+
process_bigraph.egg-info/requires.txt
|
|
9
|
+
process_bigraph.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bigraph-schema
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
process_bigraph
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from setuptools import setup, find_packages
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
VERSION = '0.0.1'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
with open("README.md", "r") as readme:
|
|
9
|
+
description = readme.read()
|
|
10
|
+
# Patch the relative links to absolute URLs that will work on PyPI.
|
|
11
|
+
description2 = re.sub(
|
|
12
|
+
r']\(([\w/.-]+\.png)\)',
|
|
13
|
+
r'](https://github.com/vivarium-collective/process-bigraph/raw/main/\1)',
|
|
14
|
+
description)
|
|
15
|
+
long_description = re.sub(
|
|
16
|
+
r']\(([\w/.-]+)\)',
|
|
17
|
+
r'](https://github.com/vivarium-collective/process-bigraph/blob/main/\1)',
|
|
18
|
+
description2)
|
|
19
|
+
|
|
20
|
+
setup(
|
|
21
|
+
name="process-bigraph",
|
|
22
|
+
version=VERSION,
|
|
23
|
+
author="Ryan Spangler, Eran Agmon",
|
|
24
|
+
author_email="ryan.spangler@gmail.com, agmon.eran@gmail.com",
|
|
25
|
+
description="",
|
|
26
|
+
long_description=long_description,
|
|
27
|
+
long_description_content_type="text/markdown",
|
|
28
|
+
url="https://github.com/vivarium-collective/process-bigraph",
|
|
29
|
+
packages=find_packages(),
|
|
30
|
+
classifiers=[
|
|
31
|
+
"Development Status :: 3 - Alpha",
|
|
32
|
+
"Intended Audience :: Developers",
|
|
33
|
+
"License :: OSI Approved :: MIT License",
|
|
34
|
+
"Operating System :: OS Independent",
|
|
35
|
+
"Programming Language :: Python",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3.6",
|
|
38
|
+
"Programming Language :: Python :: 3.7",
|
|
39
|
+
"Programming Language :: Python :: 3.8",
|
|
40
|
+
"Programming Language :: Python :: 3.9",
|
|
41
|
+
"Programming Language :: Python :: 3.10",
|
|
42
|
+
"Programming Language :: Python :: 3.11",
|
|
43
|
+
],
|
|
44
|
+
python_requires=">=3.6",
|
|
45
|
+
install_requires=[
|
|
46
|
+
# List your package dependencies here
|
|
47
|
+
"bigraph-schema"
|
|
48
|
+
],
|
|
49
|
+
)
|