Implemented RAMification

This commit is contained in:
Joeri Exelmans 2024-09-03 18:48:27 +02:00
parent 8be7d6a450
commit 7bda71dc1f
3 changed files with 228 additions and 31 deletions

View file

@ -26,6 +26,13 @@ def main():
def print_tree(root, max_depth, depth=0): def print_tree(root, max_depth, depth=0):
print(" "*depth, "root=", root, "value=", state.read_value(root)) 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 in state.read_outgoing(root):
for edge_label in state.read_outgoing(edge): for edge_label in state.read_outgoing(edge):
[_,tgt] = state.read_edge(edge_label) [_,tgt] = state.read_edge(edge_label)
@ -50,19 +57,21 @@ def main():
print_tree(tgt, max_depth, depth+1) print_tree(tgt, max_depth, depth+1)
print("explore...") print("explore...")
print_tree(root, 2) # print_tree(root, 2)
int_type_id = state.read_dict(state.read_root(), "Integer") int_type_id = state.read_dict(state.read_root(), "Integer")
int_type = UUID(state.read_value(int_type_id)) int_type = UUID(state.read_value(int_type_id))
scd2 = SCD(scd_node, state) # scd2 = SCD(scd_node, state)
for el in scd2.list_elements(): # for el in scd2.list_elements():
print(el) # print(el)
model_id = state.create_node() model_id = state.create_node()
scd = SCD(model_id, state) scd = SCD(model_id, state)
scd.create_class("A") scd.create_class("Abstract", abstract=True)
scd.create_class("A", min_c=1, max_c=10)
scd.create_inheritance("A", "Abstract")
scd.create_model_ref("Integer", int_type) scd.create_model_ref("Integer", int_type)
scd.create_attribute_link("A", "Integer", "size", False) scd.create_attribute_link("A", "Integer", "size", False)
scd.create_class("B") scd.create_class("B")
@ -73,7 +82,7 @@ def main():
tgt_max_c=2, tgt_max_c=2,
) )
print_tree(model_id, 2) # print_tree(model_id, 3)
conf = Conformance(state, model_id, scd_node) conf = Conformance(state, model_id, scd_node)
@ -95,9 +104,9 @@ def main():
print("checking conformance....") print("checking conformance....")
conf2 = Conformance(state, inst_id, model_id) conf2 = Conformance(state, inst_id, model_id)
print(conf2.check_nominal(log=True)) print("conforms?", conf2.check_nominal(log=True))
# ramify(state, model_id) ramify(state, model_id)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -90,6 +90,15 @@ class SCD:
Returns: Returns:
Nothing. Nothing.
""" """
src, = self.bottom.read_outgoing_elements(self.model, source)
tgt, = self.bottom.read_outgoing_elements(self.model, target)
return self._create_association(name, src, tgt,
src_min_c, src_max_c,
tgt_min_c, tgt_max_c)
def _create_association(self, name: str, source: UUID, target: UUID,
src_min_c: int = None, src_max_c: int = None,
tgt_min_c: int = None, tgt_max_c: int = None):
def set_cardinality(bound: str, value: int): def set_cardinality(bound: str, value: int):
# similar to set_cardinality function defined in create_class # similar to set_cardinality function defined in create_class
@ -105,10 +114,7 @@ class SCD:
self.bottom.create_edge(_c_link, _scd_link, "Morphism") self.bottom.create_edge(_c_link, _scd_link, "Morphism")
# create association + attributes + morphism links # create association + attributes + morphism links
assoc_edge = self.bottom.create_edge( assoc_edge = self.bottom.create_edge(source, target) # create assoc edge
*self.bottom.read_outgoing_elements(self.model, source),
*self.bottom.read_outgoing_elements(self.model, target),
) # create assoc edge
self.bottom.create_edge(self.model, assoc_edge, name) # attach to model self.bottom.create_edge(self.model, assoc_edge, name) # attach to model
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Association") # retrieve type scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Association") # retrieve type
self.bottom.create_edge(assoc_edge, scd_node, "Morphism") # create morphism link self.bottom.create_edge(assoc_edge, scd_node, "Morphism") # create morphism link
@ -166,11 +172,13 @@ class SCD:
Returns: Returns:
Nothing. Nothing.
""" """
tgt, = self.bottom.read_outgoing_elements(self.model, target)
return self._create_attribute_link(source, tgt, name, optional)
def _create_attribute_link(self, source: str, target: UUID, name: str, optional: bool):
# create attribute link + morphism links # create attribute link + morphism links
assoc_edge = self.bottom.create_edge( src, = self.bottom.read_outgoing_elements(self.model, source)
*self.bottom.read_outgoing_elements(self.model, source), assoc_edge = self.bottom.create_edge(src, target) # create v edge
*self.bottom.read_outgoing_elements(self.model, target),
) # create v edge
self.bottom.create_edge(self.model, assoc_edge, f"{source}_{name}") # attach to model self.bottom.create_edge(self.model, assoc_edge, f"{source}_{name}") # attach to model
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "AttributeLink") # retrieve type scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "AttributeLink") # retrieve type
self.bottom.create_edge(assoc_edge, scd_node, "Morphism") # create morphism link self.bottom.create_edge(assoc_edge, scd_node, "Morphism") # create morphism link
@ -215,6 +223,7 @@ class SCD:
self.bottom.create_edge(self.model, element_node, name) # attach to model self.bottom.create_edge(self.model, element_node, name) # attach to model
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "ModelRef") # retrieve type scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "ModelRef") # retrieve type
self.bottom.create_edge(element_node, scd_node, "Morphism") # create morphism link self.bottom.create_edge(element_node, scd_node, "Morphism") # create morphism link
return element_node
def create_inheritance(self, child: str, parent: str): def create_inheritance(self, child: str, parent: str):
""" """
@ -227,14 +236,25 @@ class SCD:
Returns: Returns:
Nothing. Nothing.
""" """
c, = self.bottom.read_outgoing_elements(self.model, child)
p, = self.bottom.read_outgoing_elements(self.model, parent)
return self._create_inheritance(c, p)
def _create_inheritance(self, child: UUID, parent: UUID):
# create inheritance + morphism links # create inheritance + morphism links
assoc_edge = self.bottom.create_edge( inh_edge = self.bottom.create_edge(child, parent)
*self.bottom.read_outgoing_elements(self.model, child), child_name = self.get_class_name(child)
*self.bottom.read_outgoing_elements(self.model, parent), parent_name = self.get_class_name(parent)
) # create inheritance edge self.bottom.create_edge(self.model, inh_edge, f"{child_name}_inh_{parent_name}") # attach to model
self.bottom.create_edge(self.model, assoc_edge, f"{child}_inh_{parent}") # attach to model
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Inheritance") # retrieve type scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Inheritance") # retrieve type
self.bottom.create_edge(assoc_edge, scd_node, "Morphism") # create morphism link self.bottom.create_edge(inh_edge, scd_node, "Morphism") # create morphism link
def get_class_name(self, cls: UUID):
for key in self.bottom.read_keys(self.model):
el, = self.bottom.read_outgoing_elements(self.model, key)
if el == cls:
return key
def add_constraint(self, element: str, code: str): def add_constraint(self, element: str, code: str):
""" """
@ -278,6 +298,39 @@ class SCD:
unsorted.append(f"{key} : {scd_names[element_type_node]}") unsorted.append(f"{key} : {scd_names[element_type_node]}")
return sorted(unsorted) return sorted(unsorted)
def get_classes(self):
class_node, = self.bottom.read_outgoing_elements(self.scd_model, "Class")
return self.get_typed_by(class_node)
def get_associations(self):
assoc_node, = self.bottom.read_outgoing_elements(self.scd_model, "Association")
return self.get_typed_by(assoc_node)
def get_inheritances(self):
inh_node, = self.bottom.read_outgoing_elements(self.scd_model, "Inheritance")
return self.get_typed_by(inh_node)
def get_typed_by(self, type_node: UUID):
name_to_instance = {}
for key in self.bottom.read_keys(self.model):
element, = self.bottom.read_outgoing_elements(self.model, key)
element_types = self.bottom.read_outgoing_elements(element, "Morphism")
if type_node in element_types:
name_to_instance[key] = element
# mapping from instance name to UUID
return name_to_instance
def get_attributes(self, class_name: str):
attr_link_node, = self.bottom.read_outgoing_elements(self.scd_model, "AttributeLink")
class_node, = self.bottom.read_outgoing_elements(self.model, class_name)
name_to_attr = {}
for edge in self.bottom.read_outgoing_edges(class_node):
edge_types = self.bottom.read_outgoing_elements(edge, "Morphism")
if attr_link_node in edge_types:
name_to_attr[key] = edge
return name_to_attr
def delete_element(self, name: str): def delete_element(self, name: str):
""" """
Deletes an element from the model. Deletes an element from the model.

