From a575a1286f07cc12bf01c794007c71e39657cd9c Mon Sep 17 00:00:00 2001 From: Ryan Spangler Date: Tue, 16 Jul 2024 15:52:50 -0700 Subject: [PATCH 1/7] began on new composite emitter config --- process_bigraph/composite.py | 61 ++++++++++++++++++++++++++++++-- process_bigraph/process_types.py | 1 + process_bigraph/tests.py | 61 ++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/process_bigraph/composite.py b/process_bigraph/composite.py index 1df335f..db2fa30 100644 --- a/process_bigraph/composite.py +++ b/process_bigraph/composite.py @@ -594,8 +594,19 @@ class Composite(Process): 'bridge': { 'inputs': 'wires', 'outputs': 'wires'}, - 'global_time_precision': 'maybe[float]', - } + 'emitter': { + 'path': { + '_type': 'path', + '_default': ['emitter']}, + 'address': { + '_type': 'string', + '_default': 'local:ram-emitter'}, + 'config': 'tree[any]', + 'mode': { # this should be an enum: all, none, bridge, port + '_type': 'string', + '_default': 'none'}, + 'emit': 'wires'}, + 'global_time_precision': 'maybe[float]'} def __init__(self, config=None, core=None): @@ -665,6 +676,9 @@ def __init__(self, config=None, core=None): self.global_time_precision = self.config[ 'global_time_precision'] + self.add_emitter( + self.config['emitter']) + self.step_triggers = {} for step_path, step in self.step_paths.items(): @@ -730,6 +744,46 @@ def outputs(self): return self.process_schema.get('outputs', {}) + def read_emitter_config(self, emitter_config): + address = emitter_config.get('address', 'local:ram-emitter') + config = emitter_config.get('config', {}) + mode = emitter_config.get('mode', 'none') + + if mode == 'all': + inputs = { + key: [key] + for key in self.state.keys() + if not is_schema_key(key) and key not in self.config['emitter']['inputs']} + + elif mode == 'none': + inputs = emitter_config.get('emit', {}) + + elif mode == 'bridge': + inputs = {} + + elif mode == 'ports': + inputs = {} + + if not 'emit' in config: + config['emit'] = { + input: 'any' + for input in inputs} + + return { + '_type': 'step', + 'address': address, + 'config': config, + 'inputs': inputs} + + + def add_emitter(self, emitter_config): + path = emitter_config['path'] + step_config = self.read_emitter_config(emitter_config) + emitter = set_path( + {}, path, step_config) + self.merge(emitter) + + def merge(self, initial_state): self.state = self.core.merge( self.composition, @@ -1163,6 +1217,9 @@ def query(self, query=None): return result +# def StateEmitter(Emitter): + + # def test_emitter(): # composite = Composite({}) diff --git a/process_bigraph/process_types.py b/process_bigraph/process_types.py index 72e719a..08466f8 100644 --- a/process_bigraph/process_types.py +++ b/process_bigraph/process_types.py @@ -188,6 +188,7 @@ def deserialize_step(schema, encoded, core): 'address': 'protocol', 'config': 'tree[any]'}, + # TODO: slice process to allow for navigating through a port 'process': { '_type': 'process', '_inherit': 'edge', diff --git a/process_bigraph/tests.py b/process_bigraph/tests.py index e883055..ee7629c 100644 --- a/process_bigraph/tests.py +++ b/process_bigraph/tests.py @@ -384,6 +384,66 @@ def test_reaction(): 'inner': ['inner']}}}}}} +def test_emitter(core): + composite_schema = { + 'bridge': { + 'inputs': { + 'DNA': ['DNA'], + 'mRNA': ['mRNA']}, + 'outputs': { + 'DNA': ['DNA'], + 'mRNA': ['mRNA']}}, + + 'state': { + 'interval': { + '_type': 'step', + 'address': 'local:!process_bigraph.experiments.minimal_gillespie.GillespieInterval', + 'config': {'ktsc': '6e0'}, + 'inputs': { + 'DNA': ['DNA'], + 'mRNA': ['mRNA']}, + 'outputs': { + 'interval': ['event', 'interval']}}, + + 'event': { + '_type': 'process', + 'address': 'local:!process_bigraph.experiments.minimal_gillespie.GillespieEvent', + 'config': {'ktsc': 6e0}, + 'inputs': { + 'DNA': ['DNA'], + 'mRNA': ['mRNA']}, + 'outputs': { + 'mRNA': ['mRNA']}, + 'interval': '3.0'}}, + + 'emitter': { + 'emit': { + 'time': ['global_time'], + 'mRNA': ['mRNA'], + 'interval': ['event', 'interval']}}} + + gillespie = Composite( + composite_schema, + core=core) + + updates = gillespie.update({ + 'DNA': { + 'A gene': 11.0, + 'B gene': 5.0}, + 'mRNA': { + 'A mRNA': 33.3, + 'B mRNA': 2.1}}, + 1000.0) + + # TODO: make this work + results = gillespie.gather_results() + + assert 'mRNA' in updates[0] + # TODO: support omit as well as emit + + + + if __name__ == '__main__': core = ProcessTypes() @@ -394,4 +454,5 @@ def test_reaction(): test_infer(core) test_step_initialization(core) test_dependencies(core) + test_emitter(core) # test_reaction() From c0b5765a92f1985f5c41763ffb6a849bd69417e8 Mon Sep 17 00:00:00 2001 From: Ryan Spangler Date: Tue, 6 Aug 2024 16:25:42 -0700 Subject: [PATCH 2/7] emitter merged, we need to update the schema --- process_bigraph/composite.py | 31 ++++++++++++++++++---- process_bigraph/experiments/comets.py | 38 ++++++++++++++++----------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/process_bigraph/composite.py b/process_bigraph/composite.py index db2fa30..5dde4f4 100644 --- a/process_bigraph/composite.py +++ b/process_bigraph/composite.py @@ -676,8 +676,10 @@ def __init__(self, config=None, core=None): self.global_time_precision = self.config[ 'global_time_precision'] - self.add_emitter( - self.config['emitter']) + emitter_config = self.config.get('emitter') + if emitter_config: + self.add_emitter( + emitter_config) self.step_triggers = {} @@ -751,9 +753,9 @@ def read_emitter_config(self, emitter_config): if mode == 'all': inputs = { - key: [key] + key: [emitter_config.get('inputs', {}).get(key, key)] for key in self.state.keys() - if not is_schema_key(key) and key not in self.config['emitter']['inputs']} + if not is_schema_key(key)} elif mode == 'none': inputs = emitter_config.get('emit', {}) @@ -777,13 +779,25 @@ def read_emitter_config(self, emitter_config): def add_emitter(self, emitter_config): - path = emitter_config['path'] + path = tuple(emitter_config['path']) + step_config = self.read_emitter_config(emitter_config) emitter = set_path( {}, path, step_config) self.merge(emitter) + _, instance = self.core.slice( + self.composition, + self.state, + path) + + self.emitter_paths[path] = instance + self.step_paths[path] = instance + # TODO: merge needs to be schema aware, + # and since the results of the merge may + # entail a schema update, we need to return + # the new schema def merge(self, initial_state): self.state = self.core.merge( self.composition, @@ -1065,6 +1079,8 @@ def run_steps(self, step_paths): self.state, step_path) + import ipdb; ipdb.set_trace() + state = self.core.view_edge( self.composition, self.state, @@ -1128,6 +1144,9 @@ def gather_results(self, queries=None): emitter = get_path(self.state, path) results[path] = emitter['instance'].query(query) + # TODO: unnest the results? + # TODO: allow the results to be transposed + return results def update(self, state, interval): @@ -1201,6 +1220,8 @@ def __init__(self, config, core): def update(self, state) -> Dict: + import ipdb; ipdb.set_trace() + self.history.append(copy.deepcopy(state)) return {} diff --git a/process_bigraph/experiments/comets.py b/process_bigraph/experiments/comets.py index ed3bbfb..7c47586 100644 --- a/process_bigraph/experiments/comets.py +++ b/process_bigraph/experiments/comets.py @@ -465,25 +465,31 @@ def run_comets(): 'fields': ['fields'] } }, - 'emitter': { - '_type': 'step', - 'address': 'local:ram-emitter', - 'config': { - 'emit': { - 'fields': 'map', - 'time': 'float', - } - }, - 'inputs': { - 'fields': ['fields'], - 'time': ['global_time'] - } - } + # 'emitter': { + # '_type': 'step', + # 'address': 'local:ram-emitter', + # 'config': { + # 'emit': { + # 'fields': 'map', + # 'time': 'float', + # } + # }, + # 'inputs': { + # 'fields': ['fields'], + # 'time': ['global_time'] + # } + # } } - sim = Composite({'state': composite_state}, core=core) + sim = Composite({ + 'state': composite_state, + 'emitter': { + 'mode': 'all'}}, core=core) - sim.update({}, 100.0) + # sim = Composite({ + # 'state': composite_state}, core=core) + + sim.update({}, 10.0) results = sim.gather_results() From 1b3e9406b06a5cc082b92a4222950f2ef8f729f4 Mon Sep 17 00:00:00 2001 From: Ryan Spangler Date: Fri, 9 Aug 2024 15:12:06 -0700 Subject: [PATCH 3/7] adding a complete to merge to infer the resulting schema, emitter config option 'all' is working --- process_bigraph/composite.py | 8 ++++---- process_bigraph/experiments/comets.py | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/process_bigraph/composite.py b/process_bigraph/composite.py index 5dde4f4..e6723c5 100644 --- a/process_bigraph/composite.py +++ b/process_bigraph/composite.py @@ -804,6 +804,10 @@ def merge(self, initial_state): self.state, initial_state) + self.composition, self.state = self.core.complete( + self.composition, + self.state) + def process_update( self, @@ -1079,8 +1083,6 @@ def run_steps(self, step_paths): self.state, step_path) - import ipdb; ipdb.set_trace() - state = self.core.view_edge( self.composition, self.state, @@ -1220,8 +1222,6 @@ def __init__(self, config, core): def update(self, state) -> Dict: - import ipdb; ipdb.set_trace() - self.history.append(copy.deepcopy(state)) return {} diff --git a/process_bigraph/experiments/comets.py b/process_bigraph/experiments/comets.py index 7c47586..7138455 100644 --- a/process_bigraph/experiments/comets.py +++ b/process_bigraph/experiments/comets.py @@ -493,6 +493,8 @@ def run_comets(): results = sim.gather_results() + import ipdb; ipdb.set_trace() + print(results) From 8f6a4938551ad7a327faba634d14b515157d1e44 Mon Sep 17 00:00:00 2001 From: Ryan Spangler Date: Fri, 9 Aug 2024 15:38:21 -0700 Subject: [PATCH 4/7] working on emitter config --- process_bigraph/composite.py | 10 +++++++--- process_bigraph/experiments/comets.py | 5 ++++- process_bigraph/process_types.py | 3 +++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/process_bigraph/composite.py b/process_bigraph/composite.py index e6723c5..661daf6 100644 --- a/process_bigraph/composite.py +++ b/process_bigraph/composite.py @@ -310,6 +310,12 @@ def __init__(self, config=None, core=None): self.config_schema, config) + # TODO: validate your config after filling, report if anything + # is off + # print(self.core.validate_state( + # self.config_schema, + # config)) + def initial_state(self): return {} @@ -602,9 +608,7 @@ class Composite(Process): '_type': 'string', '_default': 'local:ram-emitter'}, 'config': 'tree[any]', - 'mode': { # this should be an enum: all, none, bridge, port - '_type': 'string', - '_default': 'none'}, + 'mode': 'emitter_mode', 'emit': 'wires'}, 'global_time_precision': 'maybe[float]'} diff --git a/process_bigraph/experiments/comets.py b/process_bigraph/experiments/comets.py index 7138455..fe39cfe 100644 --- a/process_bigraph/experiments/comets.py +++ b/process_bigraph/experiments/comets.py @@ -486,8 +486,11 @@ def run_comets(): 'emitter': { 'mode': 'all'}}, core=core) + # TODO: this should fail validation # sim = Composite({ - # 'state': composite_state}, core=core) + # 'state': composite_state, + # 'emitter': { + # 'mode': 'pluto'}}, core=core) sim.update({}, 10.0) diff --git a/process_bigraph/process_types.py b/process_bigraph/process_types.py index 08466f8..d5230ad 100644 --- a/process_bigraph/process_types.py +++ b/process_bigraph/process_types.py @@ -168,6 +168,9 @@ def deserialize_step(schema, encoded, core): '_type': 'protocol', '_inherit': 'string'}, + # TODO: have the default enum be the first option + 'emitter_mode': 'enum[none,all,paths,bridge,port]', + 'interval': { '_type': 'interval', '_inherit': 'float', From 6b54966e17cf61fde36d223fbc542f314d83c3c8 Mon Sep 17 00:00:00 2001 From: Ryan Spangler Date: Wed, 14 Aug 2024 16:45:41 -0700 Subject: [PATCH 5/7] adding default method to init --- process_bigraph/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process_bigraph/__init__.py b/process_bigraph/__init__.py index 316a8d5..3da93d6 100644 --- a/process_bigraph/__init__.py +++ b/process_bigraph/__init__.py @@ -1,5 +1,5 @@ import pprint -from bigraph_schema.registry import deep_merge +from bigraph_schema.registry import deep_merge, default from process_bigraph.composite import Process, Step, Composite, ProcessTypes, interval_time_precision From 6b5849f392077012a6ebc6697c9b00142b68db5e Mon Sep 17 00:00:00 2001 From: Ryan Spangler Date: Wed, 14 Aug 2024 16:48:24 -0700 Subject: [PATCH 6/7] fix extra addopts in pytest.ini --- pytest.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pytest.ini b/pytest.ini index 72ca674..01efc49 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,8 +1,7 @@ [pytest] -addopts = --ignore=setup.py +addopts = --ignore=setup.py --ignore=process_bigraph/experiments/comets.py python_files = *.py #skip comets tests -addopts = --ignore=process_bigraph/experiments/comets.py testpaths = process_bigraph markers = slow: indicates slow tests (deselect with '-m "not slow"') From deb26eb211ced067fc92014c805513c52cdb1eed Mon Sep 17 00:00:00 2001 From: Ryan Spangler Date: Fri, 16 Aug 2024 15:09:51 -0700 Subject: [PATCH 7/7] fix emitter none mode --- process_bigraph/composite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process_bigraph/composite.py b/process_bigraph/composite.py index 661daf6..1f6d420 100644 --- a/process_bigraph/composite.py +++ b/process_bigraph/composite.py @@ -681,7 +681,7 @@ def __init__(self, config=None, core=None): 'global_time_precision'] emitter_config = self.config.get('emitter') - if emitter_config: + if emitter_config and not emitter_config.get('mode', 'none') == 'none': self.add_emitter( emitter_config)