add examples
This commit is contained in:
parent
8504ba52f6
commit
42757ddc4f
35 changed files with 1104 additions and 609 deletions
62
examples/cbd/fibonacci_runner.py
Normal file
62
examples/cbd/fibonacci_runner.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
from state.devstate import DevState
|
||||
from bootstrap.scd import bootstrap_scd
|
||||
|
||||
from api.od import ODAPI
|
||||
|
||||
from concrete_syntax.common import indent
|
||||
from concrete_syntax.textual_od import renderer as od_renderer
|
||||
from concrete_syntax.plantuml import renderer as plantuml
|
||||
from concrete_syntax.plantuml.make_url import make_url as make_plantuml_url
|
||||
from concrete_syntax.graphviz.make_url import make_url as make_graphviz_url
|
||||
from concrete_syntax.graphviz import renderer as graphviz
|
||||
|
||||
from transformation.matcher.mvs_adapter import match_od
|
||||
from transformation.rewriter import rewrite
|
||||
from transformation.cloner import clone_od
|
||||
from transformation.ramify import ramify
|
||||
from transformation.rule import RuleMatcherRewriter, ActionGenerator
|
||||
|
||||
from examples.semantics.operational import simulator
|
||||
|
||||
from util import loader
|
||||
import models
|
||||
|
||||
|
||||
state = DevState()
|
||||
scd_mmm = bootstrap_scd(state)
|
||||
|
||||
print("Parsing models...")
|
||||
mm, mm_rt, m, m_rt_initial = models.load_fibonacci(state, scd_mmm)
|
||||
mm_rt_ramified = ramify(state, mm_rt)
|
||||
|
||||
# print("RT-MM")
|
||||
# print(make_plantuml_url(plantuml.render_class_diagram(state, mm_rt)))
|
||||
|
||||
# print("RAMIFIED RT-MM")
|
||||
# print(make_plantuml_url(plantuml.render_class_diagram(state, mm_rt_ramified)))
|
||||
|
||||
high_priority_rules, low_priority_rules = models.load_rules(state, mm_rt_ramified)
|
||||
|
||||
matcher_rewriter = RuleMatcherRewriter(state, mm_rt, mm_rt_ramified)
|
||||
|
||||
high_priority_actions = ActionGenerator(matcher_rewriter, high_priority_rules)
|
||||
low_priority_actions = ActionGenerator(matcher_rewriter, low_priority_rules)
|
||||
|
||||
# yields the currently enabled actions
|
||||
def generate_actions(od):
|
||||
at_least_one_match = yield from high_priority_actions(od)
|
||||
if not at_least_one_match:
|
||||
# Only if no other action is possible, can time advance:
|
||||
yield from low_priority_actions(od)
|
||||
|
||||
sim = simulator.Simulator(
|
||||
action_generator=generate_actions,
|
||||
# decision_maker=simulator.InteractiveDecisionMaker(auto_proceed=False),
|
||||
decision_maker=simulator.RandomDecisionMaker(seed=0),
|
||||
termination_condition=lambda od: "Time is up" if od.get_slot_value(od.get_all_instances("Clock")[0][1], "time") >= 10 else None,
|
||||
check_conformance=True,
|
||||
verbose=True,
|
||||
renderer=lambda od: od_renderer.render_od(state, od.m, od.mm, hide_names=False),
|
||||
)
|
||||
|
||||
sim.run(ODAPI(state, m_rt_initial, mm_rt))
|
||||
|
|
@ -1,71 +1,41 @@
|
|||
# This module loads all the models (including the transformation rules) and performs a conformance-check on them.
|
||||
from util import loader
|
||||
|
||||
import os
|
||||
from framework.conformance import Conformance, render_conformance_check_result
|
||||
from concrete_syntax.textual_od import parser
|
||||
from transformation.ramify import ramify
|
||||
THIS_DIR = os.path.dirname(__file__)
|
||||
|
||||
# get file contents as string
|
||||
def read_file(filename):
|
||||
dir = os.path.dirname(__file__)
|
||||
with open(dir+'/'+filename) as file:
|
||||
with open(THIS_DIR+'/'+filename) as file:
|
||||
return file.read()
|
||||
|
||||
def parse_and_check(state, m_cs, mm, descr: str):
|
||||
try:
|
||||
m = parser.parse_od(
|
||||
state,
|
||||
m_text=m_cs,
|
||||
mm=mm,
|
||||
)
|
||||
except Exception as e:
|
||||
e.add_note("While parsing model " + descr)
|
||||
raise
|
||||
try:
|
||||
conf = Conformance(state, m, mm)
|
||||
errors = conf.check_nominal()
|
||||
if len(errors) > 0:
|
||||
print(render_conformance_check_result(errors))
|
||||
except Exception as e:
|
||||
e.add_note("In model " + descr)
|
||||
raise
|
||||
return m
|
||||
|
||||
def get_metamodels(state, scd_mmm):
|
||||
def load_metamodels(state, scd_mmm):
|
||||
mm_cs = read_file('models/mm_design.od')
|
||||
mm_rt_cs = mm_cs + read_file('models/mm_runtime.od')
|
||||
|
||||
mm = parse_and_check(state, mm_cs, scd_mmm, "Design meta-model")
|
||||
mm_rt = parse_and_check(state, mm_rt_cs, scd_mmm, "Runtime meta-model")
|
||||
mm = loader.parse_and_check(state, mm_cs, scd_mmm, "Design meta-model")
|
||||
mm_rt = loader.parse_and_check(state, mm_rt_cs, scd_mmm, "Runtime meta-model")
|
||||
|
||||
return (mm, mm_rt)
|
||||
|
||||
def get_fibonacci(state, scd_mmm):
|
||||
mm, mm_rt = get_metamodels(state, scd_mmm)
|
||||
def load_fibonacci(state, scd_mmm):
|
||||
mm, mm_rt = load_metamodels(state, scd_mmm)
|
||||
|
||||
m_cs = read_file('models/m_fibonacci.od')
|
||||
m_rt_initial_cs = m_cs + read_file('models/m_fibonacci_initial.od')
|
||||
|
||||
m = parse_and_check(state, m_cs, mm, "Fibonacci model")
|
||||
m_rt_initial = parse_and_check(state, m_rt_initial_cs, mm_rt, "Fibonacci initial state")
|
||||
m = loader.parse_and_check(state, m_cs, mm, "Fibonacci model")
|
||||
m_rt_initial = loader.parse_and_check(state, m_rt_initial_cs, mm_rt, "Fibonacci initial state")
|
||||
|
||||
return (mm, mm_rt, m, m_rt_initial)
|
||||
|
||||
RULE_NAMES = ["delay_out", "function_out", "delay_in", "advance_time"]
|
||||
KINDS = ["nac", "lhs", "rhs"]
|
||||
|
||||
def get_rules(state, rt_mm):
|
||||
rt_mm_ramified = ramify(state, rt_mm)
|
||||
RULES0 = ["delay_in", "delay_out", "function_out"] # high priority
|
||||
RULES1 = ["advance_time"] # low priority
|
||||
|
||||
rules = {} # e.g., { "delay": {"nac": <UUID>, "lhs": <UUID>, ...}, ...}
|
||||
def load_rules(state, mm_rt_ramified):
|
||||
get_filename = lambda rule_name, kind: f"{THIS_DIR}/models/r_{rule_name}_{kind}.od"
|
||||
|
||||
for rule_name in RULE_NAMES:
|
||||
rule = {}
|
||||
for kind in KINDS:
|
||||
filename = f"models/r_{rule_name}_{kind}.od";
|
||||
cs = read_file(filename)
|
||||
rule_m = parse_and_check(state, cs, rt_mm_ramified, descr=f"'{filename}'")
|
||||
rule[kind] = rule_m
|
||||
rules[rule_name] = rule
|
||||
rules0 = loader.load_rules(state, get_filename, mm_rt_ramified, RULES0)
|
||||
rules1 = loader.load_rules(state, get_filename, mm_rt_ramified, RULES1)
|
||||
|
||||
return (rt_mm_ramified, rules)
|
||||
return rules0, rules1
|
||||
|
|
|
|||
11
examples/cbd/models/README.txt
Normal file
11
examples/cbd/models/README.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
This directory contains the following files:
|
||||
|
||||
mm_design.od: Meta-model of design model
|
||||
mm_runtime.od: Meta-model of runtime model
|
||||
|
||||
m_fibonacci.od: Design model for computing Fibonacci numbers
|
||||
m_fibonacci_initial.od: Initial runtime model (=initial state), for our Fibonacci model
|
||||
|
||||
r_<rule_name>_lhs.od: Left-hand side of model transformation rule
|
||||
r_<rule_name>_nac.od: Negative application condition of model transformation rule
|
||||
r_<rule_name>_rhs.od: Right-hand side of model transformation rule
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
import functools
|
||||
import pprint
|
||||
|
||||
from state.devstate import DevState
|
||||
from bootstrap.scd import bootstrap_scd
|
||||
|
||||
from api.od import ODAPI
|
||||
|
||||
from concrete_syntax.common import indent
|
||||
from concrete_syntax.textual_od import renderer as od_renderer
|
||||
from concrete_syntax.plantuml import renderer as plantuml
|
||||
from concrete_syntax.plantuml.make_url import make_url as make_plantuml_url
|
||||
from concrete_syntax.graphviz.make_url import make_url as make_graphviz_url
|
||||
from concrete_syntax.graphviz import renderer as graphviz
|
||||
|
||||
from transformation.matcher.mvs_adapter import match_od
|
||||
from transformation.rewriter import rewrite
|
||||
from transformation.cloner import clone_od
|
||||
|
||||
from examples.semantics.operational import simulator
|
||||
|
||||
import models
|
||||
|
||||
|
||||
def match_rule(rule_name, od: ODAPI, lhs, nac):
|
||||
lhs_matcher = match_od(state,
|
||||
host_m=od.m,
|
||||
host_mm=od.mm,
|
||||
pattern_m=lhs,
|
||||
pattern_mm=mm_rt_ram)
|
||||
|
||||
try:
|
||||
for i, lhs_match in enumerate(lhs_matcher):
|
||||
nac_matcher = match_od(state,
|
||||
host_m=od.m,
|
||||
host_mm=od.mm,
|
||||
pattern_m=nac,
|
||||
pattern_mm=mm_rt_ram,
|
||||
pivot=lhs_match)
|
||||
|
||||
try:
|
||||
for j, nac_match in enumerate(nac_matcher):
|
||||
break # there may be more NAC-matches, but we already now enough -> proceed to next lhs_match
|
||||
else:
|
||||
yield lhs_match # got match
|
||||
except Exception as e:
|
||||
# Make exceptions raised in eval'ed code easier to trace:
|
||||
e.add_note(f"while matching NAC of '{rule_name}'")
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
# Make exceptions raised in eval'ed code easier to trace:
|
||||
e.add_note(f"while matching LHS of '{rule_name}'")
|
||||
raise
|
||||
|
||||
def exec_action(rule_name, od: ODAPI, lhs, rhs, lhs_match):
|
||||
# copy these, will be overwritten in-place
|
||||
cloned_m = clone_od(state, od.m, od.mm)
|
||||
rhs_match = dict(lhs_match)
|
||||
|
||||
try:
|
||||
rewrite(state,
|
||||
lhs_m=lhs,
|
||||
rhs_m=rhs,
|
||||
pattern_mm=mm_rt_ram,
|
||||
lhs_name_mapping=rhs_match,
|
||||
host_m=cloned_m,
|
||||
host_mm=od.mm)
|
||||
except Exception as e:
|
||||
# Make exceptions raised in eval'ed code easier to trace:
|
||||
e.add_note(f"while executing RHS of '{rule_name}'")
|
||||
raise
|
||||
|
||||
print("Updated match:\n" + indent(pp.pformat(rhs_match), 6))
|
||||
|
||||
return (ODAPI(state, cloned_m, od.mm), [f"executed rule '{rule_name}'"])
|
||||
|
||||
pp = pprint.PrettyPrinter(depth=4)
|
||||
|
||||
def attempt_rules(od: ODAPI, rule_dict):
|
||||
at_least_one_match = False
|
||||
for rule_name, rule in rule_dict.items():
|
||||
for lhs_match in match_rule(rule_name, od, rule["lhs"], rule["nac"]):
|
||||
# We got a match!
|
||||
yield (rule_name + '\n' + indent(pp.pformat(lhs_match), 6),
|
||||
functools.partial(exec_action,
|
||||
rule_name, od, rule["lhs"], rule["rhs"], lhs_match))
|
||||
at_least_one_match = True
|
||||
return at_least_one_match
|
||||
|
||||
def get_actions(od: ODAPI):
|
||||
# transformation schedule
|
||||
rule_advance_time = rules["advance_time"]
|
||||
rules_not_advancing_time = { rule_name: rule for rule_name, rule in rules.items() if rule_name != "advance_time" }
|
||||
|
||||
at_least_one_match = yield from attempt_rules(od, rules_not_advancing_time)
|
||||
if not at_least_one_match:
|
||||
yield from attempt_rules(od, {"advance_time": rule_advance_time})
|
||||
|
||||
|
||||
|
||||
state = DevState()
|
||||
scd_mmm = bootstrap_scd(state)
|
||||
|
||||
print("Parsing models...")
|
||||
mm, mm_rt, m, m_rt_initial = models.get_fibonacci(state, scd_mmm)
|
||||
mm_rt_ram, rules = models.get_rules(state, mm_rt)
|
||||
|
||||
# print("RT-MM")
|
||||
# print(make_plantuml_url(plantuml.render_class_diagram(state, mm_rt)))
|
||||
|
||||
# print("RAMIFIED RT-MM")
|
||||
# print(make_plantuml_url(plantuml.render_class_diagram(state, mm_rt_ram)))
|
||||
|
||||
sim = simulator.Simulator(
|
||||
action_generator=get_actions,
|
||||
# decision_maker=simulator.InteractiveDecisionMaker(auto_proceed=False),
|
||||
decision_maker=simulator.RandomDecisionMaker(seed=0),
|
||||
termination_condition=lambda od: "Time is up" if od.get_slot_value(od.get_all_instances("Clock")[0][1], "time") >= 10 else None,
|
||||
check_conformance=True,
|
||||
verbose=True,
|
||||
renderer=lambda od: od_renderer.render_od(state, od.m, od.mm, hide_names=False),
|
||||
)
|
||||
|
||||
sim.run(ODAPI(state, m_rt_initial, mm_rt))
|
||||
Loading…
Add table
Add a link
Reference in a new issue