Example of rendering the entire match set, and rendering the rewrite (match between RHS and updated host graph)
This commit is contained in:
parent
a926de1998
commit
13f19cdec6
4 changed files with 174 additions and 62 deletions
36
experiments/exp_plantuml.py
Normal file
36
experiments/exp_plantuml.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
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
|
||||
|
||||
def main():
|
||||
state = DevState()
|
||||
root = state.read_root() # id: 0
|
||||
|
||||
scd_mm_id = bootstrap_scd(state)
|
||||
|
||||
uml = ""
|
||||
|
||||
# Render SCD Meta-Model as Object Diagram
|
||||
uml += plantuml.render_package("Object Diagram", plantuml.render_object_diagram(state, scd_mm_id, scd_mm_id, prefix_ids="od_"))
|
||||
|
||||
# Render SCD Meta-Model as Class Diagram
|
||||
uml += plantuml.render_package("Class Diagram", plantuml.render_class_diagram(state, scd_mm_id, prefix_ids="cd_"))
|
||||
|
||||
# Render conformance
|
||||
uml += plantuml.render_trace_conformance(state, scd_mm_id, scd_mm_id, prefix_inst_ids="od_", prefix_type_ids="cd_")
|
||||
|
||||
print(uml)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -149,47 +149,91 @@ def main():
|
|||
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")
|
||||
def render_ramification():
|
||||
uml = (""
|
||||
# Render original and RAMified meta-models
|
||||
+ plantuml.render_package("Meta-Model", plantuml.render_class_diagram(state, dsl_mm_id))
|
||||
+ plantuml.render_package("RAMified Meta-Model", plantuml.render_class_diagram(state, ramified_mm_id))
|
||||
|
||||
# Render RAMification traceability links
|
||||
+ plantuml.render_trace_ramifies(state, dsl_mm_id, ramified_mm_id)
|
||||
)
|
||||
|
||||
# Render pattern
|
||||
uml += plantuml.render_package("LHS", plantuml.render_object_diagram(state, lhs_id, ramified_mm_id))
|
||||
uml += plantuml.render_trace_conformance(state, lhs_id, ramified_mm_id)
|
||||
|
||||
# Render pattern
|
||||
uml += plantuml.render_package("RHS", plantuml.render_object_diagram(state, rhs_id, ramified_mm_id))
|
||||
uml += plantuml.render_trace_conformance(state, rhs_id, ramified_mm_id)
|
||||
|
||||
return uml
|
||||
|
||||
def render_all_matches():
|
||||
uml = render_ramification()
|
||||
# Render host graph (before rewriting)
|
||||
uml += plantuml.render_package("Model (before rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
|
||||
# Render conformance
|
||||
uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
|
||||
|
||||
print("matching...")
|
||||
matcher = MatcherVF2(host, guest, mvs_adapter.RAMCompare(Bottom(state), dsl_m_od))
|
||||
for m, color in zip(matcher.match(), ["red", "orange"]):
|
||||
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)
|
||||
|
||||
# Render every match
|
||||
uml += plantuml.render_trace_match(state, name_mapping, lhs_id, dsl_m_id, color)
|
||||
|
||||
print("DONE")
|
||||
return uml
|
||||
|
||||
def render_rewrite():
|
||||
uml = render_ramification()
|
||||
|
||||
matcher = MatcherVF2(host, guest, mvs_adapter.RAMCompare(Bottom(state), dsl_m_od))
|
||||
for m in matcher.match():
|
||||
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)
|
||||
|
||||
# Render match
|
||||
uml_match = plantuml.render_trace_match(state, name_mapping, rhs_id, dsl_m_id)
|
||||
|
||||
# Stop matching after rewrite
|
||||
break
|
||||
|
||||
# Render host graph (after rewriting)
|
||||
uml += plantuml.render_package("Model (after rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
|
||||
# Render conformance
|
||||
uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
|
||||
|
||||
uml += uml_match
|
||||
|
||||
return uml
|
||||
|
||||
conf5 = Conformance(state, dsl_m_id, dsl_mm_id)
|
||||
print("Updated model conforms?", conf5.check_nominal(log=True))
|
||||
|
||||
print()
|
||||
print("==============================================")
|
||||
|
||||
print(render_all_matches())
|
||||
# print(render_rewrite())
|
||||
|
||||
|
||||
# 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()
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@ from services import scd, od
|
|||
from services.bottom.V0 import Bottom
|
||||
from transformation import ramify
|
||||
import json
|
||||
from uuid import UUID
|
||||
|
||||
def render_class_diagram(state, model):
|
||||
def render_class_diagram(state, model, prefix_ids=""):
|
||||
bottom = Bottom(state)
|
||||
model_scd = scd.SCD(model, state)
|
||||
model_od = od.OD(od.get_scd_mm(bottom), model, state)
|
||||
|
||||
def make_id(uuid) -> str:
|
||||
return prefix_ids+str(uuid).replace('-','_')
|
||||
|
||||
output = ""
|
||||
|
||||
# Render classes
|
||||
|
|
@ -69,11 +73,14 @@ def render_class_diagram(state, model):
|
|||
return output
|
||||
|
||||
|
||||
def render_object_diagram(state, m, mm, render_attributes=True):
|
||||
def render_object_diagram(state, m, mm, render_attributes=True, prefix_ids=""):
|
||||
bottom = Bottom(state)
|
||||
mm_scd = scd.SCD(mm, state)
|
||||
m_od = od.OD(mm, m, state)
|
||||
|
||||
def make_id(uuid) -> str:
|
||||
return prefix_ids+str(uuid).replace('-','_')
|
||||
|
||||
output = ""
|
||||
|
||||
# Render objects
|
||||
|
|
@ -101,7 +108,7 @@ def render_object_diagram(state, m, mm, render_attributes=True):
|
|||
src_name = m_od.get_object_name(src_obj)
|
||||
tgt_name = m_od.get_object_name(tgt_obj)
|
||||
|
||||
output += f"\n{make_id(src_obj)} -> {make_id(tgt_obj)} : {assoc_name}"
|
||||
output += f"\n{make_id(src_obj)} -> {make_id(tgt_obj)} : :{assoc_name}"
|
||||
|
||||
return output
|
||||
|
||||
|
|
@ -112,19 +119,24 @@ def render_package(name, contents):
|
|||
output += '\n}'
|
||||
return output
|
||||
|
||||
def render_trace_ramifies(state, mm, ramified_mm, render_attributes=True):
|
||||
def render_trace_ramifies(state, mm, ramified_mm, render_attributes=True, prefix_ram_ids="", prefix_orig_ids=""):
|
||||
bottom = Bottom(state)
|
||||
|
||||
mm_scd = scd.SCD(mm, state)
|
||||
ramified_mm_scd = scd.SCD(ramified_mm, state)
|
||||
|
||||
def make_ram_id(uuid) -> str:
|
||||
return prefix_ram_ids+str(uuid).replace('-','_')
|
||||
def make_orig_id(uuid) -> str:
|
||||
return prefix_orig_ids+str(uuid).replace('-','_')
|
||||
|
||||
output = ""
|
||||
|
||||
# Render RAMifies-edges between classes
|
||||
for ram_name, ram_class_node in ramified_mm_scd.get_classes().items():
|
||||
original_class, = bottom.read_outgoing_elements(ram_class_node, ramify.RAMIFIES_LABEL)
|
||||
original_name = mm_scd.get_class_name(original_class)
|
||||
output += f"\n{make_id(ram_class_node)} ..> {make_id(original_class)} #line:green;text:green : RAMifies"
|
||||
output += f"\n{make_ram_id(ram_class_node)} ..> {make_orig_id(original_class)} #line:green;text:green : RAMifies"
|
||||
|
||||
if render_attributes:
|
||||
# and between attributes
|
||||
|
|
@ -133,16 +145,21 @@ def render_trace_ramifies(state, mm, ramified_mm, render_attributes=True):
|
|||
orig_class_node = bottom.read_edge_source(orig_attr_edge)
|
||||
# dirty AF:
|
||||
orig_attr_name = mm_scd.get_class_name(orig_attr_edge)[len(original_name)+1:]
|
||||
output += f"\n{make_id(ram_class_node)}::{ram_attr_name} ..> {make_id(orig_class_node)}::{orig_attr_name} #line:green;text:green : RAMifies"
|
||||
output += f"\n{make_ram_id(ram_class_node)}::{ram_attr_name} ..> {make_orig_id(orig_class_node)}::{orig_attr_name} #line:green;text:green : RAMifies"
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def render_trace_conformance(state, m, mm, render_attributes=True):
|
||||
def render_trace_conformance(state, m, mm, render_attributes=True, prefix_inst_ids="", prefix_type_ids=""):
|
||||
bottom = Bottom(state)
|
||||
mm_scd = scd.SCD(mm, state)
|
||||
m_od = od.OD(mm, m, state)
|
||||
|
||||
def make_inst_id(uuid) -> str:
|
||||
return prefix_inst_ids+str(uuid).replace('-','_')
|
||||
def make_type_id(uuid) -> str:
|
||||
return prefix_type_ids+str(uuid).replace('-','_')
|
||||
|
||||
output = ""
|
||||
|
||||
# Render objects
|
||||
|
|
@ -152,39 +169,50 @@ def render_trace_conformance(state, m, mm, render_attributes=True):
|
|||
attributes = od.get_attributes(bottom, class_node)
|
||||
|
||||
for obj_name, obj_node in m_od.get_objects(class_node).items():
|
||||
output += f"\n{make_id(obj_node)} ..> {make_id(class_node)} #line:blue;text:blue : instanceOf"
|
||||
output += f"\n{make_inst_id(obj_node)} ..> {make_type_id(class_node)} #line:blue;text:blue : instanceOf"
|
||||
|
||||
if render_attributes:
|
||||
for attr_name, attr_edge in attributes:
|
||||
slot = m_od.get_slot(obj_node, attr_name)
|
||||
if slot != None:
|
||||
output += f"\n{make_id(obj_node)}::{attr_name} ..> {make_id(class_node)}::{attr_name} #line:blue;text:blue : instanceOf"
|
||||
output += f"\n{make_inst_id(obj_node)}::{attr_name} ..> {make_type_id(class_node)}::{attr_name} #line:blue;text:blue : instanceOf"
|
||||
|
||||
output += '\n'
|
||||
|
||||
return output
|
||||
|
||||
def render_trace_match(state, mapping):
|
||||
def render_trace_match(state, name_mapping: dict, pattern_m: UUID, host_m: UUID, color="grey", prefix_pattern_ids="", prefix_host_ids=""):
|
||||
bottom = Bottom(state)
|
||||
class_type = od.get_scd_mm_class_node(bottom)
|
||||
attr_link_type = od.get_scd_mm_attributelink_node(bottom)
|
||||
|
||||
def make_pattern_id(uuid) -> str:
|
||||
return prefix_pattern_ids+str(uuid).replace('-','_')
|
||||
def make_host_id(uuid) -> str:
|
||||
return prefix_host_ids+str(uuid).replace('-','_')
|
||||
|
||||
output = ""
|
||||
|
||||
for pattern_el, host_el in mapping.items():
|
||||
render_suffix = f"#line:{color};line.dotted;text:{color} : matchedWith"
|
||||
|
||||
for pattern_el_name, host_el_name in name_mapping.items():
|
||||
print(pattern_el_name, host_el_name)
|
||||
try:
|
||||
pattern_el, = bottom.read_outgoing_elements(pattern_m, pattern_el_name)
|
||||
host_el, = bottom.read_outgoing_elements(host_m, host_el_name)
|
||||
except:
|
||||
continue
|
||||
# only render 'match'-edges between objects (= those elements where the type of the type is 'Class'):
|
||||
pattern_el_type = od.get_type(bottom, pattern_el)
|
||||
pattern_el_type_type = od.get_type(bottom, pattern_el_type)
|
||||
if pattern_el_type_type == class_type:
|
||||
output += f"\n{make_id(pattern_el)} ..> {make_id(host_el)} #line:grey;text:grey : matchedWith"
|
||||
output += f"\n{make_pattern_id(pattern_el)} ..> {make_host_id(host_el)} {render_suffix}"
|
||||
elif pattern_el_type_type == attr_link_type:
|
||||
pattern_obj = bottom.read_edge_source(pattern_el)
|
||||
pattern_attr_name = od.get_attr_name(bottom, pattern_el_type)
|
||||
host_obj = bottom.read_edge_source(host_el)
|
||||
host_el_type = od.get_type(bottom, host_el)
|
||||
host_attr_name = od.get_attr_name(bottom, host_el_type)
|
||||
output += f"\n{make_id(pattern_obj)}::{pattern_attr_name} ..> {make_id(host_obj)}::{host_attr_name} #line:grey;text:grey : matchedWith"
|
||||
output += f"\n{make_pattern_id(pattern_obj)}::{pattern_attr_name} ..> {make_host_id(host_obj)}::{host_attr_name} {render_suffix}"
|
||||
return output
|
||||
|
||||
def make_id(uuid) -> str:
|
||||
return (str(uuid).replace('-','_'))
|
||||
|
|
@ -23,7 +23,9 @@ def process_rule(state, lhs: UUID, rhs: UUID):
|
|||
|
||||
return to_delete, to_create, common
|
||||
|
||||
def rewrite(state, lhs: UUID, rhs: UUID, rhs_mm: UUID, match_mapping: dict, m_to_transform: UUID, mm: UUID) -> UUID:
|
||||
# Rewrite is performed in-place
|
||||
# Also updates the mapping in-place, to become RHS -> host
|
||||
def rewrite(state, lhs: UUID, rhs: UUID, rhs_mm: UUID, match_mapping: dict, m_to_transform: UUID, mm: UUID) -> dict:
|
||||
bottom = Bottom(state)
|
||||
|
||||
scd_metamodel_id = state.read_dict(state.read_root(), "SCD")
|
||||
|
|
@ -50,8 +52,10 @@ def rewrite(state, lhs: UUID, rhs: UUID, rhs_mm: UUID, match_mapping: dict, m_to
|
|||
element_to_delete, = bottom.read_outgoing_elements(m_to_transform, model_element_name_to_delete)
|
||||
# Delete
|
||||
bottom.delete_element(element_to_delete)
|
||||
# Remove from mapping
|
||||
del match_mapping[pattern_name_to_delete]
|
||||
|
||||
extended_mapping = dict(match_mapping) # will be extended with created elements
|
||||
# extended_mapping = dict(match_mapping) # will be extended with created elements
|
||||
edges_to_create = [] # postpone creation of edges after creation of nodes
|
||||
|
||||
# Perform creations
|
||||
|
|
@ -74,7 +78,7 @@ def rewrite(state, lhs: UUID, rhs: UUID, rhs_mm: UUID, match_mapping: dict, m_to
|
|||
# It's type is typed by Class -> it's an object
|
||||
print(' -> creating object')
|
||||
o = m_od._create_object(model_element_name_to_create, original_type)
|
||||
extended_mapping[pattern_name_to_create] = model_element_name_to_create
|
||||
match_mapping[pattern_name_to_create] = model_element_name_to_create
|
||||
elif od.is_typed_by(bottom, original_type, attr_link_type):
|
||||
print(' -> postpone (is attribute link)')
|
||||
edges_to_create.append((pattern_name_to_create, rhs_element_to_create, original_type, 'attribute link', rhs_type, model_element_name_to_create))
|
||||
|
|
@ -98,10 +102,10 @@ def rewrite(state, lhs: UUID, rhs: UUID, rhs_mm: UUID, match_mapping: dict, m_to
|
|||
m_od.create_integer_value(model_element_name_to_create, result)
|
||||
elif isinstance(result, str):
|
||||
m_od.create_string_value(model_element_name_to_create, result)
|
||||
extended_mapping[pattern_name_to_create] = model_element_name_to_create
|
||||
match_mapping[pattern_name_to_create] = model_element_name_to_create
|
||||
|
||||
|
||||
print('extended_mapping:', extended_mapping)
|
||||
print('match_mapping:', match_mapping)
|
||||
|
||||
print("create edges....")
|
||||
for pattern_name_to_create, rhs_element_to_create, original_type, original_type_name, rhs_type, model_element_name_to_create in edges_to_create:
|
||||
|
|
@ -112,24 +116,24 @@ def rewrite(state, lhs: UUID, rhs: UUID, rhs_mm: UUID, match_mapping: dict, m_to
|
|||
src_name = od.get_object_name(bottom, rhs, src)
|
||||
tgt = bottom.read_edge_target(rhs_element_to_create)
|
||||
tgt_name = od.get_object_name(bottom, rhs, tgt)
|
||||
obj_name = extended_mapping[src_name] # name of object in host graph to create slot for
|
||||
obj_name = match_mapping[src_name] # name of object in host graph to create slot for
|
||||
attr_name = od.get_object_name(bottom, mm, original_type)
|
||||
class_name = m_od.get_class_of_object(obj_name)
|
||||
# Just when you thought the code couldn't get any dirtier:
|
||||
attribute_name = attr_name[len(class_name)+1:]
|
||||
# print(attribute_name, obj_name, extended_mapping[tgt_name])
|
||||
m_od.create_slot(attribute_name, obj_name, extended_mapping[tgt_name])
|
||||
# print(attribute_name, obj_name, match_mapping[tgt_name])
|
||||
m_od.create_slot(attribute_name, obj_name, match_mapping[tgt_name])
|
||||
elif original_type_name == 'link':
|
||||
print(' -> creating link')
|
||||
src = bottom.read_edge_source(rhs_element_to_create)
|
||||
src_name = od.get_object_name(bottom, rhs, src)
|
||||
tgt = bottom.read_edge_target(rhs_element_to_create)
|
||||
tgt_name = od.get_object_name(bottom, rhs, tgt)
|
||||
obj_name = extended_mapping[src_name] # name of object in host graph to create slot for
|
||||
obj_name = match_mapping[src_name] # name of object in host graph to create slot for
|
||||
attr_name = od.get_object_name(bottom, mm, original_type)
|
||||
class_name = m_od.get_class_of_object(obj_name)
|
||||
# print(attr_name, obj_name, extended_mapping[tgt_name])
|
||||
m_od.create_link(model_element_name_to_create, attr_name, obj_name, extended_mapping[tgt_name])
|
||||
# print(attr_name, obj_name, match_mapping[tgt_name])
|
||||
m_od.create_link(model_element_name_to_create, attr_name, obj_name, match_mapping[tgt_name])
|
||||
|
||||
# Perform updates
|
||||
for pattern_element_name in common:
|
||||
|
|
@ -149,7 +153,7 @@ def rewrite(state, lhs: UUID, rhs: UUID, rhs_mm: UUID, match_mapping: dict, m_to
|
|||
result = eval(expr, {}, {'v': old_value})
|
||||
# print('eval result=', result)
|
||||
if isinstance(result, int):
|
||||
# overwrite the old value
|
||||
# overwrite the old value, in-place
|
||||
referred_model_id = UUID(bottom.read_value(model_element))
|
||||
Integer(referred_model_id, state).create(result)
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue