Browse Source

New type mapping storage method (faster and more correct)

Yentl Van Tendeloo 5 years ago
parent
commit
863ba9fb7d

+ 6 - 7
bootstrap/conformance_finding.alc

@@ -78,19 +78,18 @@ Boolean function find_type_mapping(model : Element):
 		while (set_len(elems) > 0):
 			elem = set_pop(elems)
 
-			if (bool_and(is_edge(model["model"][elem]), read_nr_out(model["model"][elem]) == 0)):
+			if (node_source_element == node_target_element):
+				if (is_edge(model["model"][elem])):
+					retype(model, elem, edge_element)
+				else:
+					retype(model, elem, node_source_element)
+			elif (bool_and(is_edge(model["model"][elem]), read_nr_out(model["model"][elem]) == 0)):
 				// An edge, and there is always exactly one, so type
 				retype(model, elem, edge_element)
 
 				// The source and target are ALWAYS typed as well!
 				retype(model, readAssociationSource(model, elem), node_source_element)
 				retype(model, readAssociationDestination(model, elem), node_target_element)
-			elif (node_source_element == node_target_element):
-				// A node, and we are sure that there is only one
-				if (is_edge(model["model"][elem])):
-					retype(model, elem, edge_element)
-				else:
-					retype(model, elem, node_source_element)
 
 	// 3) (optional) verify that the mapping is correct with conformance checking
 	// TODO

+ 3 - 1
bootstrap/type_mapping.mvc

@@ -3,7 +3,9 @@ import models/SimpleClassDiagrams as SCD
 SCD type_mapping {
     Class Instance {}
     Class Type {}
-    Association TypeLink (Instance, Type) {}
+    Class Root {}
+    Association TypeLink (Root, Type) {}
+    Association InstanceLink (TypeLink, Instance) {}
 }
 
 export type_mapping to models/TypeMapping

+ 28 - 110
bootstrap/typing.alc

@@ -3,106 +3,11 @@ include "utils.alh"
 
 Element function get_type_mapping(model : Element):
 	// Deserialize dictionary as model
-	Element tm_model
-	tm_model = dict_create()
-
-	Element m
-	Element mm
-	Element edge
-	Element keys
-	String key
-	String m_name
-	String mm_name
-
-	Element m_model
-	Element mm_model
-	Element tm
-	m_model = model["model"]
-	mm_model = model["metamodel"]["model"]
-	tm = model["type_mapping"]
-
-	keys = dict_keys(model["type_mapping"])
-
-	while (set_len(keys) > 0):
-		key = set_pop(keys)
-		m = m_model[key]
-		mm = mm_model[tm[key]]
-		edge = create_edge(m, mm)
-
-		m_name = "instance_" + key
-		mm_name = "type_" + cast_string(tm[key])
-		dict_add_fast(tm_model, m_name, m)
-		if (bool_not(dict_in(tm_model, mm_name))):
-			dict_add_fast(tm_model, mm_name, mm)
-		dict_add_fast(tm_model, cast_id(edge), edge)
-
-	return tm_model!
+	return model["type_mapping"]!
 
 Void function set_type_mapping(model : Element, type_mapping_model : Element):
 	// Serialize model to dictionary
-	Element type_mapping
-	Element keys
-	String key
-	String source_name
-	String destination_name
-	String tmp_source_name
-	String tmp_destination_name
-	Element lookups
-	String value
-	String src_id
-	String dst_id
-	Element mm_model
-	Element m_model
-	m_model = model["model"]
-	mm_model = model["metamodel"]["model"]
-
-	type_mapping = dict_create()
-	keys = dict_keys(type_mapping_model)
-
-	Element reverse_mapping
-	reverse_mapping = dict_create()
-
-	while (set_len(keys) > 0):
-		key = set_pop(keys)
-		value = cast_id(type_mapping_model[key])
-
-		if (bool_not(dict_in(reverse_mapping, value))):
-			dict_add(reverse_mapping, value, set_create())
-		set_add(reverse_mapping[value], key)
-
-	keys = dict_keys(type_mapping_model)
-	while (set_len(keys) > 0):
-		key = set_pop(keys)
-		if (is_edge(type_mapping_model[key])):
-			src_id = cast_id(read_edge_src(type_mapping_model[key]))
-			if (bool_not(dict_in(reverse_mapping, src_id))):
-				continue!
-			lookups = set_copy(reverse_mapping[src_id])
-			source_name = ""
-			while (set_len(lookups) > 0):
-				tmp_source_name = set_pop(lookups)
-				if (string_startswith(tmp_source_name, "instance_")):
-					source_name = string_replace(tmp_source_name, "instance_", "")
-					break!
-
-			dst_id = cast_id(read_edge_dst(type_mapping_model[key]))
-			if (bool_not(dict_in(reverse_mapping, dst_id))):
-				continue!
-			lookups = set_copy(reverse_mapping[dst_id])
-			destination_name = ""
-			while (set_len(lookups) > 0):
-				tmp_destination_name = set_pop(lookups)
-				if (string_startswith(tmp_destination_name, "type_")):
-					destination_name = string_replace(tmp_destination_name, "type_", "")
-					break!
-
-			if (bool_and(bool_and(dict_in(m_model, source_name), dict_in(mm_model, destination_name)), read_nr_out(type_mapping_model[key]) == 0)):
-				// Element is in neither model or metamodel
-				// Must be a typing link!
-				// So add it
-				dict_add_fast(type_mapping, source_name, destination_name)
-
-	dict_overwrite(model, "type_mapping", type_mapping)
+	dict_overwrite(model, "type_mapping", type_mapping_model)
 	return!
 
 Element function elements_typed_by(model : Element, type_name : String):
