muMLE/experiments/exp_scd.py

195 lines
7.1 KiB
Python

# Simple Class Diagram 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.ramify import ramify
from transformation import rewriter
from services.bottom.V0 import Bottom
from services.primitives.integer_type import Integer
from pattern_matching import mvs_adapter
from pattern_matching.matcher import MatcherVF2
from renderer import plantuml
import sys
def create_integer_node(state, i: int):
node = state.create_node()
integer_t = Integer(node, state)
integer_t.create(i)
return node
def main():
state = DevState()
root = state.read_root() # id: 0
scd_mm_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")))
# def print_tree(root, max_depth, depth=0):
# print(" "*depth, "root=", root, "value=", state.read_value(root))
# src,tgt = state.read_edge(root)
# if src != None:
# print(" "*depth, "src...")
# print_tree(src, max_depth, depth+1)
# if tgt != None:
# print(" "*depth, "tgt...")
# print_tree(tgt, max_depth, depth+1)
# for edge in state.read_outgoing(root):
# for edge_label in state.read_outgoing(edge):
# [_,tgt] = state.read_edge(edge_label)
# label = state.read_value(tgt)
# print(" "*depth, " key:", label)
# [_, tgt] = state.read_edge(edge)
# value = state.read_value(tgt)
# if value != None:
# print(" "*depth, " ->", tgt, " (value:", value, ")")
# else:
# print(" "*depth, " ->", tgt)
# if depth < max_depth:
# if isinstance(value, str) and len(value) == 36:
# i = None
# try:
# i = UUID(value)
# except ValueError as e:
# # print("invalid UUID:", value)
# pass
# if i != None:
# print_tree(i, max_depth, depth+1)
# print_tree(tgt, max_depth, depth+1)
# Meta-model for our DSL
dsl_mm_id = state.create_node()
dsl_mm_scd = SCD(dsl_mm_id, state)
dsl_mm_scd.create_class("Animal", abstract=True)
dsl_mm_scd.create_class("Man", min_c=1, max_c=2)
dsl_mm_scd.create_inheritance("Man", "Animal")
dsl_mm_scd.create_model_ref("Integer", int_mm_id)
dsl_mm_scd.create_attribute_link("Man", "Integer", "weight", optional=False)
dsl_mm_scd.create_class("Bear")
dsl_mm_scd.create_inheritance("Bear", "Animal")
dsl_mm_scd.create_association("afraidOf", "Man", "Animal",
# Every Man afraid of at least one Animal:
src_min_c=0,
src_max_c=None,
tgt_min_c=1,
tgt_max_c=None,
)
print(dsl_mm_scd.list_elements())
conf = Conformance(state, dsl_mm_id, scd_mm_id)
print("conforms?", conf.check_nominal(log=True))
# Model in our DSL
dsl_m_id = state.create_node()
dsl_m_od = OD(dsl_mm_id, dsl_m_id, state)
# dsl_m_od.create_object("animal", "Animal")
dsl_m_od.create_object("george", "Man")
dsl_m_od.create_slot("weight", "george",
dsl_m_od.create_integer_value("george.weight", 80))
# "george_weight"
dsl_m_od.create_object("bear1", "Bear")
dsl_m_od.create_object("bear2", "Bear")
dsl_m_od.create_link("georgeAfraidOfBear1", "afraidOf", "george", "bear1")
dsl_m_od.create_link("georgeAfraidOfBear2", "afraidOf", "george", "bear2")
conf2 = Conformance(state, dsl_m_id, dsl_mm_id)
print("DSL instance conforms?", conf2.check_nominal(log=True))
print(conf2.type_mapping)
# 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)
# LHS of our rule
lhs_id = state.create_node()
lhs_od = OD(ramified_mm_id, lhs_id, state)
lhs_od.create_object("man", prefix+"Man")
lhs_od.create_slot(prefix+"weight", "man", lhs_od.create_string_value(f"man.{prefix}weight", 'v < 99'))
lhs_od.create_object("scaryAnimal", prefix+"Animal")
lhs_od.create_link("manAfraidOfAnimal", prefix+"afraidOf", "man", "scaryAnimal")
conf3 = Conformance(state, lhs_id, ramified_mm_id)
print("LHS conforms?", conf3.check_nominal(log=True))
# RHS of our rule
rhs_id = state.create_node()
rhs_od = OD(ramified_mm_id, rhs_id, state)
rhs_od.create_object("man", prefix+"Man")
rhs_od.create_slot(prefix+"weight", "man", rhs_od.create_string_value(f"man.{prefix}weight", 'v + 5'))
rhs_od.create_object("bill", prefix+"Man")
rhs_od.create_slot(prefix+"weight", "bill", rhs_od.create_string_value(f"bill.{prefix}weight", '100'))
rhs_od.create_link("billAfraidOfMan", prefix+"afraidOf", "bill", "man")
conf4 = Conformance(state, rhs_id, ramified_mm_id)
print("RHS conforms?", conf4.check_nominal(log=True))
# Convert to format understood by matching algorithm
host = mvs_adapter.model_to_graph(state, dsl_m_id, dsl_mm_id)
guest = mvs_adapter.model_to_graph(state, lhs_id, ramified_mm_id)
print("HOST:")
print(host.vtxs)
print(host.edges)
print("GUEST:")
print(guest.vtxs)
print(guest.edges)
print("matching...")
matcher = MatcherVF2(host, guest, mvs_adapter.RAMCompare(Bottom(state), dsl_m_od))
for m in matcher.match():
print("\nMATCH:\n", m)
name_mapping = {}
id_mapping = {}
for guest_vtx, host_vtx in m.mapping_vtxs.items():
if isinstance(guest_vtx, mvs_adapter.NamedNode) and isinstance(host_vtx, mvs_adapter.NamedNode):
id_mapping[guest_vtx.node_id] = host_vtx.node_id
name_mapping[guest_vtx.name] = host_vtx.name
print(name_mapping)
#rewriter.rewrite(state, lhs_id, rhs_id, ramified_mm_id, name_mapping, dsl_m_id, dsl_mm_id)
break
print("DONE")
conf5 = Conformance(state, dsl_m_id, dsl_mm_id)
print("Updated model conforms?", conf5.check_nominal(log=True))
# Render original and RAMified meta-models
print(plantuml.render_package("Meta-Model", plantuml.render_class_diagram(state, dsl_mm_id)))
print(plantuml.render_package("RAMified Meta-Model", plantuml.render_class_diagram(state, ramified_mm_id)))
# Render ramification traceability links
print(plantuml.render_trace_ramifies(state, dsl_mm_id, ramified_mm_id))
# Render host graph
print(plantuml.render_package("Model", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id)))
# Render conformance host -> MM
print(plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id))
# Render pattern
print(plantuml.render_package("LHS", plantuml.render_object_diagram(state, lhs_id, ramified_mm_id)))
# Render pattern -> RAM-MM
print(plantuml.render_trace_conformance(state, lhs_id, ramified_mm_id))
print(plantuml.render_trace_match(state, id_mapping))
if __name__ == "__main__":
main()