View file

@ -2,17 +2,152 @@ from state.base import State
from uuid import UUID from uuid import UUID
from services.bottom.V0 import Bottom from services.bottom.V0 import Bottom
from services.scd import SCD from services.scd import SCD
from framework.conformance import Conformance
def ramify(state: State, model: UUID) -> UUID: def ramify(state: State, model: UUID) -> UUID:
"""
Parameters: def print_tree(root, max_depth, depth=0):
bottom: Bottom-service, wrapping MVS print(" "*depth, "root=", root, "value=", state.read_value(root))
model: An SCD-conforming meta-model to ramify 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)
bottom = Bottom(state)
scd_metamodel_id = state.read_dict(state.read_root(), "SCD")
scd_metamodel = UUID(state.read_value(scd_metamodel_id))
class_upper_card_node, = bottom.read_outgoing_elements(scd_metamodel, "Class_upper_cardinality")
src_upper_card_node, = bottom.read_outgoing_elements(scd_metamodel, "Association_source_upper_cardinality")
tgt_upper_card_node, = bottom.read_outgoing_elements(scd_metamodel, "Association_target_upper_cardinality")
attr_link_node, = bottom.read_outgoing_elements(scd_metamodel, "AttributeLink")
attr_link_name_node, = bottom.read_outgoing_elements(scd_metamodel, "AttributeLink_name")
glob_constr_node, = bottom.read_outgoing_elements(scd_metamodel, "GlobalConstraint")
inheritance_node, = bottom.read_outgoing_elements(scd_metamodel, "Inheritance")
string_type_id = state.read_dict(state.read_root(), "String")
string_type = UUID(state.read_value(string_type_id))
scd = SCD(model, state) scd = SCD(model, state)
classes = scd.get_classes() # print_tree(model, 2)
print(classes)
attrs = scd.get_attributes('A') # for el in SCD(scd_metamodel, state).list_elements():
print(attrs) # print(el)
def find_outgoing_typed_by(src: UUID, type_node: UUID):
edges = []
for outgoing_edge in bottom.read_outgoing_edges(src):
for typedBy in bottom.read_outgoing_elements(outgoing_edge, "Morphism"):
if typedBy == type_node:
edges.append(outgoing_edge)
break
return edges
def navigate_modelref(node: UUID):
uuid = bottom.read_value(node)
return UUID(uuid)
def find_upper_cardinality(class_node: UUID, type_node: UUID):
upper_card_edges = find_outgoing_typed_by(class_node, type_node)
if len(upper_card_edges) == 1:
ref = bottom.read_edge_target(upper_card_edges[0])
integer, = bottom.read_outgoing_elements(
navigate_modelref(ref),
"integer")
# finally, the value we're looking for:
return bottom.read_value(integer)
def get_attributes(class_node: UUID):
attr_edges = find_outgoing_typed_by(class_node, attr_link_node)
result = []
for attr_edge in attr_edges:
name_edge, = find_outgoing_typed_by(attr_edge, attr_link_name_node)
if name_edge == None:
raise Exception("Expected attribute to have a name...")
ref_name = bottom.read_edge_target(name_edge)
string, = bottom.read_outgoing_elements(
navigate_modelref(ref_name),
"string")
attr_name = bottom.read_value(string)
ref_type = bottom.read_edge_target(attr_edge)
typ = navigate_modelref(ref_type)
result.append((attr_name, typ))
return result
ramified = state.create_node()
ramified_scd = SCD(ramified, state)
string_modelref = ramified_scd.create_model_ref("String", string_type)
print()
classes = scd.get_classes()
for class_name, class_node in classes.items():
# For every class in our original model, create a class:
# - abstract: False
# - min-card: 0
# - max-card: same as original
upper_card = find_upper_cardinality(class_node, class_upper_card_node)
print('creating class', class_name, "with upper card", upper_card)
ramified_scd.create_class(class_name, abstract=None, max_c=upper_card)
for (attr_name, attr_type) in get_attributes(class_node):
print(' creating attribute', attr_name, "with type String")
# Every attribute becomes 'string' type
# The string will be a Python expression
ramified_scd._create_attribute_link(class_name, string_modelref, attr_name, optional=False)
associations = scd.get_associations()
for assoc_name, assoc_node in associations.items():
# For every association in our original model, create an association:
# - src-min-card: 0
# - src-max-card: same as original
# - tgt-min-card: 0
# - tgt-max-card: same as original
src_upper_card = find_upper_cardinality(assoc_node, src_upper_card_node)
tgt_upper_card = find_upper_cardinality(assoc_node, tgt_upper_card_node)
print('creating assoc', assoc_name, "with src upper card", src_upper_card, "and tgt upper card", tgt_upper_card)
ramified_scd._create_association(assoc_name,
bottom.read_edge_source(assoc_node),
bottom.read_edge_target(assoc_node),
src_max_c=src_upper_card,
tgt_max_c=tgt_upper_card)
for inh_name, inh_node in scd.get_inheritances().items():
# Re-create inheritance links like in our original model:
print('creating inheritance', inh_name)
ramified_scd._create_inheritance(
bottom.read_edge_source(inh_node),
bottom.read_edge_target(inh_node))
# The RAMified meta-model should also conform to 'SCD':
conf = Conformance(state, model, scd_metamodel)
print("conforms?", conf.check_nominal(log=True))