@@ -121,14 +26,14 @@ Element function elements_typed_by(model : Element, type_name : String):
 	return result!
 
 Element function get_type_mapping_as_dict(model : Element):
-	return model["type_mapping"]!
+	return model["type_mapping"]["root"]!
 
 String function read_type(model : Element, name : String):
 	String result
 	Element tm
 	if (dict_in(model["model"], name)):
-		if (dict_in(model["type_mapping"], name)):
-			result = model["type_mapping"][name]
+		if (dict_in(model["type_mapping"]["root"], name)):
+			result = model["type_mapping"]["root"][name]
 			if (dict_in(model["metamodel"]["model"], result)):
 				return result!
 			else:
@@ -140,21 +45,34 @@ String function read_type(model : Element, name : String):
 
 Void function retype(model : Element, element : String, type : String):
 	// Retype a model, deleting any previous type the element had
-	// The type string is evaluated in the metamodel previously specified
-	dict_overwrite(model["type_mapping"], element, type)
+	Element tm
+	tm = model["type_mapping"]
+
+	remove_type(model, element)
+
+	// Create new elements
+	Element type_link
+	Element type_elem
+	Element instance_link
+	Element instance_elem
+	type_elem = create_value(type)
+	instance_elem = create_value(element)
+	type_link = create_edge(tm["root"], type_elem)
+	instance_link = create_edge(type_link, instance_elem)
+	dict_add(tm, cast_id(type_elem), type_elem)
+	dict_add(tm, cast_id(instance_elem), instance_elem)
+	dict_add(tm, cast_id(type_link), type_link)
+	dict_add(tm, cast_id(instance_link), instance_link)
 	return!
 
 Void function new_type_mapping(model : Element):
 	dict_overwrite(model, "type_mapping", dict_create())
+	dict_add(model["type_mapping"], "root", create_node())
 	return !
 
 Void function remove_type(model : Element, name : String):
-	if (dict_in(model["type_mapping"], name)):
-		dict_delete(model["type_mapping"], name)
-	
-	String elem
-	elem = cast_id(model["model"][name])
-	if (dict_in(model["type_mapping"], elem)):
-		dict_delete(model["type_mapping"], elem)
-
+	Element value
+	value = dict_read(model["type_mapping"]["root"], name)
+	if (element_neq(value, read_root())):
+		delete_element(reverseKeyLookup(model["type_mapping"], value))
 	return !

+ 12 - 7
kernel/modelverse_kernel/compiled.py

@@ -5,6 +5,7 @@ def get_superclasses(a, b, **remainder):
         b['value'], = yield [("RV", [b['id']])]
     model_dict, tm_dict = yield [("RD", [a['id'], "model"]), 
                                  ("RD", [a['id'], "type_mapping"])]
+    tm_dict, = yield [("RD", [tm_dict, "root"])]
 
     worklist = set([b['value']])
     found = set([])
@@ -96,16 +97,16 @@ def reverseKeyLookup(a, b, **remainder):
         yield [("RETURN", [{'value': ""}])]
 
     options = set(edges_out) & set(edges_in)
-    if options:
-        # Select one option randomly
+    # Select one option randomly
+    while options:
         edge = options.pop()
         out_edges, = yield [("RO", [edge])]
         # Select one option randomly
-        out_edge = out_edges.pop()
-        e, = yield [("RE", [out_edge])]
-        yield [("RETURN", [{'id': e[1]}])]
-    else:
-        yield [("RETURN", [{'value': ""}])]
+        if out_edges:
+            out_edge = out_edges.pop()
+            e, = yield [("RE", [out_edge])]
+            yield [("RETURN", [{'id': e[1]}])]
+    yield [("RETURN", [{'value': ""}])]
 
 def instantiated_name(a, b, **remainder):
     if "id" not in a:
@@ -310,6 +311,7 @@ def list_pop_final(a, **remainder):
     _, = yield [("DE", [result_edge])]
     yield [("RETURN", [{'id': result}])]
 
+"""
 def instantiate_node(a, b, c, **remainder):
     if "value" not in c:
         c['value'], = yield [("RV", [c['id']])]
@@ -333,6 +335,7 @@ def instantiate_node(a, b, c, **remainder):
     yield [("CD", [typing, name, b['id']])]
 
     yield [("RETURN", [name_node])]
+"""
 
 def list_insert(a, b, c, **remainder):
     if "id" not in b:
@@ -387,6 +390,7 @@ def set_in_node(a, b, **remainder):
     value, = yield [("RDN", [a['id'], b['id']])]
     yield [("RETURN", [{'value': value is not None}])]
 
+"""
 def read_type(a, b, **remainder):
     if "value" not in b:
         b['value'], = yield [("RV", [b['id']])]
@@ -405,3 +409,4 @@ def read_type(a, b, **remainder):
             yield [("RETURN", [{'value': ""}])]
         else:
             yield [("RETURN", [{'value': type_value}])]
+"""

+ 1 - 0
unit/test_all.py

@@ -415,6 +415,7 @@ class TestModelverse(unittest.TestCase):
         count_nodes = 0
         count_edges = 0
         for entry in element_list_nice("test/PetriNet"):
+            print(entry)
             assert entry["__type"] in ["Node", "Edge"]
             if entry["__type"] == "Node":
                 assert len(entry) == 2

+ 1 - 1
wrappers/modelverse_SCCD.py

@@ -1,7 +1,7 @@
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
-Date:   Wed May 30 12:57:56 2018
+Date:   Wed May 30 15:01:47 2018
 
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server