diff --git a/examples/performance/runner.py b/examples/performance/runner.py new file mode 100644 index 0000000..bf8afc6 --- /dev/null +++ b/examples/performance/runner.py @@ -0,0 +1,105 @@ +# Model transformation experiment + +from state.devstate import DevState +from bootstrap.scd import bootstrap_scd +from uuid import UUID +from services.scd import SCD +from framework.conformance import Conformance +from services.od import OD +from transformation.matcher import match_od +from transformation.ramify import ramify +from transformation.cloner import clone_od +from transformation import rewriter +from services.bottom.V0 import Bottom +from services.primitives.integer_type import Integer +from concrete_syntax.plantuml import renderer as plantuml +from concrete_syntax.plantuml.make_url import make_url as make_plantuml_url +from concrete_syntax.textual_od import parser, renderer +from util.timer import Timer + +if __name__ == "__main__": + state = DevState() + root = state.read_root() # id: 0 + + # Meta-meta-model: a class diagram that describes the language of class diagrams + scd_mmm_id = bootstrap_scd(state) + int_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "Integer"))) + string_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "String"))) + + dsl_mm_cs = """ + Rare:Class + Many:Class + ManyB:Class + Other:Class + OtherB:Class + OtherC:Class + ass:Association(Many->ManyB) + """ + dsl_mm_id = parser.parse_od(state, dsl_mm_cs, mm=scd_mmm_id) + + dsl_m_cs = """ + rare:Rare + many0:Many + many1:Many + many2:Many + many3:Many + many4:Many + many5:ManyB + many6:ManyB + many7:ManyB + many8:ManyB + + :ass (many2->many6) + :ass (many3->many8) + + # other0:Other + # other1:OtherC + # other2:Other + # other3:Other + # other4:Other + # other5:OtherB + # other6:OtherB + # other7:OtherB + # other8:OtherB + # other9:OtherB + # other10:OtherB + # other11:OtherC + # other12:OtherC + # other13:OtherC + # other14:OtherC + + # other1099:OtherB + # other1199:OtherC + # other1299:OtherC + # other1399:OtherC + # other1499:OtherC + """ + dsl_m_id = parser.parse_od(state, dsl_m_cs, mm=dsl_mm_id) + + # RAMify MM + prefix = "RAM_" # all ramified types can be prefixed to distinguish them a bit more + ramified_mm_id = ramify(state, dsl_mm_id, prefix) + ramified_int_mm_id = ramify(state, int_mm_id, prefix) + + # LHS - pattern to match + + # TODO: enable more powerful constraints + pattern_cs = f""" + # object to match + rare:{prefix}Rare {{ + }} + + many:{prefix}Many + manyB:{prefix}ManyB + manyB2:{prefix}ManyB + """ + pattern_id = parser.parse_od(state, pattern_cs, mm=ramified_mm_id) + + with Timer("find all matches"): + matches = list(match_od(state, dsl_m_id, dsl_mm_id, pattern_id, ramified_mm_id)) + + + for match in matches: + print("\nMATCH:\n", match) + + print(len(matches), 'matches') diff --git a/examples/semantics/translational/runner.py b/examples/semantics/translational/runner.py deleted file mode 100644 index a156785..0000000 --- a/examples/semantics/translational/runner.py +++ /dev/null @@ -1,35 +0,0 @@ -from state.devstate import DevState -from bootstrap.scd import bootstrap_scd -from concrete_syntax.textual_od import parser, renderer -from concrete_syntax.plantuml.renderer import render_object_diagram, render_class_diagram -from concrete_syntax.plantuml.make_url import make_url -from api.od import ODAPI - -from transformation.ramify import ramify -from transformation.topify.topify import Topifier -from transformation.merger import merge_models - -from util import loader - -from examples.semantics.operational.simulator import Simulator, RandomDecisionMaker, InteractiveDecisionMaker -from examples.semantics.operational.port import models -from examples.semantics.operational.port.helpers import design_to_state, state_to_design, get_time -from examples.semantics.operational.port.renderer import render_port_textual, render_port_graphviz - -import os -THIS_DIR = os.path.dirname(__file__) - -# get file contents as string -def read_file(filename): - with open(THIS_DIR+'/'+filename) as file: - return file.read() - -if __name__ == "__main__": - state = DevState() - scd_mmm = bootstrap_scd(state) - - # Load merged Petri Net and Port meta-model: - merged_mm = loader.parse_and_check(state, read_file("merged_mm.od"), scd_mmm, "merged_mm.od") - - # Load Port initial runtime model: - port_m_rt_initial = loader.parse_and_check(state, models.port_rt_m_cs, merged_mm, "Port-M-RT-initial") diff --git a/examples/semantics/translational/runner_exec_pn.py b/examples/semantics/translational/runner_exec_pn.py new file mode 100644 index 0000000..9021e7f --- /dev/null +++ b/examples/semantics/translational/runner_exec_pn.py @@ -0,0 +1,79 @@ +from state.devstate import DevState +from bootstrap.scd import bootstrap_scd +from concrete_syntax.textual_od import parser, renderer +from concrete_syntax.plantuml.renderer import render_object_diagram, render_class_diagram +from concrete_syntax.plantuml.make_url import make_url +from api.od import ODAPI + +from transformation.ramify import ramify +from transformation.topify.topify import Topifier +from transformation.merger import merge_models +from transformation.ramify import ramify +from transformation.rule import RuleMatcherRewriter, ActionGenerator + +from util import loader + +from examples.semantics.operational.simulator import Simulator, RandomDecisionMaker, InteractiveDecisionMaker +from examples.semantics.operational.port import models +from examples.semantics.operational.port.helpers import design_to_state, state_to_design, get_time +from examples.semantics.operational.port.renderer import render_port_textual, render_port_graphviz +from examples.petrinet.renderer import render_petri_net +from examples.semantics.operational import simulator + +import os +import sys +THIS_DIR = os.path.dirname(__file__) + +# get file contents as string +def read_file(filename): + with open(THIS_DIR+'/'+filename) as file: + return file.read() + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage:") + print(f" python {__file__} model.od") + print("where `model.od` is a valid instance of Port+Petri-Net.") + sys.exit(1) + + model_to_open = sys.argv[1] + + state = DevState() + scd_mmm = bootstrap_scd(state) + + print('loading merged MM...') + merged_mm = loader.parse_and_check(state, read_file("merged_mm.od"), scd_mmm, "merged_mm.od", + check_conformance=False, # no need to check conformance every time + ) + + print('ramifying...') + ramified_merged_mm = ramify(state, merged_mm) + + print('loading petri net rules...') + rules = loader.load_rules(state, + lambda rule_name, kind: f"{THIS_DIR}/../../petrinet/operational_semantics/r_{rule_name}_{kind}.od", + ramified_merged_mm, + ["fire_transition"]) + + print('loading model...') + filename = f"{THIS_DIR}/{model_to_open}" + with open(filename, "r") as file: + model = loader.parse_and_check(state, file.read(), merged_mm, "model", + check_conformance=False, # no need to check conformance every time + ) + print('loaded', filename) + + print('ready!') + + matcher_rewriter = RuleMatcherRewriter(state, merged_mm, ramified_merged_mm) + action_generator = ActionGenerator(matcher_rewriter, rules) + + sim = simulator.Simulator( + action_generator=action_generator, + decision_maker=simulator.InteractiveDecisionMaker(auto_proceed=False), + # decision_maker=simulator.RandomDecisionMaker(seed=0), + renderer=lambda od: render_petri_net(od) + renderer.render_od(state, od.m, od.mm), + # renderer=lambda od: render_od(state, od.m, od.mm), + ) + + sim.run(ODAPI(state, model, merged_mm)) diff --git a/transformation/rule.py b/transformation/rule.py index b0c633b..39d1409 100644 --- a/transformation/rule.py +++ b/transformation/rule.py @@ -50,6 +50,9 @@ class RuleMatcherRewriter: lhs_match = lhs_matcher.__next__() x += 1 + # Uncomment to see matches attempted - may give insight into why your rule is not matching + # print(" lhs_match:", lhs_match) + nac_matched = False with Timer(f"MATCH NACs {rule_name}"): @@ -122,6 +125,11 @@ class RuleMatcherRewriter: return (cloned_m, rhs_match) + # This is often what you want: find a match, and execute the rule + def exec_on_first_match(self, host: UUID, rule: Rule, rule_name: str, in_place=False): + for lhs_match in self.match_rule(host, rule.lhs, rule.nacs, rule_name): + (rewritten_host, rhs_match) = self.exec_rule(host, rule.lhs, rule.rhs, lhs_match, rule_name, in_place) + return rewritten_host, lhs_match, rhs_match # Generator that yields actions in the format expected by 'Simulator' class class ActionGenerator: